From c1230068dc4501c52999ac0bbb3a2e5933453f09 Mon Sep 17 00:00:00 2001 From: Ivan Sukhanov Date: Tue, 25 Nov 2025 18:13:48 +0000 Subject: [PATCH 001/706] 8363943: ARM32: Represent Registers as values Reviewed-by: shade, bulasevich --- src/hotspot/cpu/arm/arm_32.ad | 32 +- src/hotspot/cpu/arm/assembler_arm_32.hpp | 2 +- src/hotspot/cpu/arm/c1_CodeStubs_arm.cpp | 2 +- src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp | 8 +- src/hotspot/cpu/arm/interp_masm_arm.cpp | 4 +- src/hotspot/cpu/arm/register_arm.cpp | 30 +- src/hotspot/cpu/arm/register_arm.hpp | 547 ++++++++++-------- src/hotspot/cpu/arm/sharedRuntime_arm.cpp | 10 +- src/hotspot/cpu/arm/vmreg_arm.cpp | 4 +- src/hotspot/cpu/arm/vmreg_arm.hpp | 8 +- src/hotspot/cpu/arm/vmreg_arm.inline.hpp | 8 +- .../linux_arm/macroAssembler_linux_arm_32.cpp | 6 +- 12 files changed, 376 insertions(+), 285 deletions(-) diff --git a/src/hotspot/cpu/arm/arm_32.ad b/src/hotspot/cpu/arm/arm_32.ad index 00bf3bd61e4..9438e8da8b5 100644 --- a/src/hotspot/cpu/arm/arm_32.ad +++ b/src/hotspot/cpu/arm/arm_32.ad @@ -62,22 +62,22 @@ register %{ // Integer/Long Registers // ---------------------------- -reg_def R_R0 (SOC, SOC, Op_RegI, 0, R(0)->as_VMReg()); -reg_def R_R1 (SOC, SOC, Op_RegI, 1, R(1)->as_VMReg()); -reg_def R_R2 (SOC, SOC, Op_RegI, 2, R(2)->as_VMReg()); -reg_def R_R3 (SOC, SOC, Op_RegI, 3, R(3)->as_VMReg()); -reg_def R_R4 (SOC, SOE, Op_RegI, 4, R(4)->as_VMReg()); -reg_def R_R5 (SOC, SOE, Op_RegI, 5, R(5)->as_VMReg()); -reg_def R_R6 (SOC, SOE, Op_RegI, 6, R(6)->as_VMReg()); -reg_def R_R7 (SOC, SOE, Op_RegI, 7, R(7)->as_VMReg()); -reg_def R_R8 (SOC, SOE, Op_RegI, 8, R(8)->as_VMReg()); -reg_def R_R9 (SOC, SOE, Op_RegI, 9, R(9)->as_VMReg()); -reg_def R_R10(NS, SOE, Op_RegI, 10, R(10)->as_VMReg()); -reg_def R_R11(NS, SOE, Op_RegI, 11, R(11)->as_VMReg()); -reg_def R_R12(SOC, SOC, Op_RegI, 12, R(12)->as_VMReg()); -reg_def R_R13(NS, NS, Op_RegI, 13, R(13)->as_VMReg()); -reg_def R_R14(SOC, SOC, Op_RegI, 14, R(14)->as_VMReg()); -reg_def R_R15(NS, NS, Op_RegI, 15, R(15)->as_VMReg()); +reg_def R_R0 (SOC, SOC, Op_RegI, 0, as_Register(0)->as_VMReg()); +reg_def R_R1 (SOC, SOC, Op_RegI, 1, as_Register(1)->as_VMReg()); +reg_def R_R2 (SOC, SOC, Op_RegI, 2, as_Register(2)->as_VMReg()); +reg_def R_R3 (SOC, SOC, Op_RegI, 3, as_Register(3)->as_VMReg()); +reg_def R_R4 (SOC, SOE, Op_RegI, 4, as_Register(4)->as_VMReg()); +reg_def R_R5 (SOC, SOE, Op_RegI, 5, as_Register(5)->as_VMReg()); +reg_def R_R6 (SOC, SOE, Op_RegI, 6, as_Register(6)->as_VMReg()); +reg_def R_R7 (SOC, SOE, Op_RegI, 7, as_Register(7)->as_VMReg()); +reg_def R_R8 (SOC, SOE, Op_RegI, 8, as_Register(8)->as_VMReg()); +reg_def R_R9 (SOC, SOE, Op_RegI, 9, as_Register(9)->as_VMReg()); +reg_def R_R10(NS, SOE, Op_RegI, 10, as_Register(10)->as_VMReg()); +reg_def R_R11(NS, SOE, Op_RegI, 11, as_Register(11)->as_VMReg()); +reg_def R_R12(SOC, SOC, Op_RegI, 12, as_Register(12)->as_VMReg()); +reg_def R_R13(NS, NS, Op_RegI, 13, as_Register(13)->as_VMReg()); +reg_def R_R14(SOC, SOC, Op_RegI, 14, as_Register(14)->as_VMReg()); +reg_def R_R15(NS, NS, Op_RegI, 15, as_Register(15)->as_VMReg()); // ---------------------------- // Float/Double Registers diff --git a/src/hotspot/cpu/arm/assembler_arm_32.hpp b/src/hotspot/cpu/arm/assembler_arm_32.hpp index ae13644ecf9..d6524f08680 100644 --- a/src/hotspot/cpu/arm/assembler_arm_32.hpp +++ b/src/hotspot/cpu/arm/assembler_arm_32.hpp @@ -114,7 +114,7 @@ class RegisterSet { } RegisterSet(Register first, Register last) { - assert(first < last, "encoding constraint"); + assert(first->encoding() < last->encoding(), "encoding constraint"); _encoding = (1 << (last->encoding() + 1)) - (1 << first->encoding()); } diff --git a/src/hotspot/cpu/arm/c1_CodeStubs_arm.cpp b/src/hotspot/cpu/arm/c1_CodeStubs_arm.cpp index 8e49cfcbcaa..3ef02e44b65 100644 --- a/src/hotspot/cpu/arm/c1_CodeStubs_arm.cpp +++ b/src/hotspot/cpu/arm/c1_CodeStubs_arm.cpp @@ -181,7 +181,7 @@ void MonitorEnterStub::emit_code(LIR_Assembler* ce) { const Register lock_reg = _lock_reg->as_pointer_register(); ce->verify_reserved_argument_area_size(2); - if (obj_reg < lock_reg) { + if (obj_reg->encoding() < lock_reg->encoding()) { __ stmia(SP, RegisterSet(obj_reg) | RegisterSet(lock_reg)); } else { __ str(obj_reg, Address(SP)); diff --git a/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp b/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp index f168a34f140..b314577c2c8 100644 --- a/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp +++ b/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp @@ -2639,11 +2639,11 @@ void LIR_Assembler::volatile_move_op(LIR_Opr src, LIR_Opr dest, BasicType type, const Register src_hi = src->as_register_hi(); assert(addr->index()->is_illegal() && addr->disp() == 0, "The address is simple already"); - if (src_lo < src_hi) { + if (src_lo->encoding() < src_hi->encoding()) { null_check_offset = __ offset(); __ stmia(addr->base()->as_register(), RegisterSet(src_lo) | RegisterSet(src_hi)); } else { - assert(src_lo < Rtemp, "Rtemp is higher than any allocatable register"); + assert(src_lo->encoding() < Rtemp->encoding(), "Rtemp is higher than any allocatable register"); __ mov(Rtemp, src_hi); null_check_offset = __ offset(); __ stmia(addr->base()->as_register(), RegisterSet(src_lo) | RegisterSet(Rtemp)); @@ -2656,10 +2656,10 @@ void LIR_Assembler::volatile_move_op(LIR_Opr src, LIR_Opr dest, BasicType type, assert(addr->index()->is_illegal() && addr->disp() == 0, "The address is simple already"); null_check_offset = __ offset(); - if (dest_lo < dest_hi) { + if (dest_lo->encoding() < dest_hi->encoding()) { __ ldmia(addr->base()->as_register(), RegisterSet(dest_lo) | RegisterSet(dest_hi)); } else { - assert(dest_lo < Rtemp, "Rtemp is higher than any allocatable register"); + assert(dest_lo->encoding() < Rtemp->encoding(), "Rtemp is higher than any allocatable register"); __ ldmia(addr->base()->as_register(), RegisterSet(dest_lo) | RegisterSet(Rtemp)); __ mov(dest_hi, Rtemp); } diff --git a/src/hotspot/cpu/arm/interp_masm_arm.cpp b/src/hotspot/cpu/arm/interp_masm_arm.cpp index 720413c9c5b..23ecea24eb2 100644 --- a/src/hotspot/cpu/arm/interp_masm_arm.cpp +++ b/src/hotspot/cpu/arm/interp_masm_arm.cpp @@ -409,7 +409,7 @@ void InterpreterMacroAssembler::pop_i(Register r) { void InterpreterMacroAssembler::pop_l(Register lo, Register hi) { assert_different_registers(lo, hi); - assert(lo < hi, "lo must be < hi"); + assert(lo->encoding() < hi->encoding(), "lo must be < hi"); pop(RegisterSet(lo) | RegisterSet(hi)); } @@ -459,7 +459,7 @@ void InterpreterMacroAssembler::push_i(Register r) { void InterpreterMacroAssembler::push_l(Register lo, Register hi) { assert_different_registers(lo, hi); - assert(lo < hi, "lo must be < hi"); + assert(lo->encoding() < hi->encoding(), "lo must be < hi"); push(RegisterSet(lo) | RegisterSet(hi)); } diff --git a/src/hotspot/cpu/arm/register_arm.cpp b/src/hotspot/cpu/arm/register_arm.cpp index ea3ef87e670..296c55e2e16 100644 --- a/src/hotspot/cpu/arm/register_arm.cpp +++ b/src/hotspot/cpu/arm/register_arm.cpp @@ -25,12 +25,19 @@ #include "register_arm.hpp" #include "utilities/debug.hpp" -const int ConcreteRegisterImpl::max_gpr = ConcreteRegisterImpl::num_gpr; -const int ConcreteRegisterImpl::max_fpr = ConcreteRegisterImpl::num_fpr + - ConcreteRegisterImpl::max_gpr; +Register::RegisterImpl all_RegisterImpls [Register::number_of_registers + 1]; +FloatRegister::FloatRegisterImpl all_FloatRegisterImpls [FloatRegister::number_of_registers + 1]; +VFPSystemRegister::VFPSystemRegisterImpl all_VFPSystemRegisterImpls [VFPSystemRegister::number_of_registers + 1] { + { -1 }, //vfpsnoreg + { VFPSystemRegister::FPSID }, + { VFPSystemRegister::FPSCR }, + { VFPSystemRegister::MVFR0 }, + { VFPSystemRegister::MVFR1 } +}; -const char* RegisterImpl::name() const { - const char* names[number_of_registers] = { +const char* Register::RegisterImpl::name() const { + static const char* names[number_of_registers + 1] = { + "noreg", "r0", "r1", "r2", "r3", "r4", "r5", "r6", #if (FP_REG_NUM == 7) "fp", @@ -45,13 +52,14 @@ const char* RegisterImpl::name() const { #endif "r12", "sp", "lr", "pc" }; - return is_valid() ? names[encoding()] : "noreg"; + return names[encoding() + 1]; } -const char* FloatRegisterImpl::name() const { - const char* names[number_of_registers] = { - "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", - "s8", "s9", "s10", "s11", "s12", "s13", "s14", "s15", +const char* FloatRegister::FloatRegisterImpl::name() const { + static const char* names[number_of_registers + 1] = { + "fnoreg", + "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", + "s8", "s9", "s10", "s11", "s12", "s13", "s14", "s15", "s16", "s17", "s18", "s19", "s20", "s21", "s22", "s23", "s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31" #ifdef COMPILER2 @@ -61,5 +69,5 @@ const char* FloatRegisterImpl::name() const { "s56", "s57?","s58", "s59?","s60", "s61?","s62", "s63?" #endif }; - return is_valid() ? names[encoding()] : "fnoreg"; + return names[encoding() + 1]; } diff --git a/src/hotspot/cpu/arm/register_arm.hpp b/src/hotspot/cpu/arm/register_arm.hpp index e0688af0d36..401d25a4fce 100644 --- a/src/hotspot/cpu/arm/register_arm.hpp +++ b/src/hotspot/cpu/arm/register_arm.hpp @@ -31,26 +31,6 @@ class VMRegImpl; typedef VMRegImpl* VMReg; -// These are declared ucontext.h -#undef R0 -#undef R1 -#undef R2 -#undef R3 -#undef R4 -#undef R5 -#undef R6 -#undef R7 -#undef R8 -#undef R9 -#undef R10 -#undef R11 -#undef R12 -#undef R13 -#undef R14 -#undef R15 - -#define R(r) ((Register)(r)) - ///////////////////////////////// // Support for different ARM ABIs // Note: default ABI is for linux @@ -94,25 +74,86 @@ typedef VMRegImpl* VMReg; #define ALIGN_WIDE_ARGUMENTS 1 #endif -#define R0 ((Register)0) -#define R1 ((Register)1) -#define R2 ((Register)2) -#define R3 ((Register)3) -#define R4 ((Register)4) -#define R5 ((Register)5) -#define R6 ((Register)6) -#define R7 ((Register)7) -#define R8 ((Register)8) -#define R9 ((Register)9) -#define R10 ((Register)10) -#define R11 ((Register)11) -#define R12 ((Register)12) -#define R13 ((Register)13) -#define R14 ((Register)14) -#define R15 ((Register)15) +class Register { + private: + int _encoding; + + constexpr explicit Register(int encoding) : _encoding(encoding) {} + + public: + enum { + number_of_registers = 16, + max_slots_per_register = 1 + }; + + class RegisterImpl : public AbstractRegisterImpl { + friend class Register; + + static constexpr const RegisterImpl* first(); + + public: + + // accessors and testers + int raw_encoding() const { return this - first(); } + int encoding() const { assert(is_valid(), "invalid register"); return raw_encoding(); } + bool is_valid() const { return 0 <= raw_encoding() && raw_encoding() < number_of_registers; } + + inline Register successor() const; + + VMReg as_VMReg() const; + + const char* name() const; + }; -#define FP ((Register)FP_REG_NUM) + inline friend constexpr Register as_Register(int encoding); + + constexpr Register() : _encoding(-1) {} //noreg + + int operator==(const Register r) const { return _encoding == r._encoding; } + int operator!=(const Register r) const { return _encoding != r._encoding; } + + const RegisterImpl* operator->() const { return RegisterImpl::first() + _encoding; } +}; + +extern Register::RegisterImpl all_RegisterImpls[Register::number_of_registers + 1] INTERNAL_VISIBILITY; + +inline constexpr const Register::RegisterImpl* Register::RegisterImpl::first() { + return all_RegisterImpls + 1; +} + +constexpr Register noreg = Register(); + +inline constexpr Register as_Register(int encoding) { + if (0 <= encoding && encoding < Register::number_of_registers) { + return Register(encoding); + } + return noreg; +} + +inline Register Register::RegisterImpl::successor() const { + assert(is_valid(), "sainty"); + return as_Register(encoding() + 1); +} + +constexpr Register R0 = as_Register( 0); +constexpr Register R1 = as_Register( 1); +constexpr Register R2 = as_Register( 2); +constexpr Register R3 = as_Register( 3); +constexpr Register R4 = as_Register( 4); +constexpr Register R5 = as_Register( 5); +constexpr Register R6 = as_Register( 6); +constexpr Register R7 = as_Register( 7); +constexpr Register R8 = as_Register( 8); +constexpr Register R9 = as_Register( 9); +constexpr Register R10 = as_Register(10); +constexpr Register R11 = as_Register(11); +constexpr Register R12 = as_Register(12); +constexpr Register R13 = as_Register(13); +constexpr Register R14 = as_Register(14); +constexpr Register R15 = as_Register(15); + +constexpr Register FP = as_Register(FP_REG_NUM); // Safe use of registers which may be FP on some platforms. // @@ -122,185 +163,170 @@ typedef VMRegImpl* VMReg; // as FP on supported ABIs (and replace R# by altFP_#_11). altFP_#_11 // must be #define to R11 if and only if # is FP_REG_NUM. #if (FP_REG_NUM == 7) -#define altFP_7_11 ((Register)11) +constexpr Register altFP_7_11 = R11; #else -#define altFP_7_11 ((Register)7) +constexpr Register altFP_7_11 = R7; #endif -#define SP R13 -#define LR R14 -#define PC R15 +constexpr Register SP = R13; +constexpr Register LR = R14; +constexpr Register PC = R15; -class RegisterImpl; -typedef RegisterImpl* Register; +class FloatRegister { + private: + int _encoding; -inline Register as_Register(int encoding) { - return (Register)(intptr_t)encoding; -} + constexpr explicit FloatRegister(int encoding) : _encoding(encoding) {} -class RegisterImpl : public AbstractRegisterImpl { public: enum { - number_of_registers = 16 + number_of_registers = NOT_COMPILER2(32) COMPILER2_PRESENT(64), + max_slots_per_register = 1 }; - Register successor() const { return as_Register(encoding() + 1); } + class FloatRegisterImpl : public AbstractRegisterImpl { + friend class FloatRegister; - inline friend Register as_Register(int encoding); + static constexpr const FloatRegisterImpl* first(); - VMReg as_VMReg(); + public: - // accessors - int encoding() const { assert(is_valid(), "invalid register"); return value(); } - const char* name() const; + // accessors and testers + int raw_encoding() const { return this - first(); } + int encoding() const { assert(is_valid(), "invalid register"); return raw_encoding(); } + bool is_valid() const { return 0 <= raw_encoding() && raw_encoding() < number_of_registers; } + inline FloatRegister successor() const; - // testers - bool is_valid() const { return 0 <= value() && value() < number_of_registers; } + VMReg as_VMReg() const; + int hi_bits() const { + return (encoding() >> 1) & 0xf; + } + + int lo_bit() const { + return encoding() & 1; + } + + int hi_bit() const { + return encoding() >> 5; + } + + const char* name() const; + }; + + inline friend constexpr FloatRegister as_FloatRegister(int encoding); + + constexpr FloatRegister() : _encoding(-1) {} // fnoreg + + int operator==(const FloatRegister r) const { return _encoding == r._encoding; } + int operator!=(const FloatRegister r) const { return _encoding != r._encoding; } + + const FloatRegisterImpl* operator->() const { return FloatRegisterImpl::first() + _encoding; } }; -CONSTANT_REGISTER_DECLARATION(Register, noreg, (-1)); +extern FloatRegister::FloatRegisterImpl all_FloatRegisterImpls[FloatRegister::number_of_registers + 1] INTERNAL_VISIBILITY; - -// Use FloatRegister as shortcut -class FloatRegisterImpl; -typedef FloatRegisterImpl* FloatRegister; - -inline FloatRegister as_FloatRegister(int encoding) { - return (FloatRegister)(intptr_t)encoding; +inline constexpr const FloatRegister::FloatRegisterImpl* FloatRegister::FloatRegisterImpl::first() { + return all_FloatRegisterImpls + 1; } -class FloatRegisterImpl : public AbstractRegisterImpl { - public: - enum { - number_of_registers = NOT_COMPILER2(32) COMPILER2_PRESENT(64) - }; +constexpr FloatRegister fnoreg = FloatRegister(); - inline friend FloatRegister as_FloatRegister(int encoding); - - VMReg as_VMReg(); - - int encoding() const { assert(is_valid(), "invalid register"); return value(); } - bool is_valid() const { return 0 <= (intx)this && (intx)this < number_of_registers; } - FloatRegister successor() const { return as_FloatRegister(encoding() + 1); } - - const char* name() const; - - int hi_bits() const { - return (encoding() >> 1) & 0xf; +inline constexpr FloatRegister as_FloatRegister(int encoding) { + if (0 <= encoding && encoding < FloatRegister::number_of_registers) { + return FloatRegister(encoding); } + return fnoreg; +} - int lo_bit() const { - return encoding() & 1; - } - - int hi_bit() const { - return encoding() >> 5; - } -}; - -CONSTANT_REGISTER_DECLARATION(FloatRegister, fnoreg, (-1)); +inline FloatRegister FloatRegister::FloatRegisterImpl::successor() const { + assert(is_valid(), "sainty"); + return as_FloatRegister(encoding() + 1); +} /* * S1-S6 are named with "_reg" suffix to avoid conflict with * constants defined in sharedRuntimeTrig.cpp */ -CONSTANT_REGISTER_DECLARATION(FloatRegister, S0, ( 0)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, S1_reg, ( 1)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, S2_reg, ( 2)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, S3_reg, ( 3)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, S4_reg, ( 4)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, S5_reg, ( 5)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, S6_reg, ( 6)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, S7, ( 7)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, S8, ( 8)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, S9, ( 9)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, S10, (10)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, S11, (11)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, S12, (12)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, S13, (13)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, S14, (14)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, S15, (15)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, S16, (16)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, S17, (17)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, S18, (18)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, S19, (19)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, S20, (20)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, S21, (21)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, S22, (22)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, S23, (23)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, S24, (24)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, S25, (25)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, S26, (26)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, S27, (27)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, S28, (28)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, S29, (29)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, S30, (30)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, S31, (31)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, Stemp, (30)); +constexpr FloatRegister S0 = as_FloatRegister( 0); +constexpr FloatRegister S1_reg = as_FloatRegister(1); +constexpr FloatRegister S2_reg = as_FloatRegister(2); +constexpr FloatRegister S3_reg = as_FloatRegister(3); +constexpr FloatRegister S4_reg = as_FloatRegister(4); +constexpr FloatRegister S5_reg = as_FloatRegister(5); +constexpr FloatRegister S6_reg = as_FloatRegister(6); +constexpr FloatRegister S7 = as_FloatRegister( 7); +constexpr FloatRegister S8 = as_FloatRegister( 8); +constexpr FloatRegister S9 = as_FloatRegister( 9); +constexpr FloatRegister S10 = as_FloatRegister(10); +constexpr FloatRegister S11 = as_FloatRegister(11); +constexpr FloatRegister S12 = as_FloatRegister(12); +constexpr FloatRegister S13 = as_FloatRegister(13); +constexpr FloatRegister S14 = as_FloatRegister(14); +constexpr FloatRegister S15 = as_FloatRegister(15); +constexpr FloatRegister S16 = as_FloatRegister(16); +constexpr FloatRegister S17 = as_FloatRegister(17); +constexpr FloatRegister S18 = as_FloatRegister(18); +constexpr FloatRegister S19 = as_FloatRegister(19); +constexpr FloatRegister S20 = as_FloatRegister(20); +constexpr FloatRegister S21 = as_FloatRegister(21); +constexpr FloatRegister S22 = as_FloatRegister(22); +constexpr FloatRegister S23 = as_FloatRegister(23); +constexpr FloatRegister S24 = as_FloatRegister(24); +constexpr FloatRegister S25 = as_FloatRegister(25); +constexpr FloatRegister S26 = as_FloatRegister(26); +constexpr FloatRegister S27 = as_FloatRegister(27); +constexpr FloatRegister S28 = as_FloatRegister(28); +constexpr FloatRegister S29 = as_FloatRegister(29); +constexpr FloatRegister S30 = as_FloatRegister(30); +constexpr FloatRegister S31 = as_FloatRegister(31); +constexpr FloatRegister Stemp = S30; -CONSTANT_REGISTER_DECLARATION(FloatRegister, D0, ( 0)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, D1, ( 2)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, D2, ( 4)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, D3, ( 6)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, D4, ( 8)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, D5, ( 10)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, D6, ( 12)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, D7, ( 14)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, D8, ( 16)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, D9, ( 18)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, D10, ( 20)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, D11, ( 22)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, D12, ( 24)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, D13, ( 26)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, D14, ( 28)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, D15, (30)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, D16, (32)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, D17, (34)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, D18, (36)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, D19, (38)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, D20, (40)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, D21, (42)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, D22, (44)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, D23, (46)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, D24, (48)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, D25, (50)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, D26, (52)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, D27, (54)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, D28, (56)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, D29, (58)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, D30, (60)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, D31, (62)); +constexpr FloatRegister D0 = as_FloatRegister( 0); +constexpr FloatRegister D1 = as_FloatRegister( 2); +constexpr FloatRegister D2 = as_FloatRegister( 4); +constexpr FloatRegister D3 = as_FloatRegister( 6); +constexpr FloatRegister D4 = as_FloatRegister( 8); +constexpr FloatRegister D5 = as_FloatRegister(10); +constexpr FloatRegister D6 = as_FloatRegister(12); +constexpr FloatRegister D7 = as_FloatRegister(14); +constexpr FloatRegister D8 = as_FloatRegister(16); +constexpr FloatRegister D9 = as_FloatRegister(18); +constexpr FloatRegister D10 = as_FloatRegister(20); +constexpr FloatRegister D11 = as_FloatRegister(22); +constexpr FloatRegister D12 = as_FloatRegister(24); +constexpr FloatRegister D13 = as_FloatRegister(26); +constexpr FloatRegister D14 = as_FloatRegister(28); +constexpr FloatRegister D15 = as_FloatRegister(30); +constexpr FloatRegister D16 = as_FloatRegister(32); +constexpr FloatRegister D17 = as_FloatRegister(34); +constexpr FloatRegister D18 = as_FloatRegister(36); +constexpr FloatRegister D19 = as_FloatRegister(38); +constexpr FloatRegister D20 = as_FloatRegister(40); +constexpr FloatRegister D21 = as_FloatRegister(42); +constexpr FloatRegister D22 = as_FloatRegister(44); +constexpr FloatRegister D23 = as_FloatRegister(46); +constexpr FloatRegister D24 = as_FloatRegister(48); +constexpr FloatRegister D25 = as_FloatRegister(50); +constexpr FloatRegister D26 = as_FloatRegister(52); +constexpr FloatRegister D27 = as_FloatRegister(54); +constexpr FloatRegister D28 = as_FloatRegister(56); +constexpr FloatRegister D29 = as_FloatRegister(58); +constexpr FloatRegister D30 = as_FloatRegister(60); +constexpr FloatRegister D31 = as_FloatRegister(62); class ConcreteRegisterImpl : public AbstractRegisterImpl { public: enum { - log_vmregs_per_word = LogBytesPerWord - LogBytesPerInt, // VMRegs are of 4-byte size -#ifdef COMPILER2 - log_bytes_per_fpr = 2, // quad vectors -#else - log_bytes_per_fpr = 2, // double vectors -#endif - log_words_per_fpr = log_bytes_per_fpr - LogBytesPerWord, - words_per_fpr = 1 << log_words_per_fpr, - log_vmregs_per_fpr = log_bytes_per_fpr - LogBytesPerInt, - log_vmregs_per_gpr = log_vmregs_per_word, - vmregs_per_gpr = 1 << log_vmregs_per_gpr, - vmregs_per_fpr = 1 << log_vmregs_per_fpr, + max_gpr = Register::number_of_registers * Register::max_slots_per_register, + max_fpr = max_gpr + FloatRegister::number_of_registers * FloatRegister::max_slots_per_register, - num_gpr = RegisterImpl::number_of_registers << log_vmregs_per_gpr, - max_gpr0 = num_gpr, - num_fpr = FloatRegisterImpl::number_of_registers << log_vmregs_per_fpr, - max_fpr0 = max_gpr0 + num_fpr, - number_of_registers = num_gpr + num_fpr + 1+1 // APSR and FPSCR so that c2's REG_COUNT <= ConcreteRegisterImpl::number_of_registers + number_of_registers = max_fpr + 1+1 // APSR and FPSCR so that c2's REG_COUNT <= ConcreteRegisterImpl::number_of_registers }; - - static const int max_gpr; - static const int max_fpr; }; typedef AbstractRegSet RegSet; @@ -328,100 +354,156 @@ inline FloatRegister AbstractRegSet::last() { -class VFPSystemRegisterImpl; -typedef VFPSystemRegisterImpl* VFPSystemRegister; -class VFPSystemRegisterImpl : public AbstractRegisterImpl { +class VFPSystemRegister { + private: + int _store_idx; + + constexpr explicit VFPSystemRegister(int store_idx) : _store_idx(store_idx) {} + + enum { + _FPSID_store_idx = 0, + _FPSCR_store_idx = 1, + _MVFR0_store_idx = 2, + _MVFR1_store_idx = 3 + }; + public: - int encoding() const { return value(); } + enum { + FPSID = 0, + FPSCR = 1, + MVFR0 = 6, + MVFR1 = 7, + number_of_registers = 4 + }; + + class VFPSystemRegisterImpl : public AbstractRegisterImpl { + friend class VFPSystemRegister; + + int _encoding; + + static constexpr const VFPSystemRegisterImpl* first(); + + public: + constexpr VFPSystemRegisterImpl(int encoding) : _encoding(encoding) {} + + int encoding() const { return _encoding; } + }; + + inline friend constexpr VFPSystemRegister as_VFPSystemRegister(int encoding); + + constexpr VFPSystemRegister() : _store_idx(-1) {} // vfpsnoreg + + int operator==(const VFPSystemRegister r) const { return _store_idx == r._store_idx; } + int operator!=(const VFPSystemRegister r) const { return _store_idx != r._store_idx; } + + const VFPSystemRegisterImpl* operator->() const { return VFPSystemRegisterImpl::first() + _store_idx; } }; -#define FPSID ((VFPSystemRegister)0) -#define FPSCR ((VFPSystemRegister)1) -#define MVFR0 ((VFPSystemRegister)0x6) -#define MVFR1 ((VFPSystemRegister)0x7) +extern VFPSystemRegister::VFPSystemRegisterImpl all_VFPSystemRegisterImpls[VFPSystemRegister::number_of_registers + 1] INTERNAL_VISIBILITY; + +inline constexpr const VFPSystemRegister::VFPSystemRegisterImpl* VFPSystemRegister::VFPSystemRegisterImpl::first() { + return all_VFPSystemRegisterImpls + 1; +} + +constexpr VFPSystemRegister vfpsnoreg = VFPSystemRegister(); + +inline constexpr VFPSystemRegister as_VFPSystemRegister(int encoding) { + switch (encoding) { + case VFPSystemRegister::FPSID: return VFPSystemRegister(VFPSystemRegister::_FPSID_store_idx); + case VFPSystemRegister::FPSCR: return VFPSystemRegister(VFPSystemRegister::_FPSCR_store_idx); + case VFPSystemRegister::MVFR0: return VFPSystemRegister(VFPSystemRegister::_MVFR0_store_idx); + case VFPSystemRegister::MVFR1: return VFPSystemRegister(VFPSystemRegister::_MVFR1_store_idx); + default: return vfpsnoreg; + } +} + +constexpr VFPSystemRegister FPSID = as_VFPSystemRegister(VFPSystemRegister::FPSID); +constexpr VFPSystemRegister FPSCR = as_VFPSystemRegister(VFPSystemRegister::FPSCR); +constexpr VFPSystemRegister MVFR0 = as_VFPSystemRegister(VFPSystemRegister::MVFR0); +constexpr VFPSystemRegister MVFR1 = as_VFPSystemRegister(VFPSystemRegister::MVFR1); /* * Register definitions shared across interpreter and compiler */ -#define Rexception_obj R4 -#define Rexception_pc R5 +constexpr Register Rexception_obj = R4; +constexpr Register Rexception_pc = R5; /* * Interpreter register definitions common to C++ and template interpreters. */ -#define Rlocals R8 -#define Rmethod R9 -#define Rthread R10 -#define Rtemp R12 +constexpr Register Rlocals = R8; +constexpr Register Rmethod = R9; +constexpr Register Rthread = R10; +constexpr Register Rtemp = R12; // Interpreter calling conventions -#define Rparams SP -#define Rsender_sp R4 +constexpr Register Rparams = SP; +constexpr Register Rsender_sp = R4; // JSR292 // Note: R5_mh is needed only during the call setup, including adapters // This does not seem to conflict with Rexception_pc // In case of issues, R3 might be OK but adapters calling the runtime would have to save it -#define R5_mh R5 // MethodHandle register, used during the call setup +constexpr Register R5_mh = R5; // MethodHandle register, used during the call setup /* * C++ Interpreter Register Defines */ -#define Rsave0 R4 -#define Rsave1 R5 -#define Rsave2 R6 -#define Rstate altFP_7_11 // R7 or R11 -#define Ricklass R8 +constexpr Register Rsave0 = R4; +constexpr Register Rsave1 = R5; +constexpr Register Rsave2 = R6; +constexpr Register Rstate = altFP_7_11; // R7 or R11 +constexpr Register Ricklass = R8; /* * TemplateTable Interpreter Register Usage */ // Temporary registers -#define R0_tmp R0 -#define R1_tmp R1 -#define R2_tmp R2 -#define R3_tmp R3 -#define R4_tmp R4 -#define R5_tmp R5 -#define R12_tmp R12 -#define LR_tmp LR +constexpr Register R0_tmp = R0; +constexpr Register R1_tmp = R1; +constexpr Register R2_tmp = R2; +constexpr Register R3_tmp = R3; +constexpr Register R4_tmp = R4; +constexpr Register R5_tmp = R5; +constexpr Register R12_tmp = R12; +constexpr Register LR_tmp = LR; -#define S0_tmp S0 -#define S1_tmp S1_reg +constexpr FloatRegister S0_tmp = S0; +constexpr FloatRegister S1_tmp = S1_reg; -#define D0_tmp D0 -#define D1_tmp D1 +constexpr FloatRegister D0_tmp = D0; +constexpr FloatRegister D1_tmp = D1; // Temporary registers saved across VM calls (according to C calling conventions) -#define Rtmp_save0 R4 -#define Rtmp_save1 R5 +constexpr Register Rtmp_save0 = R4; +constexpr Register Rtmp_save1 = R5; // Cached TOS value -#define R0_tos R0 +constexpr Register R0_tos = R0; -#define R0_tos_lo R0 -#define R1_tos_hi R1 +constexpr Register R0_tos_lo = R0; +constexpr Register R1_tos_hi = R1; -#define S0_tos S0 -#define D0_tos D0 +constexpr FloatRegister S0_tos = S0; +constexpr FloatRegister D0_tos = D0; // Dispatch table -#define RdispatchTable R6 +constexpr Register RdispatchTable = R6; // Bytecode pointer -#define Rbcp altFP_7_11 +constexpr Register Rbcp = altFP_7_11; // Pre-loaded next bytecode for the dispatch -#define R3_bytecode R3 +constexpr Register R3_bytecode = R3; // Conventions between bytecode templates and stubs -#define R2_ClassCastException_obj R2 -#define R4_ArrayIndexOutOfBounds_index R4 +constexpr Register R2_ClassCastException_obj = R2; +constexpr Register R4_ArrayIndexOutOfBounds_index = R4; // Interpreter expression stack top -#define Rstack_top SP +constexpr Register Rstack_top = SP; /* * Linux 32-bit ARM C ABI Register calling conventions @@ -444,10 +526,11 @@ class VFPSystemRegisterImpl : public AbstractRegisterImpl { * R14 (LR) Link register * R15 (PC) Program Counter */ -#define c_rarg0 R0 -#define c_rarg1 R1 -#define c_rarg2 R2 -#define c_rarg3 R3 + +constexpr Register c_rarg0 = R0; +constexpr Register c_rarg1 = R1; +constexpr Register c_rarg2 = R2; +constexpr Register c_rarg3 = R3; #define GPR_PARAMS 4 @@ -455,10 +538,10 @@ class VFPSystemRegisterImpl : public AbstractRegisterImpl { // Java ABI // XXX Is this correct? -#define j_rarg0 c_rarg0 -#define j_rarg1 c_rarg1 -#define j_rarg2 c_rarg2 -#define j_rarg3 c_rarg3 +constexpr Register j_rarg0 = c_rarg0; +constexpr Register j_rarg1 = c_rarg1; +constexpr Register j_rarg2 = c_rarg2; +constexpr Register j_rarg3 = c_rarg3; #endif // CPU_ARM_REGISTER_ARM_HPP diff --git a/src/hotspot/cpu/arm/sharedRuntime_arm.cpp b/src/hotspot/cpu/arm/sharedRuntime_arm.cpp index 76e38d29478..13e1f4493ff 100644 --- a/src/hotspot/cpu/arm/sharedRuntime_arm.cpp +++ b/src/hotspot/cpu/arm/sharedRuntime_arm.cpp @@ -70,7 +70,7 @@ public: enum RegisterLayout { - fpu_save_size = FloatRegisterImpl::number_of_registers, + fpu_save_size = FloatRegister::number_of_registers, #ifndef __SOFTFP__ D0_offset = 0, #endif @@ -139,8 +139,8 @@ OopMap* RegisterSaver::save_live_registers(MacroAssembler* masm, if (VM_Version::has_vfp3_32()) { __ fpush(FloatRegisterSet(D16, 16)); } else { - if (FloatRegisterImpl::number_of_registers > 32) { - assert(FloatRegisterImpl::number_of_registers == 64, "nb fp registers should be 64"); + if (FloatRegister::number_of_registers > 32) { + assert(FloatRegister::number_of_registers == 64, "nb fp registers should be 64"); __ sub(SP, SP, 32 * wordSize); } } @@ -182,8 +182,8 @@ void RegisterSaver::restore_live_registers(MacroAssembler* masm, bool restore_lr if (VM_Version::has_vfp3_32()) { __ fpop(FloatRegisterSet(D16, 16)); } else { - if (FloatRegisterImpl::number_of_registers > 32) { - assert(FloatRegisterImpl::number_of_registers == 64, "nb fp registers should be 64"); + if (FloatRegister::number_of_registers > 32) { + assert(FloatRegister::number_of_registers == 64, "nb fp registers should be 64"); __ add(SP, SP, 32 * wordSize); } } diff --git a/src/hotspot/cpu/arm/vmreg_arm.cpp b/src/hotspot/cpu/arm/vmreg_arm.cpp index 4ce1dd0be20..efaf38ef729 100644 --- a/src/hotspot/cpu/arm/vmreg_arm.cpp +++ b/src/hotspot/cpu/arm/vmreg_arm.cpp @@ -30,14 +30,14 @@ void VMRegImpl::set_regName() { Register reg = ::as_Register(0); int i; for (i = 0; i < ConcreteRegisterImpl::max_gpr; reg = reg->successor()) { - for (int j = 0; j < (1 << ConcreteRegisterImpl::log_vmregs_per_gpr); j++) { + for (int j = 0; j < Register::max_slots_per_register; j++) { regName[i++] = reg->name(); } } #ifndef __SOFTFP__ FloatRegister freg = ::as_FloatRegister(0); for ( ; i < ConcreteRegisterImpl::max_fpr ; ) { - for (int j = 0; j < (1 << ConcreteRegisterImpl::log_vmregs_per_fpr); j++) { + for (int j = 0; j < Register::max_slots_per_register; j++) { regName[i++] = freg->name(); } freg = freg->successor(); diff --git a/src/hotspot/cpu/arm/vmreg_arm.hpp b/src/hotspot/cpu/arm/vmreg_arm.hpp index c13f443b804..f1dfd09a1e6 100644 --- a/src/hotspot/cpu/arm/vmreg_arm.hpp +++ b/src/hotspot/cpu/arm/vmreg_arm.hpp @@ -36,20 +36,20 @@ inline Register as_Register() { assert(is_Register(), "must be"); assert(is_concrete(), "concrete register expected"); - return ::as_Register(value() >> ConcreteRegisterImpl::log_vmregs_per_gpr); + return ::as_Register(value() / Register::max_slots_per_register); } inline FloatRegister as_FloatRegister() { assert(is_FloatRegister(), "must be"); assert(is_concrete(), "concrete register expected"); - return ::as_FloatRegister((value() - ConcreteRegisterImpl::max_gpr) >> ConcreteRegisterImpl::log_vmregs_per_fpr); + return ::as_FloatRegister((value() - ConcreteRegisterImpl::max_gpr) / FloatRegister::max_slots_per_register); } inline bool is_concrete() { if (is_Register()) { - return ((value() & right_n_bits(ConcreteRegisterImpl::log_vmregs_per_gpr)) == 0); + return (value() % Register::max_slots_per_register == 0); } else if (is_FloatRegister()) { - return (((value() - ConcreteRegisterImpl::max_gpr) & right_n_bits(ConcreteRegisterImpl::log_vmregs_per_fpr)) == 0); + return (value() % FloatRegister::max_slots_per_register == 0); // Single slot } else { return false; } diff --git a/src/hotspot/cpu/arm/vmreg_arm.inline.hpp b/src/hotspot/cpu/arm/vmreg_arm.inline.hpp index f122b9ede70..3e5c18dbda0 100644 --- a/src/hotspot/cpu/arm/vmreg_arm.inline.hpp +++ b/src/hotspot/cpu/arm/vmreg_arm.inline.hpp @@ -25,11 +25,11 @@ #ifndef CPU_ARM_VMREG_ARM_INLINE_HPP #define CPU_ARM_VMREG_ARM_INLINE_HPP -inline VMReg RegisterImpl::as_VMReg() { - return VMRegImpl::as_VMReg(encoding() << ConcreteRegisterImpl::log_vmregs_per_gpr); +inline VMReg Register::RegisterImpl::as_VMReg() const { + return VMRegImpl::as_VMReg(encoding() * Register::max_slots_per_register); } -inline VMReg FloatRegisterImpl::as_VMReg() { - return VMRegImpl::as_VMReg((encoding() << ConcreteRegisterImpl::log_vmregs_per_fpr) + ConcreteRegisterImpl::max_gpr); +inline VMReg FloatRegister::FloatRegisterImpl::as_VMReg() const { + return VMRegImpl::as_VMReg((encoding() * FloatRegister::max_slots_per_register) + ConcreteRegisterImpl::max_gpr); } #endif // CPU_ARM_VMREG_ARM_INLINE_HPP diff --git a/src/hotspot/os_cpu/linux_arm/macroAssembler_linux_arm_32.cpp b/src/hotspot/os_cpu/linux_arm/macroAssembler_linux_arm_32.cpp index e74daaa6d66..e4737191cfc 100644 --- a/src/hotspot/os_cpu/linux_arm/macroAssembler_linux_arm_32.cpp +++ b/src/hotspot/os_cpu/linux_arm/macroAssembler_linux_arm_32.cpp @@ -246,9 +246,9 @@ void MacroAssembler::atomic_cas64(Register memval_lo, Register memval_hi, Regist Label loop; assert_different_registers(memval_lo, memval_hi, result, oldval_lo, oldval_hi, newval_lo, newval_hi, base); - assert(memval_hi == memval_lo + 1 && memval_lo < R9, "cmpxchg_long: illegal registers"); - assert(oldval_hi == oldval_lo + 1 && oldval_lo < R9, "cmpxchg_long: illegal registers"); - assert(newval_hi == newval_lo + 1 && newval_lo < R9, "cmpxchg_long: illegal registers"); + assert(memval_hi == as_Register(memval_lo->encoding() + 1) && memval_lo->encoding() < R9->encoding(), "cmpxchg_long: illegal registers"); + assert(oldval_hi == as_Register(oldval_lo->encoding() + 1) && oldval_lo->encoding() < R9->encoding(), "cmpxchg_long: illegal registers"); + assert(newval_hi == as_Register(newval_lo->encoding() + 1) && newval_lo->encoding() < R9->encoding(), "cmpxchg_long: illegal registers"); assert(result != R10, "cmpxchg_long: illegal registers"); assert(base != R10, "cmpxchg_long: illegal registers"); From c0abecdd1ffe59314bc17aeec0684cdda33a222d Mon Sep 17 00:00:00 2001 From: Erik Gahlin Date: Tue, 25 Nov 2025 18:48:17 +0000 Subject: [PATCH 002/706] 8372441: JFR: Improve logging of TestBackToBackSensitive Reviewed-by: mgronlun --- .../runtime/TestBackToBackSensitive.java | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/test/jdk/jdk/jfr/event/runtime/TestBackToBackSensitive.java b/test/jdk/jdk/jfr/event/runtime/TestBackToBackSensitive.java index 91fcd60f87d..147caee82ea 100644 --- a/test/jdk/jdk/jfr/event/runtime/TestBackToBackSensitive.java +++ b/test/jdk/jdk/jfr/event/runtime/TestBackToBackSensitive.java @@ -67,6 +67,7 @@ public class TestBackToBackSensitive { if (cl != null) { if (cl.getType().getName().contains("PlatformClassLoader")) { classLoaderStatistics.add(e.getStartTime()); + System.out.println("Class loader" + e); } } }); @@ -87,20 +88,20 @@ public class TestBackToBackSensitive { r1.stop(); long chunkFiles = filesInRepository(); System.out.println("Number of chunk files: " + chunkFiles); + // When jdk.PhysicalMemory is expected to be emitted: + // Chunk 1: begin, end + // Chunk 2: begin, end + // Chunk 3: begin, end + // Chunk 4: begin, end + assertCount(r1, "jdk.PhysicalMemory", physicalMemory, 2 * chunkFiles); // When jdk.ClassLoaderStatistics and jdk.ThreadThreadDump are expected to be // emitted: // Chunk 1: begin, end // Chunk 2: begin, end // Chunk 3: end // Chunk 4: end - assertCount("jdk.ThreadDump", threadDumps, 2 + 2 + (chunkFiles - 2)); - assertCount("jdk.ClassLoaderStatistics", classLoaderStatistics, 2 + 2 + (chunkFiles - 2)); - // When jdk.PhysicalMemory is expected to be emitted: - // Chunk 1: begin, end - // Chunk 2: begin, end - // Chunk 3: begin, end - // Chunk 4: begin, end - assertCount("jdk.PhysicalMemory", physicalMemory, 2 * chunkFiles); + assertCount(r1, "jdk.ThreadDump", threadDumps, 2 + 2 + (chunkFiles - 2)); + assertCount(r1, "jdk.ClassLoaderStatistics", classLoaderStatistics, 2 + 2 + (chunkFiles - 2)); } } @@ -109,13 +110,15 @@ public class TestBackToBackSensitive { return Files.list(repository).filter(p -> p.toString().endsWith(".jfr")).count(); } - private static void assertCount(String eventName, Set timestamps, long expected) throws Exception { + private static void assertCount(RecordingStream stream, String eventName, Set timestamps, long expected) throws Exception { System.out.println("Timestamps for " + eventName + ":"); for (Instant timestamp : timestamps) { System.out.println(timestamp); } int count = timestamps.size(); if (count != expected) { + System.out.println("Dumping failure file."); + stream.dump(Path.of("failure.jfr")); throw new Exception("Expected " + expected + " timestamps for event " + eventName + ", but got " + count); } } From b36b69470968b1578877cfe9658892a5fe44e38e Mon Sep 17 00:00:00 2001 From: Volodymyr Paprotski Date: Tue, 25 Nov 2025 22:42:53 +0000 Subject: [PATCH 003/706] 8371259: ML-DSA AVX2 and AVX512 intrinsics and improvements Reviewed-by: sviswanathan, mpowers, ascarpino --- src/hotspot/cpu/x86/assembler_x86.cpp | 40 + src/hotspot/cpu/x86/assembler_x86.hpp | 5 + src/hotspot/cpu/x86/macroAssembler_x86.hpp | 1 + .../x86/stubGenerator_x86_64_dilithium.cpp | 1664 ++++++++++------- src/hotspot/cpu/x86/vm_version_x86.cpp | 3 +- .../provider/acvp/ML_DSA_Intrinsic_Test.java | 516 +++++ 6 files changed, 1549 insertions(+), 680 deletions(-) create mode 100644 test/jdk/sun/security/provider/acvp/ML_DSA_Intrinsic_Test.java diff --git a/src/hotspot/cpu/x86/assembler_x86.cpp b/src/hotspot/cpu/x86/assembler_x86.cpp index e3ba0ebb56a..cbc5c6988d4 100644 --- a/src/hotspot/cpu/x86/assembler_x86.cpp +++ b/src/hotspot/cpu/x86/assembler_x86.cpp @@ -3860,6 +3860,46 @@ void Assembler::evmovdquq(Address dst, KRegister mask, XMMRegister src, bool mer emit_operand(src, dst, 0); } +void Assembler::vmovsldup(XMMRegister dst, XMMRegister src, int vector_len) { + assert(vector_len == AVX_512bit ? VM_Version::supports_evex() : VM_Version::supports_avx(), ""); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F, &attributes); + emit_int16(0x12, (0xC0 | encode)); +} + +void Assembler::vmovshdup(XMMRegister dst, XMMRegister src, int vector_len) { + assert(vector_len == AVX_512bit ? VM_Version::supports_evex() : VM_Version::supports_avx(), ""); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F, &attributes); + emit_int16(0x16, (0xC0 | encode)); +} + +void Assembler::evmovsldup(XMMRegister dst, KRegister mask, XMMRegister src, bool merge, int vector_len) { + assert(VM_Version::supports_evex(), ""); + assert(vector_len == AVX_512bit || VM_Version::supports_avx512vl(), ""); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_embedded_opmask_register_specifier(mask); + attributes.set_is_evex_instruction(); + if (merge) { + attributes.reset_is_clear_context(); + } + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F, &attributes); + emit_int16(0x12, (0xC0 | encode)); +} + +void Assembler::evmovshdup(XMMRegister dst, KRegister mask, XMMRegister src, bool merge, int vector_len) { + assert(VM_Version::supports_evex(), ""); + assert(vector_len == AVX_512bit || VM_Version::supports_avx512vl(), ""); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_embedded_opmask_register_specifier(mask); + attributes.set_is_evex_instruction(); + if (merge) { + attributes.reset_is_clear_context(); + } + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F, &attributes); + emit_int16(0x16, (0xC0 | encode)); +} + // Uses zero extension on 64bit void Assembler::movl(Register dst, int32_t imm32) { diff --git a/src/hotspot/cpu/x86/assembler_x86.hpp b/src/hotspot/cpu/x86/assembler_x86.hpp index c863191df4c..43471a88391 100644 --- a/src/hotspot/cpu/x86/assembler_x86.hpp +++ b/src/hotspot/cpu/x86/assembler_x86.hpp @@ -1664,6 +1664,11 @@ private: void evmovdqaq(XMMRegister dst, Address src, int vector_len); void evmovdqaq(XMMRegister dst, KRegister mask, Address src, bool merge, int vector_len); + void vmovsldup(XMMRegister dst, XMMRegister src, int vector_len); + void vmovshdup(XMMRegister dst, XMMRegister src, int vector_len); + void evmovsldup(XMMRegister dst, KRegister mask, XMMRegister src, bool merge, int vector_len); + void evmovshdup(XMMRegister dst, KRegister mask, XMMRegister src, bool merge, int vector_len); + // Move lower 64bit to high 64bit in 128bit register void movlhps(XMMRegister dst, XMMRegister src); diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.hpp b/src/hotspot/cpu/x86/macroAssembler_x86.hpp index 4cecaa55345..695eea6ad03 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.hpp @@ -1368,6 +1368,7 @@ public: void vpcmpeqw(XMMRegister dst, XMMRegister nds, Address src, int vector_len); void vpcmpeqw(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); + using Assembler::evpcmpeqd; void evpcmpeqd(KRegister kdst, KRegister mask, XMMRegister nds, AddressLiteral src, int vector_len, Register rscratch = noreg); // Vector compares diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_dilithium.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_dilithium.cpp index 9555d60c8a4..b9590939468 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64_dilithium.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_dilithium.cpp @@ -1,5 +1,6 @@ /* * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Intel Corporation. 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,8 +31,6 @@ #define __ _masm-> -#define xmm(i) as_XMMRegister(i) - #ifdef PRODUCT #define BLOCK_COMMENT(str) /* nothing */ #else @@ -40,15 +39,13 @@ #define BIND(label) bind(label); BLOCK_COMMENT(#label ":") -#define XMMBYTES 64 - // Constants // ATTRIBUTE_ALIGNED(64) static const uint32_t dilithiumAvx512Consts[] = { 58728449, // montQInvModR - 8380417, // dilithium_q - 2365951, // montRSquareModQ - 5373807 // Barrett addend for modular reduction + 8380417, // dilithium_q + 2365951, // montRSquareModQ + 5373807 // Barrett addend for modular reduction }; const int montQInvModRIdx = 0; @@ -60,392 +57,590 @@ static address dilithiumAvx512ConstsAddr(int offset) { return ((address) dilithiumAvx512Consts) + offset; } -const Register scratch = r10; -const XMMRegister montMulPerm = xmm28; -const XMMRegister montQInvModR = xmm30; -const XMMRegister dilithium_q = xmm31; +ATTRIBUTE_ALIGNED(64) static const uint32_t unshufflePerms[] = { + // Shuffle for the 128-bit element swap (uint64_t) + 0, 0, 1, 0, 8, 0, 9, 0, 4, 0, 5, 0, 12, 0, 13, 0, + 10, 0, 11, 0, 2, 0, 3, 0, 14, 0, 15, 0, 6, 0, 7, 0, + // Final shuffle for AlmostNtt + 0, 16, 1, 17, 2, 18, 3, 19, 4, 20, 5, 21, 6, 22, 7, 23, + 24, 8, 25, 9, 26, 10, 27, 11, 28, 12, 29, 13, 30, 14, 31, 15, -ATTRIBUTE_ALIGNED(64) static const uint32_t dilithiumAvx512Perms[] = { - // collect montmul results into the destination register - 17, 1, 19, 3, 21, 5, 23, 7, 25, 9, 27, 11, 29, 13, 31, 15, - // ntt - // level 4 - 0, 1, 2, 3, 4, 5, 6, 7, 16, 17, 18, 19, 20, 21, 22, 23, - 8, 9, 10, 11, 12, 13, 14, 15, 24, 25, 26, 27, 28, 29, 30, 31, - // level 5 - 0, 1, 2, 3, 16, 17, 18, 19, 8, 9, 10, 11, 24, 25, 26, 27, - 4, 5, 6, 7, 20, 21, 22, 23, 12, 13, 14, 15, 28, 29, 30, 31, - // level 6 - 0, 1, 16, 17, 4, 5, 20, 21, 8, 9, 24, 25, 12, 13, 28, 29, - 2, 3, 18, 19, 6, 7, 22, 23, 10, 11, 26, 27, 14, 15, 30, 31, - // level 7 - 0, 16, 2, 18, 4, 20, 6, 22, 8, 24, 10, 26, 12, 28, 14, 30, - 1, 17, 3, 19, 5, 21, 7, 23, 9, 25, 11, 27, 13, 29, 15, 31, - 0, 16, 1, 17, 2, 18, 3, 19, 4, 20, 5, 21, 6, 22, 7, 23, - 8, 24, 9, 25, 10, 26, 11, 27, 12, 28, 13, 29, 14, 30, 15, 31, - - // ntt inverse - // level 0 - 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, - 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, - // level 1 - 0, 16, 2, 18, 4, 20, 6, 22, 8, 24, 10, 26, 12, 28, 14, 30, - 1, 17, 3, 19, 5, 21, 7, 23, 9, 25, 11, 27, 13, 29, 15, 31, - // level 2 - 0, 1, 16, 17, 4, 5, 20, 21, 8, 9, 24, 25, 12, 13, 28, 29, - 2, 3, 18, 19, 6, 7, 22, 23, 10, 11, 26, 27, 14, 15, 30, 31, - // level 3 - 0, 1, 2, 3, 16, 17, 18, 19, 8, 9, 10, 11, 24, 25, 26, 27, - 4, 5, 6, 7, 20, 21, 22, 23, 12, 13, 14, 15, 28, 29, 30, 31, - // level 4 - 0, 1, 2, 3, 4, 5, 6, 7, 16, 17, 18, 19, 20, 21, 22, 23, - 8, 9, 10, 11, 12, 13, 14, 15, 24, 25, 26, 27, 28, 29, 30, 31 + // Initial shuffle for AlmostInverseNtt + 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, + 17, 19, 21, 23, 25, 27, 29, 31, 1, 3, 5, 7, 9, 11, 13, 15 }; -const int montMulPermsIdx = 0; -const int nttL4PermsIdx = 64; -const int nttL5PermsIdx = 192; -const int nttL6PermsIdx = 320; -const int nttL7PermsIdx = 448; -const int nttInvL0PermsIdx = 704; -const int nttInvL1PermsIdx = 832; -const int nttInvL2PermsIdx = 960; -const int nttInvL3PermsIdx = 1088; -const int nttInvL4PermsIdx = 1216; - -static address dilithiumAvx512PermsAddr() { - return (address) dilithiumAvx512Perms; +static address unshufflePermsAddr(int offset) { + return ((address) unshufflePerms) + offset*64; } -// We do Montgomery multiplications of two vectors of 16 ints each in 4 steps: -// 1. Do the multiplications of the corresponding even numbered slots into -// the odd numbered slots of a third register. -// 2. Swap the even and odd numbered slots of the original input registers. -// 3. Similar to step 1, but into a different output register. -// 4. Combine the outputs of step 1 and step 3 into the output of the Montgomery -// multiplication. -// (For levels 0-6 in the Ntt and levels 1-7 of the inverse Ntt we only swap the -// odd-even slots of the first multiplicand as in the second (zetas) the -// odd slots contain the same number as the corresponding even one.) -// The indexes of the registers to be multiplied -// are in inputRegs1[] and inputRegs[2]. -// The results go to the registers whose indexes are in outputRegs. -// scratchRegs should contain 12 different register indexes. -// The set in outputRegs should not overlap with the set of the middle four -// scratch registers. -// The sets in inputRegs1 and inputRegs2 cannot overlap with the set of the -// first eight scratch registers. -// In most of the cases, the odd and the corresponding even slices of the -// registers indexed by the numbers in inputRegs2 will contain the same number, -// this should be indicated by calling this function with -// input2NeedsShuffle=false . +// The following function swaps elements A<->B, C<->D, and so forth. +// input1[] is shuffled in place; shuffle of input2[] is copied to output2[]. +// Element size (in bits) is specified by size parameter. +// +-----+-----+-----+-----+----- +// | | A | | C | ... +// +-----+-----+-----+-----+----- +// +-----+-----+-----+-----+----- +// | B | | D | | ... +// +-----+-----+-----+-----+----- // -static void montMul64(int outputRegs[], int inputRegs1[], int inputRegs2[], - int scratchRegs[], bool input2NeedsShuffle, - MacroAssembler *_masm) { +// NOTE: size 0 and 1 are used for initial and final shuffles respectively of +// dilithiumAlmostInverseNtt and dilithiumAlmostNtt. For size 0 and 1, input1[] +// and input2[] are modified in-place (and output2 is used as a temporary) +// +// Using C++ lambdas for improved readability (to hide parameters that always repeat) +static auto whole_shuffle(Register scratch, KRegister mergeMask1, KRegister mergeMask2, + const XMMRegister unshuffle1, const XMMRegister unshuffle2, int vector_len, MacroAssembler *_masm) { - for (int i = 0; i < 4; i++) { - __ vpmuldq(xmm(scratchRegs[i]), xmm(inputRegs1[i]), xmm(inputRegs2[i]), - Assembler::AVX_512bit); - } - for (int i = 0; i < 4; i++) { - __ vpmulld(xmm(scratchRegs[i + 4]), xmm(scratchRegs[i]), montQInvModR, - Assembler::AVX_512bit); - } - for (int i = 0; i < 4; i++) { - __ vpmuldq(xmm(scratchRegs[i + 4]), xmm(scratchRegs[i + 4]), dilithium_q, - Assembler::AVX_512bit); - } - for (int i = 0; i < 4; i++) { - __ evpsubd(xmm(scratchRegs[i + 4]), k0, xmm(scratchRegs[i]), - xmm(scratchRegs[i + 4]), false, Assembler::AVX_512bit); + int regCnt = 4; + if (vector_len == Assembler::AVX_256bit) { + regCnt = 2; } - for (int i = 0; i < 4; i++) { - __ vpshufd(xmm(inputRegs1[i]), xmm(inputRegs1[i]), 0xB1, - Assembler::AVX_512bit); - if (input2NeedsShuffle) { - __ vpshufd(xmm(inputRegs2[i]), xmm(inputRegs2[i]), 0xB1, - Assembler::AVX_512bit); + return [=](const XMMRegister output2[], const XMMRegister input1[], + const XMMRegister input2[], int size) { + if (vector_len == Assembler::AVX_256bit) { + switch (size) { + case 128: + for (int i = 0; i < regCnt; i++) { + __ vperm2i128(output2[i], input1[i], input2[i], 0b110001); + } + for (int i = 0; i < regCnt; i++) { + __ vinserti128(input1[i], input1[i], input2[i], 1); + } + break; + case 64: + for (int i = 0; i < regCnt; i++) { + __ vshufpd(output2[i], input1[i], input2[i], 0b11111111, vector_len); + } + for (int i = 0; i < regCnt; i++) { + __ vshufpd(input1[i], input1[i], input2[i], 0b00000000, vector_len); + } + break; + case 32: + for (int i = 0; i < regCnt; i++) { + __ vmovshdup(output2[i], input1[i], vector_len); + } + for (int i = 0; i < regCnt; i++) { + __ vpblendd(output2[i], output2[i], input2[i], 0b10101010, vector_len); + } + for (int i = 0; i < regCnt; i++) { + __ vmovsldup(input2[i], input2[i], vector_len); + } + for (int i = 0; i < regCnt; i++) { + __ vpblendd(input1[i], input1[i], input2[i], 0b10101010, vector_len); + } + break; + // Special cases + case 1: // initial shuffle for dilithiumAlmostInverseNtt + // shuffle all even 32bit columns to input1, and odd to input2 + for (int i = 0; i < regCnt; i++) { + // 0b-3-1-3-1 + __ vshufps(output2[i], input1[i], input2[i], 0b11011101, vector_len); + } + for (int i = 0; i < regCnt; i++) { + // 0b-2-0-2-0 + __ vshufps(input1[i], input1[i], input2[i], 0b10001000, vector_len); + } + for (int i = 0; i < regCnt; i++) { + __ vpermq(input2[i], output2[i], 0b11011000, vector_len); + } + for (int i = 0; i < regCnt; i++) { + // 0b-3-1-2-0 + __ vpermq(input1[i], input1[i], 0b11011000, vector_len); + } + break; + case 0: // final unshuffle for dilithiumAlmostNtt + // reverse case 1: all even are in input1 and odd in input2, put back + for (int i = 0; i < regCnt; i++) { + __ vpunpckhdq(output2[i], input1[i], input2[i], vector_len); + } + for (int i = 0; i < regCnt; i++) { + __ vpunpckldq(input1[i], input1[i], input2[i], vector_len); + } + for (int i = 0; i < regCnt; i++) { + __ vperm2i128(input2[i], input1[i], output2[i], 0b110001); + } + for (int i = 0; i < regCnt; i++) { + __ vinserti128(input1[i], input1[i], output2[i], 1); + } + break; + default: + assert(false, "Don't call here"); + } + } else { + switch (size) { + case 256: + for (int i = 0; i < regCnt; i++) { + // 0b-3-2-3-2 + __ evshufi64x2(output2[i], input1[i], input2[i], 0b11101110, vector_len); + } + for (int i = 0; i < regCnt; i++) { + __ vinserti64x4(input1[i], input1[i], input2[i], 1); + } + break; + case 128: + for (int i = 0; i < regCnt; i++) { + __ vmovdqu(output2[i], input2[i], vector_len); + } + for (int i = 0; i < regCnt; i++) { + __ evpermt2q(output2[i], unshuffle2, input1[i], vector_len); + } + for (int i = 0; i < regCnt; i++) { + __ evpermt2q(input1[i], unshuffle1, input2[i], vector_len); + } + + break; + case 64: + for (int i = 0; i < regCnt; i++) { + __ vshufpd(output2[i], input1[i], input2[i], 0b11111111, vector_len); + } + for (int i = 0; i < regCnt; i++) { + __ vshufpd(input1[i], input1[i], input2[i], 0b00000000, vector_len); + } + break; + case 32: + for (int i = 0; i < regCnt; i++) { + __ vmovdqu(output2[i], input2[i], vector_len); + } + for (int i = 0; i < regCnt; i++) { + __ evmovshdup(output2[i], mergeMask2, input1[i], true, vector_len); + } + for (int i = 0; i < regCnt; i++) { + __ evmovsldup(input1[i], mergeMask1, input2[i], true, vector_len); + } + break; + // Special cases + case 1: // initial shuffle for dilithiumAlmostInverseNtt + // shuffle all even 32bit columns to input1, and odd to input2 + for (int i = 0; i < regCnt; i++) { + __ vmovdqu(output2[i], input2[i], vector_len); + } + for (int i = 0; i < regCnt; i++) { + __ evpermt2d(input2[i], unshuffle2, input1[i], vector_len); + } + for (int i = 0; i < regCnt; i++) { + __ evpermt2d(input1[i], unshuffle1, output2[i], vector_len); + } + break; + case 0: // final unshuffle for dilithiumAlmostNtt + // reverse case 1: all even are in input1 and odd in input2, put back + for (int i = 0; i < regCnt; i++) { + __ vmovdqu(output2[i], input2[i], vector_len); + } + for (int i = 0; i < regCnt; i++) { + __ evpermt2d(input2[i], unshuffle2, input1[i], vector_len); + } + for (int i = 0; i < regCnt; i++) { + __ evpermt2d(input1[i], unshuffle1, output2[i], vector_len); + } + break; + default: + assert(false, "Don't call here"); + } } - } - - for (int i = 0; i < 4; i++) { - __ vpmuldq(xmm(scratchRegs[i]), xmm(inputRegs1[i]), xmm(inputRegs2[i]), - Assembler::AVX_512bit); - } - for (int i = 0; i < 4; i++) { - __ vpmulld(xmm(scratchRegs[i + 8]), xmm(scratchRegs[i]), montQInvModR, - Assembler::AVX_512bit); - } - for (int i = 0; i < 4; i++) { - __ vpmuldq(xmm(scratchRegs[i + 8]), xmm(scratchRegs[i + 8]), dilithium_q, - Assembler::AVX_512bit); - } - for (int i = 0; i < 4; i++) { - __ evpsubd(xmm(outputRegs[i]), k0, xmm(scratchRegs[i]), - xmm(scratchRegs[i + 8]), false, Assembler::AVX_512bit); - } - - for (int i = 0; i < 4; i++) { - __ evpermt2d(xmm(outputRegs[i]), montMulPerm, xmm(scratchRegs[i + 4]), - Assembler::AVX_512bit); - } + }; // return } -static void montMul64(int outputRegs[], int inputRegs1[], int inputRegs2[], - int scratchRegs[], MacroAssembler *_masm) { - montMul64(outputRegs, inputRegs1, inputRegs2, scratchRegs, false, _masm); -} - -static void sub_add(int subResult[], int addResult[], - int input1[], int input2[], MacroAssembler *_masm) { - - for (int i = 0; i < 4; i++) { - __ evpsubd(xmm(subResult[i]), k0, xmm(input1[i]), xmm(input2[i]), false, - Assembler::AVX_512bit); +// We do Montgomery multiplications of two AVX registers in 4 steps: +// 1. Do the multiplications of the corresponding even numbered slots into +// the odd numbered slots of the scratch2 register. +// 2. Swap the even and odd numbered slots of the original input registers.(*Note) +// 3. Similar to step 1, but multiplication result is placed into output register. +// 4. Combine odd/even slots respectively from the scratch2 and output registers +// into the output register for the final result of the Montgomery multiplication. +// (*Note: For levels 0-6 in the Ntt and levels 1-7 of the inverse Ntt, need NOT +// swap the second operand (zetas) since the odd slots contain the same number +// as the corresponding even one. This is indicated by input2NeedsShuffle=false) +// +// The registers to be multiplied are in input1[] and inputs2[]. The results go +// into output[]. Two scratch[] register arrays are expected. input1[] can +// overlap with either output[] or scratch1[] +// - If AVX512, all register arrays are of length 4 +// - If AVX2, first two registers of each array are in xmm0-xmm15 range +// Constants montQInvModR, dilithium_q and mergeMask expected to have already +// been loaded. +// +// Using C++ lambdas for improved readability (to hide parameters that always repeat) +static auto whole_montMul(XMMRegister montQInvModR, XMMRegister dilithium_q, + KRegister mergeMask, int vector_len, MacroAssembler *_masm) { + int regCnt = 4; + int regSize = 64; + if (vector_len == Assembler::AVX_256bit) { + regCnt = 2; + regSize = 32; } - for (int i = 0; i < 4; i++) { - __ evpaddd(xmm(addResult[i]), k0, xmm(input1[i]), xmm(input2[i]), false, - Assembler::AVX_512bit); - } -} + return [=](const XMMRegister output[], const XMMRegister input1[], + const XMMRegister input2[], const XMMRegister scratch1[], + const XMMRegister scratch2[], bool input2NeedsShuffle = false) { + // (Register overloading) Can't always use scratch1 (could override input1). + // If so, use output: + const XMMRegister* scratch = scratch1 == input1 ? output: scratch1; -static void loadPerm(int destinationRegs[], Register perms, - int offset, MacroAssembler *_masm) { - __ evmovdqul(xmm(destinationRegs[0]), Address(perms, offset), - Assembler::AVX_512bit); - for (int i = 1; i < 4; i++) { - __ evmovdqul(xmm(destinationRegs[i]), xmm(destinationRegs[0]), - Assembler::AVX_512bit); + // scratch = input1_even * intput2_even + for (int i = 0; i < regCnt; i++) { + __ vpmuldq(scratch[i], input1[i], input2[i], vector_len); } + + // scratch2_low = scratch_low * montQInvModR + for (int i = 0; i < regCnt; i++) { + __ vpmuldq(scratch2[i], scratch[i], montQInvModR, vector_len); + } + + // scratch2 = scratch2_low * dilithium_q + for (int i = 0; i < regCnt; i++) { + __ vpmuldq(scratch2[i], scratch2[i], dilithium_q, vector_len); + } + + // scratch2_high = scratch2_high - scratch_high + for (int i = 0; i < regCnt; i++) { + __ vpsubd(scratch2[i], scratch[i], scratch2[i], vector_len); + } + + // input1_even = input1_odd + // input2_even = input2_odd + for (int i = 0; i < regCnt; i++) { + __ vpshufd(input1[i], input1[i], 0xB1, vector_len); + if (input2NeedsShuffle) { + __ vpshufd(input2[i], input2[i], 0xB1, vector_len); + } + } + + // scratch1 = input1_even*intput2_even + for (int i = 0; i < regCnt; i++) { + __ vpmuldq(scratch1[i], input1[i], input2[i], vector_len); + } + + // output = scratch1_low * montQInvModR + for (int i = 0; i < regCnt; i++) { + __ vpmuldq(output[i], scratch1[i], montQInvModR, vector_len); + } + + // output = output * dilithium_q + for (int i = 0; i < regCnt; i++) { + __ vpmuldq(output[i], output[i], dilithium_q, vector_len); + } + + // output_high = scratch1_high - output_high + for (int i = 0; i < regCnt; i++) { + __ vpsubd(output[i], scratch1[i], output[i], vector_len); + } + + // output = select(output_high, scratch2_high) + if (vector_len == Assembler::AVX_256bit) { + for (int i = 0; i < regCnt; i++) { + __ vmovshdup(scratch2[i], scratch2[i], vector_len); + } + for (int i = 0; i < regCnt; i++) { + __ vpblendd(output[i], output[i], scratch2[i], 0b01010101, vector_len); + } + } else { + for (int i = 0; i < regCnt; i++) { + __ evmovshdup(output[i], mergeMask, scratch2[i], true, vector_len); + } + } + }; // return } -static void load4Xmms(int destinationRegs[], Register source, int offset, - MacroAssembler *_masm) { - for (int i = 0; i < 4; i++) { - __ evmovdqul(xmm(destinationRegs[i]), Address(source, offset + i * XMMBYTES), - Assembler::AVX_512bit); +static void sub_add(const XMMRegister subResult[], const XMMRegister addResult[], + const XMMRegister input1[], const XMMRegister input2[], + int vector_len, MacroAssembler *_masm) { + int regCnt = 4; + if (vector_len == Assembler::AVX_256bit) { + regCnt = 2; + } + + for (int i = 0; i < regCnt; i++) { + __ vpsubd(subResult[i], input1[i], input2[i], vector_len); + } + + for (int i = 0; i < regCnt; i++) { + __ vpaddd(addResult[i], input1[i], input2[i], vector_len); } } -static void loadXmm29(Register source, int offset, MacroAssembler *_masm) { - __ evmovdqul(xmm29, Address(source, offset), Assembler::AVX_512bit); -} +static void loadXmms(const XMMRegister destinationRegs[], Register source, int offset, + int vector_len, MacroAssembler *_masm, int regCnt = -1, int memStep = -1) { -static void store4Xmms(Register destination, int offset, int xmmRegs[], - MacroAssembler *_masm) { - for (int i = 0; i < 4; i++) { - __ evmovdqul(Address(destination, offset + i * XMMBYTES), xmm(xmmRegs[i]), - Assembler::AVX_512bit); + if (vector_len == Assembler::AVX_256bit) { + regCnt = regCnt == -1 ? 2 : regCnt; + memStep = memStep == -1 ? 32 : memStep; + } else { + regCnt = 4; + memStep = 64; + } + + for (int i = 0; i < regCnt; i++) { + __ vmovdqu(destinationRegs[i], Address(source, offset + i * memStep), vector_len); } } -static int xmm0_3[] = {0, 1, 2, 3}; -static int xmm0145[] = {0, 1, 4, 5}; -static int xmm0246[] = {0, 2, 4, 6}; -static int xmm0426[] = {0, 4, 2, 6}; -static int xmm1357[] = {1, 3, 5, 7}; -static int xmm1537[] = {1, 5, 3, 7}; -static int xmm2367[] = {2, 3, 6, 7}; -static int xmm4_7[] = {4, 5, 6, 7}; -static int xmm8_11[] = {8, 9, 10, 11}; -static int xmm12_15[] = {12, 13, 14, 15}; -static int xmm16_19[] = {16, 17, 18, 19}; -static int xmm20_23[] = {20, 21, 22, 23}; -static int xmm20222426[] = {20, 22, 24, 26}; -static int xmm21232527[] = {21, 23, 25, 27}; -static int xmm24_27[] = {24, 25, 26, 27}; -static int xmm4_20_24[] = {4, 5, 6, 7, 20, 21, 22, 23, 24, 25, 26, 27}; -static int xmm16_27[] = {16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27}; -static int xmm29_29[] = {29, 29, 29, 29}; +static void storeXmms(Register destination, int offset, const XMMRegister xmmRegs[], + int vector_len, MacroAssembler *_masm, int regCnt = -1, int memStep = -1) { + if (vector_len == Assembler::AVX_256bit) { + regCnt = regCnt == -1 ? 2 : regCnt; + memStep = memStep == -1 ? 32 : memStep; + } else { + regCnt = 4; + memStep = 64; + } + + for (int i = 0; i < regCnt; i++) { + __ vmovdqu(Address(destination, offset + i * memStep), xmmRegs[i], vector_len); + } +} // Dilithium NTT function except for the final "normalization" to |coeff| < Q. // Implements // static int implDilithiumAlmostNtt(int[] coeffs, int zetas[]) {} // // coeffs (int[256]) = c_rarg0 -// zetas (int[256]) = c_rarg1 +// zetas (int[128*8]) = c_rarg1 // -// -static address generate_dilithiumAlmostNtt_avx512(StubGenerator *stubgen, - MacroAssembler *_masm) { - +static address generate_dilithiumAlmostNtt_avx(StubGenerator *stubgen, + int vector_len, MacroAssembler *_masm) { __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_dilithiumAlmostNtt_id; StubCodeMark mark(stubgen, stub_id); address start = __ pc(); __ enter(); - Label L_loop, L_end; - const Register coeffs = c_rarg0; const Register zetas = c_rarg1; - const Register iterations = c_rarg2; - - const Register perms = r11; - - __ lea(perms, ExternalAddress(dilithiumAvx512PermsAddr())); - - __ evmovdqul(montMulPerm, Address(perms, montMulPermsIdx), Assembler::AVX_512bit); + const Register scratch = r10; // Each level represents one iteration of the outer for loop of the Java version // In each of these iterations half of the coefficients are (Montgomery) // multiplied by a zeta corresponding to the coefficient and then these // products will be added to and subtracted from the other half of the - // coefficients. In each level we just collect the coefficients (using - // evpermi2d() instructions where necessary, i.e. in levels 4-7) that need to + // coefficients. In each level we just shuffle the coefficients that need to // be multiplied by the zetas in one set, the rest to another set of vector // registers, then redistribute the addition/substraction results. // For levels 0 and 1 the zetas are not different within the 4 xmm registers - // that we would use for them, so we use only one, xmm29. - loadXmm29(zetas, 0, _masm); + // that we would use for them, so we use only one register. + + // AVX2 version uses the first half of these arrays + const XMMRegister Coeffs1[] = {xmm0, xmm1, xmm16, xmm17}; + const XMMRegister Coeffs2[] = {xmm2, xmm3, xmm18, xmm19}; + const XMMRegister Coeffs3[] = {xmm4, xmm5, xmm20, xmm21}; + const XMMRegister Coeffs4[] = {xmm6, xmm7, xmm22, xmm23}; + const XMMRegister Scratch1[] = {xmm8, xmm9, xmm24, xmm25}; + const XMMRegister Scratch2[] = {xmm10, xmm11, xmm26, xmm27}; + const XMMRegister Zetas1[] = {xmm12, xmm12, xmm12, xmm12}; + const XMMRegister Zetas2[] = {xmm12, xmm12, xmm13, xmm13}; + const XMMRegister Zetas3[] = {xmm12, xmm13, xmm28, xmm29}; + const XMMRegister montQInvModR = xmm14; + const XMMRegister dilithium_q = xmm15; + const XMMRegister unshuffle1 = xmm30; + const XMMRegister unshuffle2 = xmm31; + KRegister mergeMask1 = k1; + KRegister mergeMask2 = k2; + // lambdas to hide repeated parameters + auto shuffle = whole_shuffle(scratch, mergeMask1, mergeMask2, unshuffle1, unshuffle2, vector_len, _masm); + auto montMul64 = whole_montMul(montQInvModR, dilithium_q, mergeMask2, vector_len, _masm); + __ vpbroadcastd(montQInvModR, ExternalAddress(dilithiumAvx512ConstsAddr(montQInvModRIdx)), - Assembler::AVX_512bit, scratch); // q^-1 mod 2^32 + vector_len, scratch); // q^-1 mod 2^32 __ vpbroadcastd(dilithium_q, ExternalAddress(dilithiumAvx512ConstsAddr(dilithium_qIdx)), - Assembler::AVX_512bit, scratch); // q + vector_len, scratch); // q - // load all coefficients into the vector registers Zmm_0-Zmm_15, - // 16 coefficients into each - load4Xmms(xmm0_3, coeffs, 0, _masm); - load4Xmms(xmm4_7, coeffs, 4 * XMMBYTES, _masm); - load4Xmms(xmm8_11, coeffs, 8 * XMMBYTES, _masm); - load4Xmms(xmm12_15, coeffs, 12 * XMMBYTES, _masm); + if (vector_len == Assembler::AVX_512bit) { + // levels 0-3, register shuffles: + const XMMRegister Coeffs1_1[] = {xmm0, xmm1, xmm2, xmm3}; + const XMMRegister Coeffs2_1[] = {xmm16, xmm17, xmm18, xmm19}; + const XMMRegister Coeffs3_1[] = {xmm4, xmm5, xmm6, xmm7}; + const XMMRegister Coeffs4_1[] = {xmm20, xmm21, xmm22, xmm23}; + const XMMRegister Coeffs1_2[] = {xmm0, xmm16, xmm2, xmm18}; + const XMMRegister Coeffs2_2[] = {xmm1, xmm17, xmm3, xmm19}; + const XMMRegister Coeffs3_2[] = {xmm4, xmm20, xmm6, xmm22}; + const XMMRegister Coeffs4_2[] = {xmm5, xmm21, xmm7, xmm23}; - // level 0 and 1 can be done entirely in registers as the zetas on these - // levels are the same for all the montmuls that we can do in parallel + // Constants for shuffle and montMul64 + __ mov64(scratch, 0b1010101010101010); + __ kmovwl(mergeMask1, scratch); + __ knotwl(mergeMask2, mergeMask1); + __ vmovdqu(unshuffle1, ExternalAddress(unshufflePermsAddr(0)), vector_len, scratch); + __ vmovdqu(unshuffle2, ExternalAddress(unshufflePermsAddr(1)), vector_len, scratch); - // level 0 - montMul64(xmm16_19, xmm8_11, xmm29_29, xmm16_27, _masm); - sub_add(xmm8_11, xmm0_3, xmm0_3, xmm16_19, _masm); - montMul64(xmm16_19, xmm12_15, xmm29_29, xmm16_27, _masm); - loadXmm29(zetas, 512, _masm); // for level 1 - sub_add(xmm12_15, xmm4_7, xmm4_7, xmm16_19, _masm); + int memStep = 4 * 64; // 4*64-byte registers + loadXmms(Coeffs1, coeffs, 0*memStep, vector_len, _masm); + loadXmms(Coeffs2, coeffs, 1*memStep, vector_len, _masm); + loadXmms(Coeffs3, coeffs, 2*memStep, vector_len, _masm); + loadXmms(Coeffs4, coeffs, 3*memStep, vector_len, _masm); - // level 1 + // level 0-3 can be done by shuffling registers (also notice fewer zetas loads, they repeat) + // level 0 - 128 + // scratch1 = coeffs3 * zetas1 + // coeffs3, coeffs1 = coeffs1 ± scratch1 + // scratch1 = coeffs4 * zetas1 + // coeffs4, coeffs2 = coeffs2 ± scratch1 + __ vmovdqu(Zetas1[0], Address(zetas, 0), vector_len); + montMul64(Scratch1, Coeffs3, Zetas1, Coeffs3, Scratch2); + sub_add(Coeffs3, Coeffs1, Coeffs1, Scratch1, vector_len, _masm); + montMul64(Scratch1, Coeffs4, Zetas1, Coeffs4, Scratch2); + sub_add(Coeffs4, Coeffs2, Coeffs2, Scratch1, vector_len, _masm); - montMul64(xmm16_19, xmm4_7, xmm29_29, xmm16_27, _masm); - loadXmm29(zetas, 768, _masm); - sub_add(xmm4_7, xmm0_3, xmm0_3, xmm16_19, _masm); - montMul64(xmm16_19, xmm12_15, xmm29_29, xmm16_27, _masm); - sub_add(xmm12_15, xmm8_11, xmm8_11, xmm16_19, _masm); + // level 1 - 64 + __ vmovdqu(Zetas1[0], Address(zetas, 512), vector_len); + montMul64(Scratch1, Coeffs2, Zetas1, Coeffs2, Scratch2); + sub_add(Coeffs2, Coeffs1, Coeffs1, Scratch1, vector_len, _masm); - // levels 2 to 7 are done in 2 batches, by first saving half of the coefficients - // from level 1 into memory, doing all the level 2 to level 7 computations - // on the remaining half in the vector registers, saving the result to - // memory after level 7, then loading back the coefficients that we saved after - // level 1 and do the same computation with those + __ vmovdqu(Zetas1[0], Address(zetas, 4*64 + 512), vector_len); + montMul64(Scratch1, Coeffs4, Zetas1, Coeffs4, Scratch2); + sub_add(Coeffs4, Coeffs3, Coeffs3, Scratch1, vector_len, _masm); - store4Xmms(coeffs, 8 * XMMBYTES, xmm8_11, _masm); - store4Xmms(coeffs, 12 * XMMBYTES, xmm12_15, _masm); + // level 2 - 32 + __ vmovdqu(Zetas2[0], Address(zetas, 2 * 512), vector_len); + __ vmovdqu(Zetas2[2], Address(zetas, 2*64 + 2 * 512), vector_len); + montMul64(Scratch1, Coeffs2_1, Zetas2, Coeffs2_1, Scratch2); + sub_add(Coeffs2_1, Coeffs1_1, Coeffs1_1, Scratch1, vector_len, _masm); - __ movl(iterations, 2); + __ vmovdqu(Zetas2[0], Address(zetas, 4*64 + 2 * 512), vector_len); + __ vmovdqu(Zetas2[2], Address(zetas, 6*64 + 2 * 512), vector_len); + montMul64(Scratch1, Coeffs4_1, Zetas2, Coeffs4_1, Scratch2); + sub_add(Coeffs4_1, Coeffs3_1, Coeffs3_1, Scratch1, vector_len, _masm); - __ align(OptoLoopAlignment); - __ BIND(L_loop); + // level 3 - 16 + loadXmms(Zetas3, zetas, 3 * 512, vector_len, _masm); + montMul64(Scratch1, Coeffs2_2, Zetas3, Coeffs2_2, Scratch2); + sub_add(Coeffs2_2, Coeffs1_2, Coeffs1_2, Scratch1, vector_len, _masm); - __ subl(iterations, 1); + loadXmms(Zetas3, zetas, 4*64 + 3 * 512, vector_len, _masm); + montMul64(Scratch1, Coeffs4_2, Zetas3, Coeffs4_2, Scratch2); + sub_add(Coeffs4_2, Coeffs3_2, Coeffs3_2, Scratch1, vector_len, _masm); - // level 2 - load4Xmms(xmm12_15, zetas, 2 * 512, _masm); - montMul64(xmm16_19, xmm2367, xmm12_15, xmm16_27, _masm); - load4Xmms(xmm12_15, zetas, 3 * 512, _masm); // for level 3 - sub_add(xmm2367, xmm0145, xmm0145, xmm16_19, _masm); + for (int level = 4, distance = 8; level<8; level++, distance /= 2) { + // zetas = load(level * 512) + // coeffs1_2, scratch1 = shuffle(coeffs1_2, coeffs2_2) + // scratch1 = scratch1 * zetas + // coeffs2_2 = coeffs1_2 - scratch1 + // coeffs1_2 = coeffs1_2 + scratch1 + loadXmms(Zetas3, zetas, level * 512, vector_len, _masm); + shuffle(Scratch1, Coeffs1_2, Coeffs2_2, distance * 32); // Coeffs2_2 freed + montMul64(Scratch1, Scratch1, Zetas3, Coeffs2_2, Scratch2, level==7); + sub_add(Coeffs2_2, Coeffs1_2, Coeffs1_2, Scratch1, vector_len, _masm); - // level 3 + loadXmms(Zetas3, zetas, 4*64 + level * 512, vector_len, _masm); + shuffle(Scratch1, Coeffs3_2, Coeffs4_2, distance * 32); // Coeffs4_2 freed + montMul64(Scratch1, Scratch1, Zetas3, Coeffs4_2, Scratch2, level==7); + sub_add(Coeffs4_2, Coeffs3_2, Coeffs3_2, Scratch1, vector_len, _masm); + } - montMul64(xmm16_19, xmm1357, xmm12_15, xmm16_27, _masm); - sub_add(xmm1357, xmm0246, xmm0246, xmm16_19, _masm); + // Constants for final unshuffle + __ vmovdqu(unshuffle1, ExternalAddress(unshufflePermsAddr(2)), vector_len, scratch); + __ vmovdqu(unshuffle2, ExternalAddress(unshufflePermsAddr(3)), vector_len, scratch); + shuffle(Scratch1, Coeffs1_2, Coeffs2_2, 0); + shuffle(Scratch1, Coeffs3_2, Coeffs4_2, 0); - // level 4 - loadPerm(xmm16_19, perms, nttL4PermsIdx, _masm); - loadPerm(xmm12_15, perms, nttL4PermsIdx + 64, _masm); - load4Xmms(xmm24_27, zetas, 4 * 512, _masm); + storeXmms(coeffs, 0*memStep, Coeffs1, vector_len, _masm); + storeXmms(coeffs, 1*memStep, Coeffs2, vector_len, _masm); + storeXmms(coeffs, 2*memStep, Coeffs3, vector_len, _masm); + storeXmms(coeffs, 3*memStep, Coeffs4, vector_len, _masm); + } else { // Assembler::AVX_256bit + // levels 0-4, register shuffles: + const XMMRegister Coeffs1_1[] = {xmm0, xmm2}; + const XMMRegister Coeffs2_1[] = {xmm1, xmm3}; + const XMMRegister Coeffs3_1[] = {xmm4, xmm6}; + const XMMRegister Coeffs4_1[] = {xmm5, xmm7}; - for (int i = 0; i < 8; i += 2) { - __ evpermi2d(xmm(i/2 + 16), xmm(i), xmm(i + 1), Assembler::AVX_512bit); + const XMMRegister Coeffs1_2[] = {xmm0, xmm1, xmm2, xmm3}; + const XMMRegister Coeffs2_2[] = {xmm4, xmm5, xmm6, xmm7}; + + // Since we cannot fit the entire payload into registers, we process the + // input in two stages. For the first half, load 8 registers, each 32 integers + // apart. With one load, we can process level 0-2 (128-, 64- and 32-integers + // apart). For the remaining levels, load 8 registers from consecutive memory + // (16-, 8-, 4-, 2-, 1-integer apart) + // Levels 5, 6, 7 (4-, 2-, 1-integer apart) require shuffles within registers. + // On the other levels, shuffles can be done by rearranging the register order + + // Four batches of 8 registers each, 128 bytes apart + for (int i=0; i<4; i++) { + loadXmms(Coeffs1_2, coeffs, i*32 + 0*128, vector_len, _masm, 4, 128); + loadXmms(Coeffs2_2, coeffs, i*32 + 4*128, vector_len, _masm, 4, 128); + + // level 0-2 can be done by shuffling registers (also notice fewer zetas loads, they repeat) + // level 0 - 128 + __ vmovdqu(Zetas1[0], Address(zetas, 0), vector_len); + montMul64(Scratch1, Coeffs3, Zetas1, Coeffs3, Scratch2); + sub_add(Coeffs3, Coeffs1, Coeffs1, Scratch1, vector_len, _masm); + montMul64(Scratch1, Coeffs4, Zetas1, Coeffs4, Scratch2); + sub_add(Coeffs4, Coeffs2, Coeffs2, Scratch1, vector_len, _masm); + + // level 1 - 64 + __ vmovdqu(Zetas1[0], Address(zetas, 512), vector_len); + montMul64(Scratch1, Coeffs2, Zetas1, Coeffs2, Scratch2); + sub_add(Coeffs2, Coeffs1, Coeffs1, Scratch1, vector_len, _masm); + + __ vmovdqu(Zetas1[0], Address(zetas, 4*64 + 512), vector_len); + montMul64(Scratch1, Coeffs4, Zetas1, Coeffs4, Scratch2); + sub_add(Coeffs4, Coeffs3, Coeffs3, Scratch1, vector_len, _masm); + + // level 2 - 32 + loadXmms(Zetas3, zetas, 2 * 512, vector_len, _masm, 2, 128); + montMul64(Scratch1, Coeffs2_1, Zetas3, Coeffs2_1, Scratch2); + sub_add(Coeffs2_1, Coeffs1_1, Coeffs1_1, Scratch1, vector_len, _masm); + + loadXmms(Zetas3, zetas, 4*64 + 2 * 512, vector_len, _masm, 2, 128); + montMul64(Scratch1, Coeffs4_1, Zetas3, Coeffs4_1, Scratch2); + sub_add(Coeffs4_1, Coeffs3_1, Coeffs3_1, Scratch1, vector_len, _masm); + + storeXmms(coeffs, i*32 + 0*128, Coeffs1_2, vector_len, _masm, 4, 128); + storeXmms(coeffs, i*32 + 4*128, Coeffs2_2, vector_len, _masm, 4, 128); + } + + // Four batches of 8 registers, consecutive loads + for (int i=0; i<4; i++) { + loadXmms(Coeffs1_2, coeffs, i*256, vector_len, _masm, 4); + loadXmms(Coeffs2_2, coeffs, 128 + i*256, vector_len, _masm, 4); + + // level 3 - 16 + __ vmovdqu(Zetas1[0], Address(zetas, i*128 + 3 * 512), vector_len); + montMul64(Scratch1, Coeffs2, Zetas1, Coeffs2, Scratch2); + sub_add(Coeffs2, Coeffs1, Coeffs1, Scratch1, vector_len, _masm); + + __ vmovdqu(Zetas1[0], Address(zetas, i*128 + 64 + 3 * 512), vector_len); + montMul64(Scratch1, Coeffs4, Zetas1, Coeffs4, Scratch2); + sub_add(Coeffs4, Coeffs3, Coeffs3, Scratch1, vector_len, _masm); + + // level 4 - 8 + loadXmms(Zetas3, zetas, i*128 + 4 * 512, vector_len, _masm); + montMul64(Scratch1, Coeffs2_1, Zetas3, Coeffs2_1, Scratch2); + sub_add(Coeffs2_1, Coeffs1_1, Coeffs1_1, Scratch1, vector_len, _masm); + + loadXmms(Zetas3, zetas, i*128 + 64 + 4 * 512, vector_len, _masm); + montMul64(Scratch1, Coeffs4_1, Zetas3, Coeffs4_1, Scratch2); + sub_add(Coeffs4_1, Coeffs3_1, Coeffs3_1, Scratch1, vector_len, _masm); + + for (int level = 5, distance = 4; level<8; level++, distance /= 2) { + // zetas = load(level * 512) + // coeffs1_2, scratch1 = shuffle(coeffs1_2, coeffs2_2) + // scratch1 = scratch1 * zetas + // coeffs2_2 = coeffs1_2 - scratch1 + // coeffs1_2 = coeffs1_2 + scratch1 + loadXmms(Zetas3, zetas, i*128 + level * 512, vector_len, _masm); + shuffle(Scratch1, Coeffs1_1, Coeffs2_1, distance * 32); //Coeffs2_2 freed + montMul64(Scratch1, Scratch1, Zetas3, Coeffs2_1, Scratch2, level==7); + sub_add(Coeffs2_1, Coeffs1_1, Coeffs1_1, Scratch1, vector_len, _masm); + + loadXmms(Zetas3, zetas, i*128 + 64 + level * 512, vector_len, _masm); + shuffle(Scratch1, Coeffs3_1, Coeffs4_1, distance * 32); //Coeffs4_2 freed + montMul64(Scratch1, Scratch1, Zetas3, Coeffs4_1, Scratch2, level==7); + sub_add(Coeffs4_1, Coeffs3_1, Coeffs3_1, Scratch1, vector_len, _masm); + } + + shuffle(Scratch1, Coeffs1_1, Coeffs2_1, 0); + shuffle(Scratch1, Coeffs3_1, Coeffs4_1, 0); + + storeXmms(coeffs, i*256, Coeffs1_2, vector_len, _masm, 4); + storeXmms(coeffs, 128 + i*256, Coeffs2_2, vector_len, _masm, 4); + } } - for (int i = 0; i < 8; i += 2) { - __ evpermi2d(xmm(i / 2 + 12), xmm(i), xmm(i + 1), Assembler::AVX_512bit); - } - - montMul64(xmm12_15, xmm12_15, xmm24_27, xmm4_20_24, _masm); - sub_add(xmm1357, xmm0246, xmm16_19, xmm12_15, _masm); - - // level 5 - loadPerm(xmm16_19, perms, nttL5PermsIdx, _masm); - loadPerm(xmm12_15, perms, nttL5PermsIdx + 64, _masm); - load4Xmms(xmm24_27, zetas, 5 * 512, _masm); - - for (int i = 0; i < 8; i += 2) { - __ evpermi2d(xmm(i/2 + 16), xmm(i), xmm(i + 1), Assembler::AVX_512bit); - } - for (int i = 0; i < 8; i += 2) { - __ evpermi2d(xmm(i / 2 + 12), xmm(i), xmm(i + 1), Assembler::AVX_512bit); - } - - montMul64(xmm12_15, xmm12_15, xmm24_27, xmm4_20_24, _masm); - sub_add(xmm1357, xmm0246, xmm16_19, xmm12_15, _masm); - - // level 6 - loadPerm(xmm16_19, perms, nttL6PermsIdx, _masm); - loadPerm(xmm12_15, perms, nttL6PermsIdx + 64, _masm); - load4Xmms(xmm24_27, zetas, 6 * 512, _masm); - - for (int i = 0; i < 8; i += 2) { - __ evpermi2d(xmm(i/2 + 16), xmm(i), xmm(i + 1), Assembler::AVX_512bit); - } - for (int i = 0; i < 8; i += 2) { - __ evpermi2d(xmm(i / 2 + 12), xmm(i), xmm(i + 1), Assembler::AVX_512bit); - } - - montMul64(xmm12_15, xmm12_15, xmm24_27, xmm4_20_24, _masm); - sub_add(xmm1357, xmm0246, xmm16_19, xmm12_15, _masm); - - // level 7 - loadPerm(xmm16_19, perms, nttL7PermsIdx, _masm); - loadPerm(xmm12_15, perms, nttL7PermsIdx + 64, _masm); - load4Xmms(xmm24_27, zetas, 7 * 512, _masm); - - for (int i = 0; i < 8; i += 2) { - __ evpermi2d(xmm(i / 2 + 16), xmm(i), xmm(i + 1), Assembler::AVX_512bit); - } - for (int i = 0; i < 8; i += 2) { - __ evpermi2d(xmm(i / 2 + 12), xmm(i), xmm(i + 1), Assembler::AVX_512bit); - } - - montMul64(xmm12_15, xmm12_15, xmm24_27, xmm4_20_24, true, _masm); - loadPerm(xmm0246, perms, nttL7PermsIdx + 2 * XMMBYTES, _masm); - loadPerm(xmm1357, perms, nttL7PermsIdx + 3 * XMMBYTES, _masm); - sub_add(xmm21232527, xmm20222426, xmm16_19, xmm12_15, _masm); - - for (int i = 0; i < 8; i += 2) { - __ evpermi2d(xmm(i), xmm(i + 20), xmm(i + 21), Assembler::AVX_512bit); - __ evpermi2d(xmm(i + 1), xmm(i + 20), xmm(i + 21), Assembler::AVX_512bit); - } - - __ cmpl(iterations, 0); - __ jcc(Assembler::equal, L_end); - - store4Xmms(coeffs, 0, xmm0_3, _masm); - store4Xmms(coeffs, 4 * XMMBYTES, xmm4_7, _masm); - - load4Xmms(xmm0_3, coeffs, 8 * XMMBYTES, _masm); - load4Xmms(xmm4_7, coeffs, 12 * XMMBYTES, _masm); - - __ addptr(zetas, 4 * XMMBYTES); - - __ jmp(L_loop); - - __ BIND(L_end); - - store4Xmms(coeffs, 8 * XMMBYTES, xmm0_3, _masm); - store4Xmms(coeffs, 12 * XMMBYTES, xmm4_7, _masm); __ leave(); // required for proper stackwalking of RuntimeStub frame __ mov64(rax, 0); // return 0 @@ -459,173 +654,234 @@ static address generate_dilithiumAlmostNtt_avx512(StubGenerator *stubgen, // static int implDilithiumAlmostInverseNtt(int[] coeffs, int[] zetas) {} // // coeffs (int[256]) = c_rarg0 -// zetas (int[256]) = c_rarg1 -static address generate_dilithiumAlmostInverseNtt_avx512(StubGenerator *stubgen, - MacroAssembler *_masm) { - +// zetas (int[128*8]) = c_rarg1 +static address generate_dilithiumAlmostInverseNtt_avx(StubGenerator *stubgen, + int vector_len, MacroAssembler *_masm) { __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_dilithiumAlmostInverseNtt_id; StubCodeMark mark(stubgen, stub_id); address start = __ pc(); __ enter(); - Label L_loop, L_end; - const Register coeffs = c_rarg0; const Register zetas = c_rarg1; + const Register scratch = r10; - const Register iterations = c_rarg2; + // AVX2 version uses the first half of these arrays + const XMMRegister Coeffs1[] = {xmm0, xmm1, xmm16, xmm17}; + const XMMRegister Coeffs2[] = {xmm2, xmm3, xmm18, xmm19}; + const XMMRegister Coeffs3[] = {xmm4, xmm5, xmm20, xmm21}; + const XMMRegister Coeffs4[] = {xmm6, xmm7, xmm22, xmm23}; + const XMMRegister Scratch1[] = {xmm8, xmm9, xmm24, xmm25}; + const XMMRegister Scratch2[] = {xmm10, xmm11, xmm26, xmm27}; + const XMMRegister Zetas1[] = {xmm12, xmm12, xmm12, xmm12}; + const XMMRegister Zetas2[] = {xmm12, xmm12, xmm13, xmm13}; + const XMMRegister Zetas3[] = {xmm12, xmm13, xmm28, xmm29}; + const XMMRegister montQInvModR = xmm14; + const XMMRegister dilithium_q = xmm15; + const XMMRegister unshuffle1 = xmm30; + const XMMRegister unshuffle2 = xmm31; + KRegister mergeMask1 = k1; + KRegister mergeMask2 = k2; + // lambdas to hide repeated parameters + auto shuffle = whole_shuffle(scratch, mergeMask1, mergeMask2, unshuffle1, unshuffle2, vector_len, _masm); + auto montMul64 = whole_montMul(montQInvModR, dilithium_q, mergeMask2, vector_len, _masm); - const Register perms = r11; - - __ lea(perms, ExternalAddress(dilithiumAvx512PermsAddr())); - - __ evmovdqul(montMulPerm, Address(perms, montMulPermsIdx), Assembler::AVX_512bit); __ vpbroadcastd(montQInvModR, ExternalAddress(dilithiumAvx512ConstsAddr(montQInvModRIdx)), - Assembler::AVX_512bit, scratch); // q^-1 mod 2^32 + vector_len, scratch); // q^-1 mod 2^32 __ vpbroadcastd(dilithium_q, ExternalAddress(dilithiumAvx512ConstsAddr(dilithium_qIdx)), - Assembler::AVX_512bit, scratch); // q + vector_len, scratch); // q // Each level represents one iteration of the outer for loop of the // Java version. // In each of these iterations half of the coefficients are added to and // subtracted from the other half of the coefficients then the result of - // the substartion is (Montgomery) multiplied by the corresponding zetas. - // In each level we just collect the coefficients (using evpermi2d() - // instructions where necessary, i.e. on levels 0-4) so that the results of + // the subtraction is (Montgomery) multiplied by the corresponding zetas. + // In each level we just shuffle the coefficients so that the results of // the additions and subtractions go to the vector registers so that they // align with each other and the zetas. - // We do levels 0-6 in two batches, each batch entirely in the vector registers - load4Xmms(xmm0_3, coeffs, 0, _masm); - load4Xmms(xmm4_7, coeffs, 4 * XMMBYTES, _masm); + if (vector_len == Assembler::AVX_512bit) { + // levels 4-7, register shuffles: + const XMMRegister Coeffs1_1[] = {xmm0, xmm1, xmm2, xmm3}; + const XMMRegister Coeffs2_1[] = {xmm16, xmm17, xmm18, xmm19}; + const XMMRegister Coeffs3_1[] = {xmm4, xmm5, xmm6, xmm7}; + const XMMRegister Coeffs4_1[] = {xmm20, xmm21, xmm22, xmm23}; + const XMMRegister Coeffs1_2[] = {xmm0, xmm16, xmm2, xmm18}; + const XMMRegister Coeffs2_2[] = {xmm1, xmm17, xmm3, xmm19}; + const XMMRegister Coeffs3_2[] = {xmm4, xmm20, xmm6, xmm22}; + const XMMRegister Coeffs4_2[] = {xmm5, xmm21, xmm7, xmm23}; - __ movl(iterations, 2); + // Constants for shuffle and montMul64 + __ mov64(scratch, 0b1010101010101010); + __ kmovwl(mergeMask1, scratch); + __ knotwl(mergeMask2, mergeMask1); + __ vmovdqu(unshuffle1, ExternalAddress(unshufflePermsAddr(4)), vector_len, scratch); + __ vmovdqu(unshuffle2, ExternalAddress(unshufflePermsAddr(5)), vector_len, scratch); - __ align(OptoLoopAlignment); - __ BIND(L_loop); + int memStep = 4 * 64; + loadXmms(Coeffs1, coeffs, 0*memStep, vector_len, _masm); + loadXmms(Coeffs2, coeffs, 1*memStep, vector_len, _masm); + loadXmms(Coeffs3, coeffs, 2*memStep, vector_len, _masm); + loadXmms(Coeffs4, coeffs, 3*memStep, vector_len, _masm); - __ subl(iterations, 1); + shuffle(Scratch1, Coeffs1_2, Coeffs2_2, 1); + shuffle(Scratch1, Coeffs3_2, Coeffs4_2, 1); - // level 0 - loadPerm(xmm8_11, perms, nttInvL0PermsIdx, _masm); - loadPerm(xmm12_15, perms, nttInvL0PermsIdx + 64, _masm); + // Constants for shuffle(128) + __ vmovdqu(unshuffle1, ExternalAddress(unshufflePermsAddr(0)), vector_len, scratch); + __ vmovdqu(unshuffle2, ExternalAddress(unshufflePermsAddr(1)), vector_len, scratch); + for (int level = 0, distance = 1; level<4; level++, distance *= 2) { + // zetas = load(level * 512) + // coeffs1_2 = coeffs1_2 + coeffs2_2 + // scratch1 = coeffs1_2 - coeffs2_2 + // scratch1 = scratch1 * zetas + // coeffs1_2, coeffs2_2 = shuffle(coeffs1_2, scratch1) + loadXmms(Zetas3, zetas, level * 512, vector_len, _masm); + sub_add(Scratch1, Coeffs1_2, Coeffs1_2, Coeffs2_2, vector_len, _masm); // Coeffs2_2 freed + montMul64(Scratch1, Scratch1, Zetas3, Coeffs2_2, Scratch2, level==0); + shuffle(Coeffs2_2, Coeffs1_2, Scratch1, distance * 32); - for (int i = 0; i < 8; i += 2) { - __ evpermi2d(xmm(i / 2 + 8), xmm(i), xmm(i + 1), Assembler::AVX_512bit); - __ evpermi2d(xmm(i / 2 + 12), xmm(i), xmm(i + 1), Assembler::AVX_512bit); + loadXmms(Zetas3, zetas, 4*64 + level * 512, vector_len, _masm); + sub_add(Scratch1, Coeffs3_2, Coeffs3_2, Coeffs4_2, vector_len, _masm); // Coeffs4_2 freed + montMul64(Scratch1, Scratch1, Zetas3, Coeffs4_2, Scratch2, level==0); + shuffle(Coeffs4_2, Coeffs3_2, Scratch1, distance * 32); + } + + // level 4 + loadXmms(Zetas3, zetas, 4 * 512, vector_len, _masm); + sub_add(Scratch1, Coeffs1_2, Coeffs1_2, Coeffs2_2, vector_len, _masm); // Coeffs2_2 freed + montMul64(Coeffs2_2, Scratch1, Zetas3, Scratch1, Scratch2); + + loadXmms(Zetas3, zetas, 4*64 + 4 * 512, vector_len, _masm); + sub_add(Scratch1, Coeffs3_2, Coeffs3_2, Coeffs4_2, vector_len, _masm); // Coeffs4_2 freed + montMul64(Coeffs4_2, Scratch1, Zetas3, Scratch1, Scratch2); + + // level 5 + __ vmovdqu(Zetas2[0], Address(zetas, 5 * 512), vector_len); + __ vmovdqu(Zetas2[2], Address(zetas, 2*64 + 5 * 512), vector_len); + sub_add(Scratch1, Coeffs1_1, Coeffs1_1, Coeffs2_1, vector_len, _masm); // Coeffs2_1 freed + montMul64(Coeffs2_1, Scratch1, Zetas2, Scratch1, Scratch2); + + __ vmovdqu(Zetas2[0], Address(zetas, 4*64 + 5 * 512), vector_len); + __ vmovdqu(Zetas2[2], Address(zetas, 6*64 + 5 * 512), vector_len); + sub_add(Scratch1, Coeffs3_1, Coeffs3_1, Coeffs4_1, vector_len, _masm); // Coeffs4_1 freed + montMul64(Coeffs4_1, Scratch1, Zetas2, Scratch1, Scratch2); + + // level 6 + __ vmovdqu(Zetas1[0], Address(zetas, 6 * 512), vector_len); + sub_add(Scratch1, Coeffs1, Coeffs1, Coeffs2, vector_len, _masm); // Coeffs2 freed + montMul64(Coeffs2, Scratch1, Zetas1, Scratch1, Scratch2); + + __ vmovdqu(Zetas1[0], Address(zetas, 4*64 + 6 * 512), vector_len); + sub_add(Scratch1, Coeffs3, Coeffs3, Coeffs4, vector_len, _masm); // Coeffs4 freed + montMul64(Coeffs4, Scratch1, Zetas1, Scratch1, Scratch2); + + // level 7 + __ vmovdqu(Zetas1[0], Address(zetas, 7 * 512), vector_len); + sub_add(Scratch1, Coeffs1, Coeffs1, Coeffs3, vector_len, _masm); // Coeffs3 freed + montMul64(Coeffs3, Scratch1, Zetas1, Scratch1, Scratch2); + sub_add(Scratch1, Coeffs2, Coeffs2, Coeffs4, vector_len, _masm); // Coeffs4 freed + montMul64(Coeffs4, Scratch1, Zetas1, Scratch1, Scratch2); + + storeXmms(coeffs, 0*memStep, Coeffs1, vector_len, _masm); + storeXmms(coeffs, 1*memStep, Coeffs2, vector_len, _masm); + storeXmms(coeffs, 2*memStep, Coeffs3, vector_len, _masm); + storeXmms(coeffs, 3*memStep, Coeffs4, vector_len, _masm); + } else { // Assembler::AVX_256bit + // Permutations of Coeffs1, Coeffs2, Coeffs3 and Coeffs4 + const XMMRegister Coeffs1_1[] = {xmm0, xmm2}; + const XMMRegister Coeffs2_1[] = {xmm1, xmm3}; + const XMMRegister Coeffs3_1[] = {xmm4, xmm6}; + const XMMRegister Coeffs4_1[] = {xmm5, xmm7}; + + const XMMRegister Coeffs1_2[] = {xmm0, xmm1, xmm2, xmm3}; + const XMMRegister Coeffs2_2[] = {xmm4, xmm5, xmm6, xmm7}; + + // Four batches of 8 registers, consecutive loads + for (int i=0; i<4; i++) { + loadXmms(Coeffs1_2, coeffs, i*256, vector_len, _masm, 4); + loadXmms(Coeffs2_2, coeffs, 128 + i*256, vector_len, _masm, 4); + + shuffle(Scratch1, Coeffs1_1, Coeffs2_1, 1); + shuffle(Scratch1, Coeffs3_1, Coeffs4_1, 1); + + for (int level = 0, distance = 1; level <= 2; level++, distance *= 2) { + // zetas = load(level * 512) + // coeffs1_2 = coeffs1_2 + coeffs2_2 + // scratch1 = coeffs1_2 - coeffs2_2 + // scratch1 = scratch1 * zetas + // coeffs1_2, coeffs2_2 = shuffle(coeffs1_2, scratch1) + loadXmms(Zetas3, zetas, i*128 + level * 512, vector_len, _masm); + sub_add(Scratch1, Coeffs1_1, Coeffs1_1, Coeffs2_1, vector_len, _masm); // Coeffs2_1 freed + montMul64(Scratch1, Scratch1, Zetas3, Coeffs2_1, Scratch2, level==0); + shuffle(Coeffs2_1, Coeffs1_1, Scratch1, distance * 32); + + loadXmms(Zetas3, zetas, i*128 + 64 + level * 512, vector_len, _masm); + sub_add(Scratch1, Coeffs3_1, Coeffs3_1, Coeffs4_1, vector_len, _masm); // Coeffs4_1 freed + montMul64(Scratch1, Scratch1, Zetas3, Coeffs4_1, Scratch2, level==0); + shuffle(Coeffs4_1, Coeffs3_1, Scratch1, distance * 32); + } + + // level 3 + loadXmms(Zetas3, zetas, i*128 + 3 * 512, vector_len, _masm); + sub_add(Scratch1, Coeffs1_1, Coeffs1_1, Coeffs2_1, vector_len, _masm); // Coeffs2_1 freed + montMul64(Coeffs2_1, Scratch1, Zetas3, Scratch1, Scratch2); + + loadXmms(Zetas3, zetas, i*128 + 64 + 3 * 512, vector_len, _masm); + sub_add(Scratch1, Coeffs3_1, Coeffs3_1, Coeffs4_1, vector_len, _masm); // Coeffs4_1 freed + montMul64(Coeffs4_1, Scratch1, Zetas3, Scratch1, Scratch2); + + // level 4 + __ vmovdqu(Zetas1[0], Address(zetas, i*128 + 4 * 512), vector_len); + sub_add(Scratch1, Coeffs1, Coeffs1, Coeffs2, vector_len, _masm); // Coeffs2 freed + montMul64(Coeffs2, Scratch1, Zetas1, Scratch1, Scratch2); + + __ vmovdqu(Zetas1[0], Address(zetas, i*128 + 64 + 4 * 512), vector_len); + sub_add(Scratch1, Coeffs3, Coeffs3, Coeffs4, vector_len, _masm); // Coeffs4 freed + montMul64(Coeffs4, Scratch1, Zetas1, Scratch1, Scratch2); + + storeXmms(coeffs, i*256, Coeffs1_2, vector_len, _masm, 4); + storeXmms(coeffs, 128 + i*256, Coeffs2_2, vector_len, _masm, 4); + } + + // Four batches of 8 registers each, 128 bytes apart + for (int i=0; i<4; i++) { + loadXmms(Coeffs1_2, coeffs, i*32 + 0*128, vector_len, _masm, 4, 128); + loadXmms(Coeffs2_2, coeffs, i*32 + 4*128, vector_len, _masm, 4, 128); + + // level 5 + loadXmms(Zetas3, zetas, 5 * 512, vector_len, _masm, 2, 128); + sub_add(Scratch1, Coeffs1_1, Coeffs1_1, Coeffs2_1, vector_len, _masm); // Coeffs2_1 freed + montMul64(Coeffs2_1, Scratch1, Zetas3, Scratch1, Scratch2); + + loadXmms(Zetas3, zetas, 4*64 + 5 * 512, vector_len, _masm, 2, 128); + sub_add(Scratch1, Coeffs3_1, Coeffs3_1, Coeffs4_1, vector_len, _masm); // Coeffs4_1 freed + montMul64(Coeffs4_1, Scratch1, Zetas3, Scratch1, Scratch2); + + // level 6 + __ vmovdqu(Zetas1[0], Address(zetas, 6 * 512), vector_len); + sub_add(Scratch1, Coeffs1, Coeffs1, Coeffs2, vector_len, _masm); // Coeffs2 freed + montMul64(Coeffs2, Scratch1, Zetas1, Scratch1, Scratch2); + + __ vmovdqu(Zetas1[0], Address(zetas, 4*64 + 6 * 512), vector_len); + sub_add(Scratch1, Coeffs3, Coeffs3, Coeffs4, vector_len, _masm); // Coeffs4 freed + montMul64(Coeffs4, Scratch1, Zetas1, Scratch1, Scratch2); + + // level 7 + __ vmovdqu(Zetas1[0], Address(zetas, 7 * 512), vector_len); + sub_add(Scratch1, Coeffs1, Coeffs1, Coeffs3, vector_len, _masm); // Coeffs3 freed + montMul64(Coeffs3, Scratch1, Zetas1, Scratch1, Scratch2); + sub_add(Scratch1, Coeffs2, Coeffs2, Coeffs4, vector_len, _masm); // Coeffs4 freed + montMul64(Coeffs4, Scratch1, Zetas1, Scratch1, Scratch2); + + storeXmms(coeffs, i*32 + 0*128, Coeffs1_2, vector_len, _masm, 4, 128); + storeXmms(coeffs, i*32 + 4*128, Coeffs2_2, vector_len, _masm, 4, 128); + } } - load4Xmms(xmm4_7, zetas, 0, _masm); - sub_add(xmm24_27, xmm0_3, xmm8_11, xmm12_15, _masm); - montMul64(xmm4_7, xmm4_7, xmm24_27, xmm16_27, true, _masm); - - // level 1 - loadPerm(xmm8_11, perms, nttInvL1PermsIdx, _masm); - loadPerm(xmm12_15, perms, nttInvL1PermsIdx + 64, _masm); - - for (int i = 0; i < 4; i++) { - __ evpermi2d(xmm(i + 8), xmm(i), xmm(i + 4), Assembler::AVX_512bit); - __ evpermi2d(xmm(i + 12), xmm(i), xmm(i + 4), Assembler::AVX_512bit); - } - - load4Xmms(xmm4_7, zetas, 512, _masm); - sub_add(xmm24_27, xmm0_3, xmm8_11, xmm12_15, _masm); - montMul64(xmm4_7, xmm24_27, xmm4_7, xmm16_27, _masm); - - // level 2 - loadPerm(xmm8_11, perms, nttInvL2PermsIdx, _masm); - loadPerm(xmm12_15, perms, nttInvL2PermsIdx + 64, _masm); - - for (int i = 0; i < 4; i++) { - __ evpermi2d(xmm(i + 8), xmm(i), xmm(i + 4), Assembler::AVX_512bit); - __ evpermi2d(xmm(i + 12), xmm(i), xmm(i + 4), Assembler::AVX_512bit); - } - - load4Xmms(xmm4_7, zetas, 2 * 512, _masm); - sub_add(xmm24_27, xmm0_3, xmm8_11, xmm12_15, _masm); - montMul64(xmm4_7, xmm24_27, xmm4_7, xmm16_27, _masm); - - // level 3 - loadPerm(xmm8_11, perms, nttInvL3PermsIdx, _masm); - loadPerm(xmm12_15, perms, nttInvL3PermsIdx + 64, _masm); - - for (int i = 0; i < 4; i++) { - __ evpermi2d(xmm(i + 8), xmm(i), xmm(i + 4), Assembler::AVX_512bit); - __ evpermi2d(xmm(i + 12), xmm(i), xmm(i + 4), Assembler::AVX_512bit); - } - - load4Xmms(xmm4_7, zetas, 3 * 512, _masm); - sub_add(xmm24_27, xmm0_3, xmm8_11, xmm12_15, _masm); - montMul64(xmm4_7, xmm24_27, xmm4_7, xmm16_27, _masm); - - // level 4 - loadPerm(xmm8_11, perms, nttInvL4PermsIdx, _masm); - loadPerm(xmm12_15, perms, nttInvL4PermsIdx + 64, _masm); - - for (int i = 0; i < 4; i++) { - __ evpermi2d(xmm(i + 8), xmm(i), xmm(i + 4), Assembler::AVX_512bit); - __ evpermi2d(xmm(i + 12), xmm(i), xmm(i + 4), Assembler::AVX_512bit); - } - - load4Xmms(xmm4_7, zetas, 4 * 512, _masm); - sub_add(xmm24_27, xmm0_3, xmm8_11, xmm12_15, _masm); - montMul64(xmm4_7, xmm24_27, xmm4_7, xmm16_27, _masm); - - // level 5 - load4Xmms(xmm12_15, zetas, 5 * 512, _masm); - sub_add(xmm8_11, xmm0_3, xmm0426, xmm1537, _masm); - montMul64(xmm4_7, xmm8_11, xmm12_15, xmm16_27, _masm); - - // level 6 - load4Xmms(xmm12_15, zetas, 6 * 512, _masm); - sub_add(xmm8_11, xmm0_3, xmm0145, xmm2367, _masm); - montMul64(xmm4_7, xmm8_11, xmm12_15, xmm16_27, _masm); - - __ cmpl(iterations, 0); - __ jcc(Assembler::equal, L_end); - - // save the coefficients of the first batch, adjust the zetas - // and load the second batch of coefficients - store4Xmms(coeffs, 0, xmm0_3, _masm); - store4Xmms(coeffs, 4 * XMMBYTES, xmm4_7, _masm); - - __ addptr(zetas, 4 * XMMBYTES); - - load4Xmms(xmm0_3, coeffs, 8 * XMMBYTES, _masm); - load4Xmms(xmm4_7, coeffs, 12 * XMMBYTES, _masm); - - __ jmp(L_loop); - - __ BIND(L_end); - - // load the coeffs of the first batch of coefficients that were saved after - // level 6 into Zmm_8-Zmm_15 and do the last level entirely in the vector - // registers - load4Xmms(xmm8_11, coeffs, 0, _masm); - load4Xmms(xmm12_15, coeffs, 4 * XMMBYTES, _masm); - - // level 7 - - loadXmm29(zetas, 7 * 512, _masm); - - for (int i = 0; i < 8; i++) { - __ evpaddd(xmm(i + 16), k0, xmm(i), xmm(i + 8), false, Assembler::AVX_512bit); - } - - for (int i = 0; i < 8; i++) { - __ evpsubd(xmm(i), k0, xmm(i + 8), xmm(i), false, Assembler::AVX_512bit); - } - - store4Xmms(coeffs, 0, xmm16_19, _masm); - store4Xmms(coeffs, 4 * XMMBYTES, xmm20_23, _masm); - montMul64(xmm0_3, xmm0_3, xmm29_29, xmm16_27, _masm); - montMul64(xmm4_7, xmm4_7, xmm29_29, xmm16_27, _masm); - store4Xmms(coeffs, 8 * XMMBYTES, xmm0_3, _masm); - store4Xmms(coeffs, 12 * XMMBYTES, xmm4_7, _masm); - __ leave(); // required for proper stackwalking of RuntimeStub frame __ mov64(rax, 0); // return 0 __ ret(0); @@ -641,8 +897,8 @@ static address generate_dilithiumAlmostInverseNtt_avx512(StubGenerator *stubgen, // result (int[256]) = c_rarg0 // poly1 (int[256]) = c_rarg1 // poly2 (int[256]) = c_rarg2 -static address generate_dilithiumNttMult_avx512(StubGenerator *stubgen, - MacroAssembler *_masm) { +static address generate_dilithiumNttMult_avx(StubGenerator *stubgen, + int vector_len, MacroAssembler *_masm) { __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_dilithiumNttMult_id; @@ -655,40 +911,60 @@ static address generate_dilithiumNttMult_avx512(StubGenerator *stubgen, const Register result = c_rarg0; const Register poly1 = c_rarg1; const Register poly2 = c_rarg2; - - const Register perms = r10; // scratch reused after not needed any more + const Register scratch = r10; const Register len = r11; - const XMMRegister montRSquareModQ = xmm29; + const XMMRegister montQInvModR = xmm8; + const XMMRegister dilithium_q = xmm9; + + const XMMRegister Poly1[] = {xmm0, xmm1, xmm16, xmm17}; + const XMMRegister Poly2[] = {xmm2, xmm3, xmm18, xmm19}; + const XMMRegister Scratch1[] = {xmm4, xmm5, xmm20, xmm21}; + const XMMRegister Scratch2[] = {xmm6, xmm7, xmm22, xmm23}; + const XMMRegister MontRSquareModQ[] = {xmm10, xmm10, xmm10, xmm10}; + KRegister mergeMask = k1; + // lambda to hide repeated parameters + auto montMul64 = whole_montMul(montQInvModR, dilithium_q, mergeMask, vector_len, _masm); __ vpbroadcastd(montQInvModR, ExternalAddress(dilithiumAvx512ConstsAddr(montQInvModRIdx)), - Assembler::AVX_512bit, scratch); // q^-1 mod 2^32 + vector_len, scratch); // q^-1 mod 2^32 __ vpbroadcastd(dilithium_q, ExternalAddress(dilithiumAvx512ConstsAddr(dilithium_qIdx)), - Assembler::AVX_512bit, scratch); // q - __ vpbroadcastd(montRSquareModQ, + vector_len, scratch); // q + __ vpbroadcastd(MontRSquareModQ[0], ExternalAddress(dilithiumAvx512ConstsAddr(montRSquareModQIdx)), - Assembler::AVX_512bit, scratch); // 2^64 mod q + vector_len, scratch); // 2^64 mod q + if (vector_len == Assembler::AVX_512bit) { + __ mov64(scratch, 0b0101010101010101); + __ kmovwl(mergeMask, scratch); + } - __ lea(perms, ExternalAddress(dilithiumAvx512PermsAddr())); - __ evmovdqul(montMulPerm, Address(perms, montMulPermsIdx), Assembler::AVX_512bit); + // Total payload is 256*int32s. + // - memStep is number of bytes one iteration processes. + // - loopCnt is number of iterations it will take to process entire payload. + int loopCnt = 4; + int memStep = 4 * 64; + if (vector_len == Assembler::AVX_256bit) { + loopCnt = 16; + memStep = 2 * 32; + } - __ movl(len, 4); + __ movl(len, loopCnt); __ align(OptoLoopAlignment); __ BIND(L_loop); - load4Xmms(xmm4_7, poly2, 0, _masm); - load4Xmms(xmm0_3, poly1, 0, _masm); - montMul64(xmm4_7, xmm4_7, xmm29_29, xmm16_27, _masm); - montMul64(xmm0_3, xmm0_3, xmm4_7, xmm16_27, true, _masm); - store4Xmms(result, 0, xmm0_3, _masm); + loadXmms(Poly2, poly2, 0, vector_len, _masm); + loadXmms(Poly1, poly1, 0, vector_len, _masm); + montMul64(Poly2, Poly2, MontRSquareModQ, Scratch1, Scratch2); + montMul64(Poly1, Poly1, Poly2, Scratch1, Scratch2, true); + storeXmms(result, 0, Poly1, vector_len, _masm); __ subl(len, 1); - __ addptr(poly1, 4 * XMMBYTES); - __ addptr(poly2, 4 * XMMBYTES); - __ addptr(result, 4 * XMMBYTES); + __ addptr(poly1, memStep); + __ addptr(poly2, memStep); + __ addptr(result, memStep); __ cmpl(len, 0); __ jcc(Assembler::notEqual, L_loop); @@ -705,8 +981,8 @@ static address generate_dilithiumNttMult_avx512(StubGenerator *stubgen, // // coeffs (int[256]) = c_rarg0 // constant (int) = c_rarg1 -static address generate_dilithiumMontMulByConstant_avx512(StubGenerator *stubgen, - MacroAssembler *_masm) { +static address generate_dilithiumMontMulByConstant_avx(StubGenerator *stubgen, + int vector_len, MacroAssembler *_masm) { __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_dilithiumMontMulByConstant_id; @@ -718,38 +994,64 @@ static address generate_dilithiumMontMulByConstant_avx512(StubGenerator *stubgen const Register coeffs = c_rarg0; const Register rConstant = c_rarg1; - - const Register perms = c_rarg2; // not used for argument + const Register scratch = r10; const Register len = r11; - const XMMRegister constant = xmm29; + const XMMRegister montQInvModR = xmm8; + const XMMRegister dilithium_q = xmm9; - __ lea(perms, ExternalAddress(dilithiumAvx512PermsAddr())); + const XMMRegister Coeffs1[] = {xmm0, xmm1, xmm16, xmm17}; + const XMMRegister Coeffs2[] = {xmm2, xmm3, xmm18, xmm19}; + const XMMRegister Scratch1[] = {xmm4, xmm5, xmm20, xmm21}; + const XMMRegister Scratch2[] = {xmm6, xmm7, xmm22, xmm23}; + const XMMRegister Constant[] = {xmm10, xmm10, xmm10, xmm10}; + XMMRegister constant = Constant[0]; + KRegister mergeMask = k1; + // lambda to hide repeated parameters + auto montMul64 = whole_montMul(montQInvModR, dilithium_q, mergeMask, vector_len, _masm); - // the following four vector registers are used in montMul64 + // load constants for montMul64 __ vpbroadcastd(montQInvModR, ExternalAddress(dilithiumAvx512ConstsAddr(montQInvModRIdx)), - Assembler::AVX_512bit, scratch); // q^-1 mod 2^32 + vector_len, scratch); // q^-1 mod 2^32 __ vpbroadcastd(dilithium_q, ExternalAddress(dilithiumAvx512ConstsAddr(dilithium_qIdx)), - Assembler::AVX_512bit, scratch); // q - __ evmovdqul(montMulPerm, Address(perms, montMulPermsIdx), Assembler::AVX_512bit); - __ evpbroadcastd(constant, rConstant, Assembler::AVX_512bit); // constant multiplier + vector_len, scratch); // q + if (vector_len == Assembler::AVX_256bit) { + __ movdl(constant, rConstant); + __ vpbroadcastd(constant, constant, vector_len); // constant multiplier + } else { + __ evpbroadcastd(constant, rConstant, Assembler::AVX_512bit); // constant multiplier - __ movl(len, 2); + __ mov64(scratch, 0b0101010101010101); //dw-mask + __ kmovwl(mergeMask, scratch); + } + + // Total payload is 256*int32s. + // - memStep is number of bytes one montMul64 processes. + // - loopCnt is number of iterations it will take to process entire payload. + // - (two memSteps per loop) + int memStep = 4 * 64; + int loopCnt = 2; + if (vector_len == Assembler::AVX_256bit) { + memStep = 2 * 32; + loopCnt = 8; + } + + __ movl(len, loopCnt); __ align(OptoLoopAlignment); __ BIND(L_loop); - load4Xmms(xmm0_3, coeffs, 0, _masm); - load4Xmms(xmm4_7, coeffs, 4 * XMMBYTES, _masm); - montMul64(xmm0_3, xmm0_3, xmm29_29, xmm16_27, _masm); - montMul64(xmm4_7, xmm4_7, xmm29_29, xmm16_27, _masm); - store4Xmms(coeffs, 0, xmm0_3, _masm); - store4Xmms(coeffs, 4 * XMMBYTES, xmm4_7, _masm); + loadXmms(Coeffs1, coeffs, 0, vector_len, _masm); + loadXmms(Coeffs2, coeffs, memStep, vector_len, _masm); + montMul64(Coeffs1, Coeffs1, Constant, Scratch1, Scratch2); + montMul64(Coeffs2, Coeffs2, Constant, Scratch1, Scratch2); + storeXmms(coeffs, 0, Coeffs1, vector_len, _masm); + storeXmms(coeffs, memStep, Coeffs2, vector_len, _masm); __ subl(len, 1); - __ addptr(coeffs, 512); + __ addptr(coeffs, 2 * memStep); __ cmpl(len, 0); __ jcc(Assembler::notEqual, L_loop); @@ -769,9 +1071,8 @@ static address generate_dilithiumMontMulByConstant_avx512(StubGenerator *stubgen // highPart (int[256]) = c_rarg2 // twoGamma2 (int) = c_rarg3 // multiplier (int) = c_rarg4 -static address generate_dilithiumDecomposePoly_avx512(StubGenerator *stubgen, - MacroAssembler *_masm) { - +static address generate_dilithiumDecomposePoly_avx(StubGenerator *stubgen, + int vector_len, MacroAssembler *_masm) { __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_dilithiumDecomposePoly_id; StubCodeMark mark(stubgen, stub_id); @@ -785,26 +1086,45 @@ static address generate_dilithiumDecomposePoly_avx512(StubGenerator *stubgen, const Register highPart = c_rarg2; const Register rTwoGamma2 = c_rarg3; + const Register scratch = r10; const Register len = r11; - const XMMRegister zero = xmm24; - const XMMRegister one = xmm25; - const XMMRegister qMinus1 = xmm26; - const XMMRegister gamma2 = xmm27; - const XMMRegister twoGamma2 = xmm28; - const XMMRegister barrettMultiplier = xmm29; - const XMMRegister barrettAddend = xmm30; - __ vpxor(zero, zero, zero, Assembler::AVX_512bit); // 0 - __ vpternlogd(xmm0, 0xff, xmm0, xmm0, Assembler::AVX_512bit); // -1 - __ vpsubd(one, zero, xmm0, Assembler::AVX_512bit); // 1 + const XMMRegister one = xmm0; + const XMMRegister gamma2 = xmm1; + const XMMRegister twoGamma2 = xmm2; + const XMMRegister barrettMultiplier = xmm3; + const XMMRegister barrettAddend = xmm4; + const XMMRegister dilithium_q = xmm5; + const XMMRegister zero = xmm29; // AVX512-only + const XMMRegister minusOne = xmm30; // AVX512-only + const XMMRegister qMinus1 = xmm31; // AVX512-only + + XMMRegister RPlus[] = {xmm6, xmm7, xmm16, xmm17}; + XMMRegister Quotient[] = {xmm8, xmm9, xmm18, xmm19}; + XMMRegister R0[] = {xmm10, xmm11, xmm20, xmm21}; + XMMRegister Mask[] = {xmm12, xmm13, xmm22, xmm23}; + XMMRegister Tmp1[] = {xmm14, xmm15, xmm24, xmm25}; + __ vpbroadcastd(dilithium_q, ExternalAddress(dilithiumAvx512ConstsAddr(dilithium_qIdx)), - Assembler::AVX_512bit, scratch); // q + vector_len, scratch); // q __ vpbroadcastd(barrettAddend, ExternalAddress(dilithiumAvx512ConstsAddr(barrettAddendIdx)), - Assembler::AVX_512bit, scratch); // addend for Barrett reduction + vector_len, scratch); // addend for Barrett reduction + if (vector_len == Assembler::AVX_512bit) { + __ vpxor(zero, zero, zero, vector_len); // 0 + __ vpternlogd(minusOne, 0xff, minusOne, minusOne, vector_len); // -1 + __ vpsrld(one, minusOne, 31, vector_len); + __ vpsubd(qMinus1, dilithium_q, one, vector_len); // q - 1 + __ evpbroadcastd(twoGamma2, rTwoGamma2, vector_len); // 2 * gamma2 + } else { + __ vpcmpeqd(one, one, one, vector_len); + __ vpsrld(one, one, 31, vector_len); + __ movdl(twoGamma2, rTwoGamma2); + __ vpbroadcastd(twoGamma2, twoGamma2, vector_len); // 2 * gamma2 + } - __ evpbroadcastd(twoGamma2, rTwoGamma2, Assembler::AVX_512bit); // 2 * gamma2 + __ vpsrad(gamma2, twoGamma2, 1, vector_len); // gamma2 #ifndef _WIN64 const Register rMultiplier = c_rarg4; @@ -813,201 +1133,185 @@ static address generate_dilithiumDecomposePoly_avx512(StubGenerator *stubgen, const Register rMultiplier = c_rarg3; // arg3 is already consumed, reused here __ movptr(rMultiplier, multiplier_mem); #endif - __ evpbroadcastd(barrettMultiplier, rMultiplier, - Assembler::AVX_512bit); // multiplier for mod 2 * gamma2 reduce + if (vector_len == Assembler::AVX_512bit) { + __ evpbroadcastd(barrettMultiplier, rMultiplier, + vector_len); // multiplier for mod 2 * gamma2 reduce + } else { + __ movdl(barrettMultiplier, rMultiplier); + __ vpbroadcastd(barrettMultiplier, barrettMultiplier, vector_len); + } - __ evpsubd(qMinus1, k0, dilithium_q, one, false, Assembler::AVX_512bit); // q - 1 - __ evpsrad(gamma2, k0, twoGamma2, 1, false, Assembler::AVX_512bit); // gamma2 + // Total payload is 1024 bytes + int memStep = 4 * 64; // Number of bytes per loop iteration + int regCnt = 4; // Register array length + if (vector_len == Assembler::AVX_256bit) { + memStep = 2 * 32; + regCnt = 2; + } __ movl(len, 1024); __ align(OptoLoopAlignment); __ BIND(L_loop); - load4Xmms(xmm0_3, input, 0, _masm); + loadXmms(RPlus, input, 0, vector_len, _masm); - __ addptr(input, 4 * XMMBYTES); + __ addptr(input, memStep); - // rplus in xmm0 // rplus = rplus - ((rplus + 5373807) >> 23) * dilithium_q; - __ evpaddd(xmm4, k0, xmm0, barrettAddend, false, Assembler::AVX_512bit); - __ evpaddd(xmm5, k0, xmm1, barrettAddend, false, Assembler::AVX_512bit); - __ evpaddd(xmm6, k0, xmm2, barrettAddend, false, Assembler::AVX_512bit); - __ evpaddd(xmm7, k0, xmm3, barrettAddend, false, Assembler::AVX_512bit); + for (int i = 0; i < regCnt; i++) { + __ vpaddd(Tmp1[i], RPlus[i], barrettAddend, vector_len); + } - __ evpsrad(xmm4, k0, xmm4, 23, false, Assembler::AVX_512bit); - __ evpsrad(xmm5, k0, xmm5, 23, false, Assembler::AVX_512bit); - __ evpsrad(xmm6, k0, xmm6, 23, false, Assembler::AVX_512bit); - __ evpsrad(xmm7, k0, xmm7, 23, false, Assembler::AVX_512bit); + for (int i = 0; i < regCnt; i++) { + __ vpsrad(Tmp1[i], Tmp1[i], 23, vector_len); + } - __ evpmulld(xmm4, k0, xmm4, dilithium_q, false, Assembler::AVX_512bit); - __ evpmulld(xmm5, k0, xmm5, dilithium_q, false, Assembler::AVX_512bit); - __ evpmulld(xmm6, k0, xmm6, dilithium_q, false, Assembler::AVX_512bit); - __ evpmulld(xmm7, k0, xmm7, dilithium_q, false, Assembler::AVX_512bit); + for (int i = 0; i < regCnt; i++) { + __ vpmulld(Tmp1[i], Tmp1[i], dilithium_q, vector_len); + } + + for (int i = 0; i < regCnt; i++) { + __ vpsubd(RPlus[i], RPlus[i], Tmp1[i], vector_len); + } - __ evpsubd(xmm0, k0, xmm0, xmm4, false, Assembler::AVX_512bit); - __ evpsubd(xmm1, k0, xmm1, xmm5, false, Assembler::AVX_512bit); - __ evpsubd(xmm2, k0, xmm2, xmm6, false, Assembler::AVX_512bit); - __ evpsubd(xmm3, k0, xmm3, xmm7, false, Assembler::AVX_512bit); - // rplus in xmm0 // rplus = rplus + ((rplus >> 31) & dilithium_q); - __ evpsrad(xmm4, k0, xmm0, 31, false, Assembler::AVX_512bit); - __ evpsrad(xmm5, k0, xmm1, 31, false, Assembler::AVX_512bit); - __ evpsrad(xmm6, k0, xmm2, 31, false, Assembler::AVX_512bit); - __ evpsrad(xmm7, k0, xmm3, 31, false, Assembler::AVX_512bit); + for (int i = 0; i < regCnt; i++) { + __ vpsrad(Tmp1[i], RPlus[i], 31, vector_len); + } - __ evpandd(xmm4, k0, xmm4, dilithium_q, false, Assembler::AVX_512bit); - __ evpandd(xmm5, k0, xmm5, dilithium_q, false, Assembler::AVX_512bit); - __ evpandd(xmm6, k0, xmm6, dilithium_q, false, Assembler::AVX_512bit); - __ evpandd(xmm7, k0, xmm7, dilithium_q, false, Assembler::AVX_512bit); + for (int i = 0; i < regCnt; i++) { + __ vpand(Tmp1[i], Tmp1[i], dilithium_q, vector_len); + } + + for (int i = 0; i < regCnt; i++) { + __ vpaddd(RPlus[i], RPlus[i], Tmp1[i], vector_len); + } - __ evpaddd(xmm0, k0, xmm0, xmm4, false, Assembler::AVX_512bit); - __ evpaddd(xmm1, k0, xmm1, xmm5, false, Assembler::AVX_512bit); - __ evpaddd(xmm2, k0, xmm2, xmm6, false, Assembler::AVX_512bit); - __ evpaddd(xmm3, k0, xmm3, xmm7, false, Assembler::AVX_512bit); - // rplus in xmm0 // int quotient = (rplus * barrettMultiplier) >> 22; - __ evpmulld(xmm4, k0, xmm0, barrettMultiplier, false, Assembler::AVX_512bit); - __ evpmulld(xmm5, k0, xmm1, barrettMultiplier, false, Assembler::AVX_512bit); - __ evpmulld(xmm6, k0, xmm2, barrettMultiplier, false, Assembler::AVX_512bit); - __ evpmulld(xmm7, k0, xmm3, barrettMultiplier, false, Assembler::AVX_512bit); + for (int i = 0; i < regCnt; i++) { + __ vpmulld(Quotient[i], RPlus[i], barrettMultiplier, vector_len); + } + + for (int i = 0; i < regCnt; i++) { + __ vpsrad(Quotient[i], Quotient[i], 22, vector_len); + } - __ evpsrad(xmm4, k0, xmm4, 22, false, Assembler::AVX_512bit); - __ evpsrad(xmm5, k0, xmm5, 22, false, Assembler::AVX_512bit); - __ evpsrad(xmm6, k0, xmm6, 22, false, Assembler::AVX_512bit); - __ evpsrad(xmm7, k0, xmm7, 22, false, Assembler::AVX_512bit); - // quotient in xmm4 // int r0 = rplus - quotient * twoGamma2; - __ evpmulld(xmm8, k0, xmm4, twoGamma2, false, Assembler::AVX_512bit); - __ evpmulld(xmm9, k0, xmm5, twoGamma2, false, Assembler::AVX_512bit); - __ evpmulld(xmm10, k0, xmm6, twoGamma2, false, Assembler::AVX_512bit); - __ evpmulld(xmm11, k0, xmm7, twoGamma2, false, Assembler::AVX_512bit); + for (int i = 0; i < regCnt; i++) { + __ vpmulld(R0[i], Quotient[i], twoGamma2, vector_len); + } + + for (int i = 0; i < regCnt; i++) { + __ vpsubd(R0[i], RPlus[i], R0[i], vector_len); + } - __ evpsubd(xmm8, k0, xmm0, xmm8, false, Assembler::AVX_512bit); - __ evpsubd(xmm9, k0, xmm1, xmm9, false, Assembler::AVX_512bit); - __ evpsubd(xmm10, k0, xmm2, xmm10, false, Assembler::AVX_512bit); - __ evpsubd(xmm11, k0, xmm3, xmm11, false, Assembler::AVX_512bit); - // r0 in xmm8 // int mask = (twoGamma2 - r0) >> 22; - __ evpsubd(xmm12, k0, twoGamma2, xmm8, false, Assembler::AVX_512bit); - __ evpsubd(xmm13, k0, twoGamma2, xmm9, false, Assembler::AVX_512bit); - __ evpsubd(xmm14, k0, twoGamma2, xmm10, false, Assembler::AVX_512bit); - __ evpsubd(xmm15, k0, twoGamma2, xmm11, false, Assembler::AVX_512bit); + for (int i = 0; i < regCnt; i++) { + __ vpsubd(Mask[i], twoGamma2, R0[i], vector_len); + } + + for (int i = 0; i < regCnt; i++) { + __ vpsrad(Mask[i], Mask[i], 22, vector_len); + } - __ evpsrad(xmm12, k0, xmm12, 22, false, Assembler::AVX_512bit); - __ evpsrad(xmm13, k0, xmm13, 22, false, Assembler::AVX_512bit); - __ evpsrad(xmm14, k0, xmm14, 22, false, Assembler::AVX_512bit); - __ evpsrad(xmm15, k0, xmm15, 22, false, Assembler::AVX_512bit); - // mask in xmm12 // r0 -= (mask & twoGamma2); - __ evpandd(xmm16, k0, xmm12, twoGamma2, false, Assembler::AVX_512bit); - __ evpandd(xmm17, k0, xmm13, twoGamma2, false, Assembler::AVX_512bit); - __ evpandd(xmm18, k0, xmm14, twoGamma2, false, Assembler::AVX_512bit); - __ evpandd(xmm19, k0, xmm15, twoGamma2, false, Assembler::AVX_512bit); + for (int i = 0; i < regCnt; i++) { + __ vpand(Tmp1[i], Mask[i], twoGamma2, vector_len); + } + + for (int i = 0; i < regCnt; i++) { + __ vpsubd(R0[i], R0[i], Tmp1[i], vector_len); + } - __ evpsubd(xmm8, k0, xmm8, xmm16, false, Assembler::AVX_512bit); - __ evpsubd(xmm9, k0, xmm9, xmm17, false, Assembler::AVX_512bit); - __ evpsubd(xmm10, k0, xmm10, xmm18, false, Assembler::AVX_512bit); - __ evpsubd(xmm11, k0, xmm11, xmm19, false, Assembler::AVX_512bit); - // r0 in xmm8 // quotient += (mask & 1); - __ evpandd(xmm16, k0, xmm12, one, false, Assembler::AVX_512bit); - __ evpandd(xmm17, k0, xmm13, one, false, Assembler::AVX_512bit); - __ evpandd(xmm18, k0, xmm14, one, false, Assembler::AVX_512bit); - __ evpandd(xmm19, k0, xmm15, one, false, Assembler::AVX_512bit); + for (int i = 0; i < regCnt; i++) { + __ vpand(Tmp1[i], Mask[i], one, vector_len); + } - __ evpaddd(xmm4, k0, xmm4, xmm16, false, Assembler::AVX_512bit); - __ evpaddd(xmm5, k0, xmm5, xmm17, false, Assembler::AVX_512bit); - __ evpaddd(xmm6, k0, xmm6, xmm18, false, Assembler::AVX_512bit); - __ evpaddd(xmm7, k0, xmm7, xmm19, false, Assembler::AVX_512bit); + for (int i = 0; i < regCnt; i++) { + __ vpaddd(Quotient[i], Quotient[i], Tmp1[i], vector_len); + } // mask = (twoGamma2 / 2 - r0) >> 31; - __ evpsubd(xmm12, k0, gamma2, xmm8, false, Assembler::AVX_512bit); - __ evpsubd(xmm13, k0, gamma2, xmm9, false, Assembler::AVX_512bit); - __ evpsubd(xmm14, k0, gamma2, xmm10, false, Assembler::AVX_512bit); - __ evpsubd(xmm15, k0, gamma2, xmm11, false, Assembler::AVX_512bit); + for (int i = 0; i < regCnt; i++) { + __ vpsubd(Mask[i], gamma2, R0[i], vector_len); + } - __ evpsrad(xmm12, k0, xmm12, 31, false, Assembler::AVX_512bit); - __ evpsrad(xmm13, k0, xmm13, 31, false, Assembler::AVX_512bit); - __ evpsrad(xmm14, k0, xmm14, 31, false, Assembler::AVX_512bit); - __ evpsrad(xmm15, k0, xmm15, 31, false, Assembler::AVX_512bit); + for (int i = 0; i < regCnt; i++) { + __ vpsrad(Mask[i], Mask[i], 31, vector_len); + } // r0 -= (mask & twoGamma2); - __ evpandd(xmm16, k0, xmm12, twoGamma2, false, Assembler::AVX_512bit); - __ evpandd(xmm17, k0, xmm13, twoGamma2, false, Assembler::AVX_512bit); - __ evpandd(xmm18, k0, xmm14, twoGamma2, false, Assembler::AVX_512bit); - __ evpandd(xmm19, k0, xmm15, twoGamma2, false, Assembler::AVX_512bit); + for (int i = 0; i < regCnt; i++) { + __ vpand(Tmp1[i], Mask[i], twoGamma2, vector_len); + } + + for (int i = 0; i < regCnt; i++) { + __ vpsubd(R0[i], R0[i], Tmp1[i], vector_len); + } - __ evpsubd(xmm8, k0, xmm8, xmm16, false, Assembler::AVX_512bit); - __ evpsubd(xmm9, k0, xmm9, xmm17, false, Assembler::AVX_512bit); - __ evpsubd(xmm10, k0, xmm10, xmm18, false, Assembler::AVX_512bit); - __ evpsubd(xmm11, k0, xmm11, xmm19, false, Assembler::AVX_512bit); - // r0 in xmm8 // quotient += (mask & 1); - __ evpandd(xmm16, k0, xmm12, one, false, Assembler::AVX_512bit); - __ evpandd(xmm17, k0, xmm13, one, false, Assembler::AVX_512bit); - __ evpandd(xmm18, k0, xmm14, one, false, Assembler::AVX_512bit); - __ evpandd(xmm19, k0, xmm15, one, false, Assembler::AVX_512bit); + for (int i = 0; i < regCnt; i++) { + __ vpand(Tmp1[i], Mask[i], one, vector_len); + } - __ evpaddd(xmm4, k0, xmm4, xmm16, false, Assembler::AVX_512bit); - __ evpaddd(xmm5, k0, xmm5, xmm17, false, Assembler::AVX_512bit); - __ evpaddd(xmm6, k0, xmm6, xmm18, false, Assembler::AVX_512bit); - __ evpaddd(xmm7, k0, xmm7, xmm19, false, Assembler::AVX_512bit); - // quotient in xmm4 + for (int i = 0; i < regCnt; i++) { + __ vpaddd(Quotient[i], Quotient[i], Tmp1[i], vector_len); + } + // r1 in RPlus // int r1 = rplus - r0 - (dilithium_q - 1); - __ evpsubd(xmm16, k0, xmm0, xmm8, false, Assembler::AVX_512bit); - __ evpsubd(xmm17, k0, xmm1, xmm9, false, Assembler::AVX_512bit); - __ evpsubd(xmm18, k0, xmm2, xmm10, false, Assembler::AVX_512bit); - __ evpsubd(xmm19, k0, xmm3, xmm11, false, Assembler::AVX_512bit); - - __ evpsubd(xmm16, k0, xmm16, xmm26, false, Assembler::AVX_512bit); - __ evpsubd(xmm17, k0, xmm17, xmm26, false, Assembler::AVX_512bit); - __ evpsubd(xmm18, k0, xmm18, xmm26, false, Assembler::AVX_512bit); - __ evpsubd(xmm19, k0, xmm19, xmm26, false, Assembler::AVX_512bit); - // r1 in xmm16 // r1 = (r1 | (-r1)) >> 31; // 0 if rplus - r0 == (dilithium_q - 1), -1 otherwise - __ evpsubd(xmm20, k0, zero, xmm16, false, Assembler::AVX_512bit); - __ evpsubd(xmm21, k0, zero, xmm17, false, Assembler::AVX_512bit); - __ evpsubd(xmm22, k0, zero, xmm18, false, Assembler::AVX_512bit); - __ evpsubd(xmm23, k0, zero, xmm19, false, Assembler::AVX_512bit); + for (int i = 0; i < regCnt; i++) { + __ vpsubd(RPlus[i], RPlus[i], R0[i], vector_len); + } - __ evporq(xmm16, k0, xmm16, xmm20, false, Assembler::AVX_512bit); - __ evporq(xmm17, k0, xmm17, xmm21, false, Assembler::AVX_512bit); - __ evporq(xmm18, k0, xmm18, xmm22, false, Assembler::AVX_512bit); - __ evporq(xmm19, k0, xmm19, xmm23, false, Assembler::AVX_512bit); + if (vector_len == Assembler::AVX_512bit) { + KRegister EqMsk[] = {k1, k2, k3, k4}; + for (int i = 0; i < regCnt; i++) { + __ evpcmpeqd(EqMsk[i], k0, RPlus[i], qMinus1, vector_len); + } - __ evpsubd(xmm12, k0, zero, one, false, Assembler::AVX_512bit); // -1 + // r0 += ~r1; // add -1 or keep as is, using EqMsk as filter + for (int i = 0; i < regCnt; i++) { + __ evpaddd(R0[i], EqMsk[i], R0[i], minusOne, true, vector_len); + } - __ evpsrad(xmm0, k0, xmm16, 31, false, Assembler::AVX_512bit); - __ evpsrad(xmm1, k0, xmm17, 31, false, Assembler::AVX_512bit); - __ evpsrad(xmm2, k0, xmm18, 31, false, Assembler::AVX_512bit); - __ evpsrad(xmm3, k0, xmm19, 31, false, Assembler::AVX_512bit); - // r1 in xmm0 - // r0 += ~r1; - __ evpxorq(xmm20, k0, xmm0, xmm12, false, Assembler::AVX_512bit); - __ evpxorq(xmm21, k0, xmm1, xmm12, false, Assembler::AVX_512bit); - __ evpxorq(xmm22, k0, xmm2, xmm12, false, Assembler::AVX_512bit); - __ evpxorq(xmm23, k0, xmm3, xmm12, false, Assembler::AVX_512bit); + // r1 in Quotient + // r1 = r1 & quotient; // copy 0 or keep as is, using EqMsk as filter + for (int i = 0; i < regCnt; i++) { + __ evpandd(Quotient[i], EqMsk[i], Quotient[i], zero, true, vector_len); + } + } else { + const XMMRegister qMinus1 = Tmp1[0]; + __ vpsubd(qMinus1, dilithium_q, one, vector_len); // q - 1 - __ evpaddd(xmm8, k0, xmm8, xmm20, false, Assembler::AVX_512bit); - __ evpaddd(xmm9, k0, xmm9, xmm21, false, Assembler::AVX_512bit); - __ evpaddd(xmm10, k0, xmm10, xmm22, false, Assembler::AVX_512bit); - __ evpaddd(xmm11, k0, xmm11, xmm23, false, Assembler::AVX_512bit); - // r0 in xmm8 - // r1 = r1 & quotient; - __ evpandd(xmm0, k0, xmm4, xmm0, false, Assembler::AVX_512bit); - __ evpandd(xmm1, k0, xmm5, xmm1, false, Assembler::AVX_512bit); - __ evpandd(xmm2, k0, xmm6, xmm2, false, Assembler::AVX_512bit); - __ evpandd(xmm3, k0, xmm7, xmm3, false, Assembler::AVX_512bit); - // r1 in xmm0 + for (int i = 0; i < regCnt; i++) { + __ vpcmpeqd(Mask[i], RPlus[i], qMinus1, vector_len); + } + + // r0 += ~r1; + // Mask already negated + for (int i = 0; i < regCnt; i++) { + __ vpaddd(R0[i], R0[i], Mask[i], vector_len); + } + + // r1 in Quotient + // r1 = r1 & quotient; + for (int i = 0; i < regCnt; i++) { + __ vpandn(Quotient[i], Mask[i], Quotient[i], vector_len); + } + } + + // r1 in Quotient // lowPart[m] = r0; // highPart[m] = r1; - store4Xmms(highPart, 0, xmm0_3, _masm); - store4Xmms(lowPart, 0, xmm8_11, _masm); + storeXmms(highPart, 0, Quotient, vector_len, _masm); + storeXmms(lowPart, 0, R0, vector_len, _masm); - __ addptr(highPart, 4 * XMMBYTES); - __ addptr(lowPart, 4 * XMMBYTES); - __ subl(len, 4 * XMMBYTES); + __ addptr(highPart, memStep); + __ addptr(lowPart, memStep); + __ subl(len, memStep); __ jcc(Assembler::notEqual, L_loop); __ leave(); // required for proper stackwalking of RuntimeStub frame @@ -1018,17 +1322,21 @@ static address generate_dilithiumDecomposePoly_avx512(StubGenerator *stubgen, } void StubGenerator::generate_dilithium_stubs() { + int vector_len = Assembler::AVX_256bit; + if (VM_Version::supports_evex() && VM_Version::supports_avx512bw()) { + vector_len = Assembler::AVX_512bit; + } // Generate Dilithium intrinsics code if (UseDilithiumIntrinsics) { - StubRoutines::_dilithiumAlmostNtt = - generate_dilithiumAlmostNtt_avx512(this, _masm); - StubRoutines::_dilithiumAlmostInverseNtt = - generate_dilithiumAlmostInverseNtt_avx512(this, _masm); - StubRoutines::_dilithiumNttMult = - generate_dilithiumNttMult_avx512(this, _masm); - StubRoutines::_dilithiumMontMulByConstant = - generate_dilithiumMontMulByConstant_avx512(this, _masm); - StubRoutines::_dilithiumDecomposePoly = - generate_dilithiumDecomposePoly_avx512(this, _masm); + StubRoutines::_dilithiumAlmostNtt = + generate_dilithiumAlmostNtt_avx(this, vector_len, _masm); + StubRoutines::_dilithiumAlmostInverseNtt = + generate_dilithiumAlmostInverseNtt_avx(this, vector_len, _masm); + StubRoutines::_dilithiumNttMult = + generate_dilithiumNttMult_avx(this, vector_len, _masm); + StubRoutines::_dilithiumMontMulByConstant = + generate_dilithiumMontMulByConstant_avx(this, vector_len, _masm); + StubRoutines::_dilithiumDecomposePoly = + generate_dilithiumDecomposePoly_avx(this, vector_len, _masm); } } diff --git a/src/hotspot/cpu/x86/vm_version_x86.cpp b/src/hotspot/cpu/x86/vm_version_x86.cpp index 4961aed61c3..747daefd51d 100644 --- a/src/hotspot/cpu/x86/vm_version_x86.cpp +++ b/src/hotspot/cpu/x86/vm_version_x86.cpp @@ -1271,8 +1271,7 @@ void VM_Version::get_processor_features() { } // Dilithium Intrinsics - // Currently we only have them for AVX512 - if (supports_evex() && supports_avx512bw()) { + if (UseAVX > 1) { if (FLAG_IS_DEFAULT(UseDilithiumIntrinsics)) { UseDilithiumIntrinsics = true; } diff --git a/test/jdk/sun/security/provider/acvp/ML_DSA_Intrinsic_Test.java b/test/jdk/sun/security/provider/acvp/ML_DSA_Intrinsic_Test.java new file mode 100644 index 00000000000..60c0804891d --- /dev/null +++ b/test/jdk/sun/security/provider/acvp/ML_DSA_Intrinsic_Test.java @@ -0,0 +1,516 @@ +/* + * Copyright (c) 2025, Intel Corporation. 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.util.Arrays; +import java.util.Random; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.reflect.Method; +import java.util.HexFormat; + +/* + * @test + * @library /test/lib + * @key randomness + * @modules java.base/sun.security.provider:+open + * @run main/othervm ML_DSA_Intrinsic_Test -XX:+UnlockDiagnosticVMOptions -XX:-UseDilithiumIntrinsics + */ +/* + * @test + * @library /test/lib + * @key randomness + * @modules java.base/sun.security.provider:+open + * @run main/othervm -XX:UseAVX=2 ML_DSA_Intrinsic_Test + */ +/* + * @test + * @library /test/lib + * @key randomness + * @modules java.base/sun.security.provider:+open + * @run main ML_DSA_Intrinsic_Test + */ + +// To run manually: java --add-opens java.base/sun.security.provider=ALL-UNNAMED --add-exports java.base/sun.security.provider=ALL-UNNAMED +// -XX:+UnlockDiagnosticVMOptions -XX:+UseDilithiumIntrinsics test/jdk/sun/security/provider/acvp/ML_DSA_Intrinsic_Test.java + +public class ML_DSA_Intrinsic_Test { + public static void main(String[] args) throws Exception { + MethodHandles.Lookup lookup = MethodHandles.lookup(); + Class kClazz = sun.security.provider.ML_DSA.class; + + Method m = kClazz.getDeclaredMethod("implDilithiumNttMult", + int[].class, int[].class, int[].class); + m.setAccessible(true); + MethodHandle mult = lookup.unreflect(m); + + m = kClazz.getDeclaredMethod("implDilithiumNttMultJava", + int[].class, int[].class, int[].class); + m.setAccessible(true); + MethodHandle multJava = lookup.unreflect(m); + + m = kClazz.getDeclaredMethod("implDilithiumMontMulByConstant", + int[].class, int.class); + m.setAccessible(true); + MethodHandle multConst = lookup.unreflect(m); + + m = kClazz.getDeclaredMethod("implDilithiumMontMulByConstantJava", + int[].class, int.class); + m.setAccessible(true); + MethodHandle multConstJava = lookup.unreflect(m); + + m = kClazz.getDeclaredMethod("implDilithiumDecomposePoly", + int[].class, int[].class, int[].class, int.class, int.class); + m.setAccessible(true); + MethodHandle decompose = lookup.unreflect(m); + + m = kClazz.getDeclaredMethod("decomposePolyJava", + int[].class, int[].class, int[].class, int.class, int.class); + m.setAccessible(true); + MethodHandle decomposeJava = lookup.unreflect(m); + + m = kClazz.getDeclaredMethod("implDilithiumAlmostNtt", + int[].class, int[].class); + m.setAccessible(true); + MethodHandle almostNtt = lookup.unreflect(m); + + m = kClazz.getDeclaredMethod("implDilithiumAlmostNttJava", + int[].class); + m.setAccessible(true); + MethodHandle almostNttJava = lookup.unreflect(m); + + m = kClazz.getDeclaredMethod("implDilithiumAlmostInverseNtt", + int[].class, int[].class); + m.setAccessible(true); + MethodHandle inverseNtt = lookup.unreflect(m); + + m = kClazz.getDeclaredMethod("implDilithiumAlmostInverseNttJava", + int[].class); + m.setAccessible(true); + MethodHandle inverseNttJava = lookup.unreflect(m); + + // Hint: if test fails, you can hardcode the seed to make the test more reproducible + Random rnd = new Random(); + long seed = rnd.nextLong(); + rnd.setSeed(seed); + //Note: it might be useful to increase this number during development of new intrinsics + final int repeat = 10000000; + int[] coeffs1 = new int[ML_DSA_N]; + int[] coeffs2 = new int[ML_DSA_N]; + int[] prod1 = new int[ML_DSA_N]; + int[] prod2 = new int[ML_DSA_N]; + int[] prod3 = new int[ML_DSA_N]; + int[] prod4 = new int[ML_DSA_N]; + try { + for (int i = 0; i < repeat; i++) { + // Hint: if test fails, you can hardcode the seed to make the test more reproducible: + // rnd.setSeed(seed); + testMult(prod1, prod2, coeffs1, coeffs2, mult, multJava, rnd, seed, i); + testMultConst(prod1, prod2, multConst, multConstJava, rnd, seed, i); + testDecompose(prod1, prod2, prod3, prod4, coeffs1, coeffs2, decompose, decomposeJava, rnd, seed, i); + testAlmostNtt(coeffs1, coeffs2, almostNtt, almostNttJava, rnd, seed, i); + testInverseNtt(coeffs1, coeffs2, inverseNtt, inverseNttJava, rnd, seed, i); + } + System.out.println("Fuzz Success"); + } catch (Throwable e) { + System.out.println("Fuzz Failed: " + e); + } + } + + private static final int ML_DSA_N = 256; + public static void testMult(int[] prod1, int[] prod2, int[] coeffs1, int[] coeffs2, + MethodHandle mult, MethodHandle multJava, Random rnd, + long seed, int i) throws Exception, Throwable { + + for (int j = 0; j recording.close()); recording.startAsync(); - String base = TestStringDeduplicationEvent.class.getSimpleName(); - String duplicate = new StringBuilder(base).toString(); - assert(getValue(base) != getValue(duplicate)); + string = TestStringDeduplicationEvent.class.getSimpleName(); + duplicateString = new StringBuilder(string).toString(); if (zgc) { // ZGC only triggers string deduplications from major collections @@ -157,14 +147,6 @@ public class TestStringDeduplicationEvent { } } - private static Object getValue(String string) { - try { - return valueField.get(string); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - private static boolean isZgc() { List gcs = ManagementFactory.getGarbageCollectorMXBeans(); return gcs.getFirst().getName().contains("ZGC"); From 65f1ad616977428fcb498479132086777dc929cb Mon Sep 17 00:00:00 2001 From: Mat Carter Date: Wed, 26 Nov 2025 02:01:27 +0000 Subject: [PATCH 005/706] 8370203: Add jcmd AOT.end_recording diagnostic command Reviewed-by: vlivanov, kvn --- src/hotspot/share/cds/aotMetaspace.cpp | 15 ++ src/hotspot/share/cds/aotMetaspace.hpp | 3 + .../share/services/diagnosticCommand.cpp | 24 +++ .../share/services/diagnosticCommand.hpp | 15 ++ .../aotCache/DiagnosticCommandMBeanTest.java | 162 ++++++++++++++++++ .../aotCache/JcmdAOTEndRecordingTest.java | 93 ++++++++++ 6 files changed, 312 insertions(+) create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/aotCache/DiagnosticCommandMBeanTest.java create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/aotCache/JcmdAOTEndRecordingTest.java diff --git a/src/hotspot/share/cds/aotMetaspace.cpp b/src/hotspot/share/cds/aotMetaspace.cpp index 42d41e6ae89..e1815c2df3c 100644 --- a/src/hotspot/share/cds/aotMetaspace.cpp +++ b/src/hotspot/share/cds/aotMetaspace.cpp @@ -114,6 +114,7 @@ intx AOTMetaspace::_relocation_delta; char* AOTMetaspace::_requested_base_address; Array* AOTMetaspace::_archived_method_handle_intrinsics = nullptr; bool AOTMetaspace::_use_optimized_module_handling = true; +int volatile AOTMetaspace::_preimage_static_archive_dumped = 0; FileMapInfo* AOTMetaspace::_output_mapinfo = nullptr; // The CDS archive is divided into the following regions: @@ -1056,7 +1057,21 @@ void AOTMetaspace::exercise_runtime_cds_code(TRAPS) { CDSProtectionDomain::to_file_URL("dummy.jar", Handle(), CHECK); } +bool AOTMetaspace::preimage_static_archive_dumped() { + assert(CDSConfig::is_dumping_preimage_static_archive(), "Required"); + return AtomicAccess::load_acquire(&_preimage_static_archive_dumped) == 1; +} + void AOTMetaspace::dump_static_archive_impl(StaticArchiveBuilder& builder, TRAPS) { + if (CDSConfig::is_dumping_preimage_static_archive()) { + // When dumping to the AOT configuration file ensure this function is only executed once. + // Multiple invocations may happen via JCmd, during VM exit or other means (in the future) + // from different threads and possibly concurrently. + if (AtomicAccess::cmpxchg(&_preimage_static_archive_dumped, 0, 1) != 0) { + return; + } + } + if (CDSConfig::is_dumping_classic_static_archive()) { // We are running with -Xshare:dump load_classes(CHECK); diff --git a/src/hotspot/share/cds/aotMetaspace.hpp b/src/hotspot/share/cds/aotMetaspace.hpp index 1712a7865ad..ab78787288f 100644 --- a/src/hotspot/share/cds/aotMetaspace.hpp +++ b/src/hotspot/share/cds/aotMetaspace.hpp @@ -60,6 +60,7 @@ class AOTMetaspace : AllStatic { static char* _requested_base_address; static bool _use_optimized_module_handling; static Array* _archived_method_handle_intrinsics; + static int volatile _preimage_static_archive_dumped; static FileMapInfo* _output_mapinfo; public: @@ -115,6 +116,8 @@ public: // inside the metaspace of the dynamic static CDS archive static bool in_aot_cache_dynamic_region(void* p) NOT_CDS_RETURN_(false); + static bool preimage_static_archive_dumped() NOT_CDS_RETURN_(false); + static void unrecoverable_loading_error(const char* message = "unrecoverable error"); static void report_loading_error(const char* format, ...) ATTRIBUTE_PRINTF(1, 0); static void unrecoverable_writing_error(const char* message = nullptr); diff --git a/src/hotspot/share/services/diagnosticCommand.cpp b/src/hotspot/share/services/diagnosticCommand.cpp index 5bef650891d..91b23904676 100644 --- a/src/hotspot/share/services/diagnosticCommand.cpp +++ b/src/hotspot/share/services/diagnosticCommand.cpp @@ -22,6 +22,7 @@ * */ +#include "cds/aotMetaspace.hpp" #include "cds/cds_globals.hpp" #include "cds/cdsConfig.hpp" #include "classfile/classLoaderDataGraph.hpp" @@ -165,6 +166,7 @@ void DCmd::register_dcmds(){ #if INCLUDE_CDS DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); #endif // INCLUDE_CDS DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); @@ -986,6 +988,28 @@ void ClassesDCmd::execute(DCmdSource source, TRAPS) { VMThread::execute(&vmop); } +#if INCLUDE_CDS +void AOTEndRecordingDCmd::execute(DCmdSource source, TRAPS) { + if (!CDSConfig::is_dumping_preimage_static_archive()) { + output()->print_cr("AOT.end_recording is unsupported when VM flags -XX:AOTMode=record or -XX:AOTCacheOutput= are missing."); + return; + } + + if (AOTMetaspace::preimage_static_archive_dumped()) { + output()->print_cr("Recording has already ended."); + return; + } + + AOTMetaspace::dump_static_archive(THREAD); + if (!AOTMetaspace::preimage_static_archive_dumped()) { + output()->print_cr("Error: Failed to end recording."); + return; + } + + output()->print_cr("Recording ended successfully."); +} +#endif // INCLUDE_CDS + #if INCLUDE_CDS #define DEFAULT_CDS_ARCHIVE_FILENAME "java_pid%p_.jsa" diff --git a/src/hotspot/share/services/diagnosticCommand.hpp b/src/hotspot/share/services/diagnosticCommand.hpp index 2364b0ce4cd..c41e7bf2e2e 100644 --- a/src/hotspot/share/services/diagnosticCommand.hpp +++ b/src/hotspot/share/services/diagnosticCommand.hpp @@ -325,6 +325,21 @@ public: virtual void execute(DCmdSource source, TRAPS); }; +#if INCLUDE_CDS +class AOTEndRecordingDCmd : public DCmd { +public: + AOTEndRecordingDCmd(outputStream* output, bool heap) : DCmd(output, heap) { } + static const char* name() { return "AOT.end_recording"; } + static const char* description() { + return "End AOT recording."; + } + static const char* impact() { + return "Medium: Pause time depends on number of loaded classes"; + } + virtual void execute(DCmdSource source, TRAPS); +}; +#endif // INCLUDE_CDS + #if INCLUDE_CDS class DumpSharedArchiveDCmd: public DCmdWithParser { protected: diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/DiagnosticCommandMBeanTest.java b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/DiagnosticCommandMBeanTest.java new file mode 100644 index 00000000000..5f836b608cf --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/DiagnosticCommandMBeanTest.java @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2025, Microsoft, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + + +/* + * @test + * @requires vm.cds.supports.aot.class.linking + * @requires vm.cds.write.archived.java.heap + * @summary Sanity test for DiagnosticCommand MBean ability to invoke AOT.end_recording + * @library /test/jdk/lib/testlibrary /test/lib + * /test/hotspot/jtreg/runtime/cds/appcds/aotCache/test-classes + * @build DiagnosticCommandMBeanTest + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar app.jar DiagnosticCommandMBeanApp + * @run driver DiagnosticCommandMBeanTest + */ + +import java.lang.management.ManagementFactory; +import javax.management.MBeanServer; +import javax.management.ObjectName; +import javax.management.InstanceNotFoundException; +import javax.management.MBeanException; +import javax.management.ReflectionException; +import javax.management.MalformedObjectNameException; + +import jdk.test.lib.cds.CDSAppTester; +import jdk.test.lib.helpers.ClassFileInstaller; +import jdk.test.lib.process.OutputAnalyzer; + +public class DiagnosticCommandMBeanTest { + static final String appJar = ClassFileInstaller.getJarPath("app.jar"); + static final String mainClass = "DiagnosticCommandMBeanApp"; + public static void main(String[] args) throws Exception { + Tester tester = new Tester(); + tester.runAOTWorkflow(); + } + + static class Tester extends CDSAppTester { + public Tester() { + super(mainClass); + } + + @Override + public String classpath(RunMode runMode) { + return appJar; + } + + @Override + public String[] vmArgs(RunMode runMode) { + return new String[] { + "-Xlog:cds+class=trace", + "--add-modules=jdk.management" + }; + } + + @Override + public String[] appCommandLine(RunMode runMode) { + return new String[] { + mainClass, runMode.name() + }; + } + + @Override + public void checkExecution(OutputAnalyzer out, RunMode runMode) { + var name = runMode.name(); + if (runMode.isApplicationExecuted()) { + if(runMode == RunMode.TRAINING) { + out.shouldContain("Hello Leyden " + name); + out.shouldContain("AOT.end_recording invoked successfully"); + out.shouldContain("Successfully stopped recording"); + } else if (runMode == RunMode.ASSEMBLY) { + out.shouldNotContain("Hello Leyden "); + } else if (runMode == RunMode.PRODUCTION) { + out.shouldContain("Hello Leyden " + name); + out.shouldContain("AOT.end_recording invoked successfully"); + out.shouldContain("Failed to stop recording"); + } + out.shouldNotContain("Exception occurred!"); + out.shouldHaveExitValue(0); + } + } + } +} + +class DiagnosticCommandMBeanApp { + public static void main(String[] args) { + System.out.println("Hello Leyden " + args[0]); + /* + * The following code is based on: docs/api/jdk.management/com/sun/management/DiagnosticCommandMBean.html + * + * Copied from the documentation for reference: + * + * ... The DiagnosticCommandMBean is generated at runtime and is subject to modifications during the lifetime of + * the Java virtual machine. A diagnostic command is represented as an operation of the DiagnosticCommandMBean + * interface. Each diagnostic command has: + * + * - the diagnostic command name which is the name being referenced in the HotSpot Virtual Machine + * - the MBean operation name which is the name generated for the diagnostic command operation invocation. The + * MBean operation name is implementation dependent + * + * The recommended way to transform a diagnostic command name into a MBean operation name is as follows: + * + * - All characters from the first one to the first dot are set to be lower-case characters + * - Every dot or underline character is removed and the following character is set to be an upper-case character + * - All other characters are copied without modification + * + * A diagnostic command may or may not support options or arguments. All the operations return String and + * either take no parameter for operations that do not support any option or argument, or take a String[] + * parameter for operations that support at least one option or argument. Each option or argument must be stored in + * a single String. + */ + try { + MBeanServer server = ManagementFactory.getPlatformMBeanServer(); + ObjectName diagName = new ObjectName("com.sun.management:type=DiagnosticCommand"); + + // The DiagnosticCommand MBean operations expect a String array parameter for command arguments + // Even though AOT.end_recording doesn't need any arguments, you still need to pass an empty String array + // The MBean framework requires you to specify both the parameters and their types (signatures) + Object[] params = { new String[0] }; + String[] signature = { "[Ljava.lang.String;" }; + + // The JCmd AOT.end_recording is invoked using 'aotEndRecording' + String result = (String) server.invoke(diagName, "aotEndRecording", params, signature); + + // The result is the string output from the command + System.out.println("AOT.end_recording invoked successfully"); + if (result.contains("Recording ended successfully")) { + System.out.println("Successfully stopped recording"); + } else { + System.out.println("Failed to stop recording"); + } + } catch (MBeanException e) { + System.out.println("MBeanException occurred!"); + } catch (ReflectionException e) { + System.out.println("ReflectionException occurred!"); + } catch (MalformedObjectNameException e) { + System.out.println("MalformedObjectNameException occurred!"); + } catch (InstanceNotFoundException e) { + System.out.println("InstanceNotFoundException occurred!"); + } + } +} \ No newline at end of file diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/JcmdAOTEndRecordingTest.java b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/JcmdAOTEndRecordingTest.java new file mode 100644 index 00000000000..50c6b6de298 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/JcmdAOTEndRecordingTest.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2025, Microsoft, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * @test + * @requires vm.cds.supports.aot.class.linking + * @requires vm.cds.write.archived.java.heap + * @summary Sanity test for Jcmd AOT.end_recording command + * @library /test/lib + * @build JcmdAOTEndRecordingTest + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar LingeredApp.jar + * jdk/test/lib/apps/LingeredApp + * jdk/test/lib/apps/LingeredApp$1 + * jdk/test/lib/apps/LingeredApp$SteadyStateLock + * jdk/test/lib/process/OutputBuffer + * @run driver JcmdAOTEndRecordingTest + */ + +import jdk.test.lib.JDKToolLauncher; +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.apps.LingeredApp; +import jdk.test.lib.dcmd.PidJcmdExecutor; +import jdk.test.lib.process.OutputAnalyzer; +import java.io.IOException; + +public class JcmdAOTEndRecordingTest { + public static void main(String[] args) throws Exception { + test(false); + test(true); + } + + static void test(boolean isTraining) throws Exception { + LingeredApp theApp = null; + try { + theApp = new LingeredApp(); + theApp.setUseDefaultClasspath(false); + if (isTraining) { + LingeredApp.startApp(theApp, + "-cp", "LingeredApp.jar", + "-XX:AOTMode=record", + "-XX:AOTConfiguration=LingeredApp.aotconfig"); + } else { + LingeredApp.startApp(theApp, + "-cp", "LingeredApp.jar"); + } + long pid = theApp.getPid(); + + JDKToolLauncher jcmd = JDKToolLauncher.createUsingTestJDK("jcmd"); + jcmd.addToolArg(String.valueOf(pid)); + jcmd.addToolArg("AOT.end_recording"); + + try { + OutputAnalyzer output = ProcessTools.executeProcess(jcmd.getCommand()); + if (isTraining) { + output.shouldContain("Recording ended successfully"); + } else { + // this message is output when the VM is not recording AOT data + output.shouldContain("AOT.end_recording is unsupported"); + } + output.shouldHaveExitValue(0); + } catch (Exception e) { + throw new RuntimeException("Test failed: " + e); + } + } + catch (IOException e) { + throw new RuntimeException("Test failed: " + e); + } + finally { + LingeredApp.stopApp(theApp); + } + } +} \ No newline at end of file From 4ffdf7af88f6c0a69663eb249957dbceea3cb697 Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Wed, 26 Nov 2025 05:46:06 +0000 Subject: [PATCH 006/706] 8366224: Introduce DecimalDigits.appendPair for efficient two-digit formatting and refactor DateTimeHelper Reviewed-by: liach, rriggs --- .../share/classes/java/time/MonthDay.java | 12 ++-- .../share/classes/java/time/YearMonth.java | 15 ++--- .../share/classes/java/time/ZoneOffset.java | 11 ++-- .../java/time/chrono/ChronoLocalDateImpl.java | 18 ++++-- .../jdk/internal/util/DateTimeHelper.java | 29 +++++----- .../jdk/internal/util/DecimalDigits.java | 55 +++++++++++++++++++ 6 files changed, 104 insertions(+), 36 deletions(-) diff --git a/src/java.base/share/classes/java/time/MonthDay.java b/src/java.base/share/classes/java/time/MonthDay.java index a25c9beec95..26ca69bbe0d 100644 --- a/src/java.base/share/classes/java/time/MonthDay.java +++ b/src/java.base/share/classes/java/time/MonthDay.java @@ -88,6 +88,8 @@ import java.time.temporal.UnsupportedTemporalTypeException; import java.time.temporal.ValueRange; import java.util.Objects; +import jdk.internal.util.DecimalDigits; + /** * A month-day in the ISO-8601 calendar system, such as {@code --12-03}. *

@@ -764,10 +766,12 @@ public final class MonthDay */ @Override public String toString() { - return new StringBuilder(10).append("--") - .append(month < 10 ? "0" : "").append(month) - .append(day < 10 ? "-0" : "-").append(day) - .toString(); + StringBuilder buf = new StringBuilder(10); + buf.append("--"); + DecimalDigits.appendPair(buf, month); + buf.append('-'); + DecimalDigits.appendPair(buf, day); + return buf.toString(); } //----------------------------------------------------------------------- diff --git a/src/java.base/share/classes/java/time/YearMonth.java b/src/java.base/share/classes/java/time/YearMonth.java index b3d1aff7bc2..665c8c85544 100644 --- a/src/java.base/share/classes/java/time/YearMonth.java +++ b/src/java.base/share/classes/java/time/YearMonth.java @@ -101,6 +101,8 @@ import java.time.temporal.UnsupportedTemporalTypeException; import java.time.temporal.ValueRange; import java.util.Objects; +import jdk.internal.util.DecimalDigits; + /** * A year-month in the ISO-8601 calendar system, such as {@code 2007-12}. *

@@ -1213,18 +1215,17 @@ public final class YearMonth public String toString() { int absYear = Math.abs(year); StringBuilder buf = new StringBuilder(9); - if (absYear < 1000) { + if (absYear < 10000) { if (year < 0) { - buf.append(year - 10000).deleteCharAt(1); - } else { - buf.append(year + 10000).deleteCharAt(0); + buf.append('-'); } + DecimalDigits.appendQuad(buf, absYear); } else { buf.append(year); } - return buf.append(month < 10 ? "-0" : "-") - .append(month) - .toString(); + buf.append('-'); + DecimalDigits.appendPair(buf, month); + return buf.toString(); } //----------------------------------------------------------------------- diff --git a/src/java.base/share/classes/java/time/ZoneOffset.java b/src/java.base/share/classes/java/time/ZoneOffset.java index 4199d17735c..2a45e7cbf82 100644 --- a/src/java.base/share/classes/java/time/ZoneOffset.java +++ b/src/java.base/share/classes/java/time/ZoneOffset.java @@ -88,6 +88,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicReferenceArray; +import jdk.internal.util.DecimalDigits; import jdk.internal.vm.annotation.Stable; /** @@ -465,12 +466,14 @@ public final class ZoneOffset StringBuilder buf = new StringBuilder(); int absHours = absTotalSeconds / SECONDS_PER_HOUR; int absMinutes = (absTotalSeconds / SECONDS_PER_MINUTE) % MINUTES_PER_HOUR; - buf.append(totalSeconds < 0 ? "-" : "+") - .append(absHours < 10 ? "0" : "").append(absHours) - .append(absMinutes < 10 ? ":0" : ":").append(absMinutes); + buf.append(totalSeconds < 0 ? '-' : '+'); + DecimalDigits.appendPair(buf, absHours); + buf.append(':'); + DecimalDigits.appendPair(buf, absMinutes); int absSeconds = absTotalSeconds % SECONDS_PER_MINUTE; if (absSeconds != 0) { - buf.append(absSeconds < 10 ? ":0" : ":").append(absSeconds); + buf.append(':'); + DecimalDigits.appendPair(buf, absSeconds); } return buf.toString(); } diff --git a/src/java.base/share/classes/java/time/chrono/ChronoLocalDateImpl.java b/src/java.base/share/classes/java/time/chrono/ChronoLocalDateImpl.java index ca226b70d24..67f08c5cb4f 100644 --- a/src/java.base/share/classes/java/time/chrono/ChronoLocalDateImpl.java +++ b/src/java.base/share/classes/java/time/chrono/ChronoLocalDateImpl.java @@ -74,6 +74,8 @@ import java.time.temporal.UnsupportedTemporalTypeException; import java.time.temporal.ValueRange; import java.util.Objects; +import jdk.internal.util.DecimalDigits; + /** * A date expressed in terms of a standard year-month-day calendar system. *

@@ -426,18 +428,22 @@ abstract class ChronoLocalDateImpl @Override public String toString() { - // getLong() reduces chances of exceptions in toString() - long yoe = getLong(YEAR_OF_ERA); - long moy = getLong(MONTH_OF_YEAR); - long dom = getLong(DAY_OF_MONTH); + // Using get() instead of getLong() for performance reasons, + // as the values of YEAR_OF_ERA, MONTH_OF_YEAR, and DAY_OF_MONTH + // are guaranteed to be within the int range for all chronologies. + int yoe = get(YEAR_OF_ERA); + int moy = get(MONTH_OF_YEAR); + int dom = get(DAY_OF_MONTH); StringBuilder buf = new StringBuilder(30); buf.append(getChronology().toString()) .append(" ") .append(getEra()) .append(" ") .append(yoe) - .append(moy < 10 ? "-0" : "-").append(moy) - .append(dom < 10 ? "-0" : "-").append(dom); + .append('-'); + DecimalDigits.appendPair(buf, moy); + buf.append('-'); + DecimalDigits.appendPair(buf, dom); return buf.toString(); } diff --git a/src/java.base/share/classes/jdk/internal/util/DateTimeHelper.java b/src/java.base/share/classes/jdk/internal/util/DateTimeHelper.java index bbb0b6738d1..4d9d560fded 100644 --- a/src/java.base/share/classes/jdk/internal/util/DateTimeHelper.java +++ b/src/java.base/share/classes/jdk/internal/util/DateTimeHelper.java @@ -49,24 +49,23 @@ public final class DateTimeHelper { * Requires extra capacity of 10 to avoid StringBuilder reallocation. */ public static void formatTo(StringBuilder buf, LocalDate date) { - int year = date.getYear(), - month = date.getMonthValue(), - day = date.getDayOfMonth(); - int absYear = Math.abs(year); - if (absYear < 1000) { + int year = date.getYear(), + absYear = Math.abs(year); + if (absYear < 10000) { if (year < 0) { buf.append('-'); } - buf.repeat('0', absYear < 10 ? 3 : absYear < 100 ? 2 : 1); - buf.append(absYear); + DecimalDigits.appendQuad(buf, absYear); } else { if (year > 9999) { buf.append('+'); } buf.append(year); } - buf.append(month < 10 ? "-0" : "-").append(month) - .append(day < 10 ? "-0" : "-").append(day); + buf.append('-'); + DecimalDigits.appendPair(buf, date.getMonthValue()); + buf.append('-'); + DecimalDigits.appendPair(buf, date.getDayOfMonth()); } /** @@ -74,14 +73,14 @@ public final class DateTimeHelper { * Requires extra capacity of 18 to avoid StringBuilder reallocation. */ public static void formatTo(StringBuilder buf, LocalTime time) { - int hour = time.getHour(), - minute = time.getMinute(), - second = time.getSecond(), + DecimalDigits.appendPair(buf, time.getHour()); + buf.append(':'); + DecimalDigits.appendPair(buf, time.getMinute()); + int second = time.getSecond(), nano = time.getNano(); - buf.append(hour < 10 ? "0" : "").append(hour) - .append(minute < 10 ? ":0" : ":").append(minute); if ((second | nano) > 0) { - buf.append(second < 10 ? ":0" : ":").append(second); + buf.append(':'); + DecimalDigits.appendPair(buf, second); if (nano > 0) { buf.append('.'); int zeros = 9 - DecimalDigits.stringSize(nano); diff --git a/src/java.base/share/classes/jdk/internal/util/DecimalDigits.java b/src/java.base/share/classes/jdk/internal/util/DecimalDigits.java index 6c0c745651e..b55b6ce63b0 100644 --- a/src/java.base/share/classes/jdk/internal/util/DecimalDigits.java +++ b/src/java.base/share/classes/jdk/internal/util/DecimalDigits.java @@ -25,6 +25,8 @@ package jdk.internal.util; +import jdk.internal.access.JavaLangAccess; +import jdk.internal.access.SharedSecrets; import jdk.internal.misc.Unsafe; import jdk.internal.vm.annotation.Stable; @@ -36,6 +38,7 @@ import static jdk.internal.misc.Unsafe.ARRAY_BYTE_BASE_OFFSET; * @since 21 */ public final class DecimalDigits { + private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess(); private static final Unsafe UNSAFE = Unsafe.getUnsafe(); /** @@ -443,4 +446,56 @@ public final class DecimalDigits { assert charPos >= 0 && charPos < (buf.length >> 1); UNSAFE.putCharUnaligned(buf, ARRAY_BYTE_BASE_OFFSET + ((long) charPos << 1), (char) c); } + + /** + * Appends the two-digit string representation of the {@code int} + * argument to the given {@code StringBuilder}. + *

+ * The integer {@code v} is formatted as two decimal digits. + * Values from 0 to 9 are formatted with a leading zero (e.g., 5 becomes "05"), + * and values from 10 to 99 are formatted as regular two-digit numbers. + * If the value is outside the range 0-99, the behavior is unspecified. + * + * @param buf the {@code StringBuilder} to append to. + * @param v the {@code int} value (should be between 0 and 99 inclusive). + */ + public static void appendPair(StringBuilder buf, int v) { + // The & 0x7f operation keeps the index within the safe range [0, 127] for the DIGITS array, + // which allows the JIT compiler to eliminate array bounds checks for performance. + int packed = DIGITS[v & 0x7f]; + // The temporary String and byte[] objects created here are typically eliminated + // by the JVM's escape analysis and scalar replacement optimizations during + // runtime compilation, avoiding actual heap allocations in optimized code. + buf.append( + JLA.uncheckedNewStringWithLatin1Bytes( + new byte[] {(byte) packed, (byte) (packed >> 8)})); + } + + /** + * Appends the four-digit string representation of the {@code int} + * argument to the given {@code StringBuilder}. + *

+ * The integer {@code v} is formatted as four decimal digits. + * Values from 0 to 9 are formatted with leading zeros (e.g., 5 becomes "0005"), + * values from 10 to 99 add two leading zeros (e.g., 25 becomes "0025"), + * values from 100 to 999 add one leading zero (e.g., 123 becomes "0123"), + * and values from 1000 to 9999 have no leading zeros. + * If the value is outside the range 0-9999, the behavior is unspecified. + * + * @param buf the {@code StringBuilder} to append to. + * @param v the {@code int} value (should be between 0 and 9999 inclusive). + */ + public static void appendQuad(StringBuilder buf, int v) { + // The & 0x7f operation keeps the index within the safe range [0, 127] for the DIGITS array, + // which allows the JIT compiler to eliminate array bounds checks for performance. + int packedHigh = DIGITS[(v / 100) & 0x7f]; + int packedLow = DIGITS[(v % 100) & 0x7f]; + // The temporary String and byte[] objects created here are typically eliminated + // by the JVM's escape analysis and scalar replacement optimizations during + // runtime compilation, avoiding actual heap allocations in optimized code. + buf.append( + JLA.uncheckedNewStringWithLatin1Bytes( + new byte[] {(byte) packedHigh, (byte) (packedHigh >> 8), + (byte) packedLow, (byte) (packedLow >> 8)})); + } } From 7cc584fbe6ce3d2f14d96ffb7e9650fd3498aa7a Mon Sep 17 00:00:00 2001 From: Sorna Sarathi N Date: Wed, 26 Nov 2025 05:47:45 +0000 Subject: [PATCH 007/706] 8372399: Add missing CPE statements Reviewed-by: asemenyuk --- .../share/classes/jdk/jpackage/internal/util/SetBuilder.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/SetBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/SetBuilder.java index b9d3140c5f9..18736b4ed7e 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/SetBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/SetBuilder.java @@ -4,7 +4,9 @@ * * 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. + * 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 From e13dfd3ec39b0550eede83aa766deaad105995fc Mon Sep 17 00:00:00 2001 From: Neha Joshi Date: Wed, 26 Nov 2025 05:53:58 +0000 Subject: [PATCH 008/706] 8370942: test/jdk/java/security/Provider/NewInstance.java and /test/jdk/java/security/cert/CertStore/NoLDAP.java may skip without notifying Reviewed-by: myankelevich, rhalade --- .../java/security/Provider/NewInstance.java | 29 ++++++++++++++----- .../java/security/cert/CertStore/NoLDAP.java | 11 ++++--- 2 files changed, 28 insertions(+), 12 deletions(-) diff --git a/test/jdk/java/security/Provider/NewInstance.java b/test/jdk/java/security/Provider/NewInstance.java index ad69f468925..547b9111682 100644 --- a/test/jdk/java/security/Provider/NewInstance.java +++ b/test/jdk/java/security/Provider/NewInstance.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, 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,21 +26,34 @@ * @bug 8039853 * @summary Provider.Service.newInstance() does not work with current JDK JGSS Mechanisms + * @library /test/lib */ -import java.security.*; -import java.util.*; + +import jtreg.SkippedException; + +import java.security.InvalidAlgorithmParameterException; +import java.security.NoSuchAlgorithmException; +import java.security.Provider; +import java.security.Security; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; public class NewInstance { public static void main(String[] args) throws Exception { - for (Provider p : Security.getProviders()) { + + System.out.println("Removing SunPCSC provider from the list (A smartcard might not be installed)."); + final List providers = Arrays.stream(Security.getProviders()) + .filter(provider -> !provider.getName().equals("SunPCSC")) + .collect(Collectors.toList()); + + for (Provider p : providers) { System.out.println("---------"); System.out.println(p.getName() + ":" + p.getInfo()); - if (p.getName().equals("SunPCSC")) { - System.out.println("A smartcard might not be installed. Skip test."); - continue; - } Set set = p.getServices(); Iterator i = set.iterator(); diff --git a/test/jdk/java/security/cert/CertStore/NoLDAP.java b/test/jdk/java/security/cert/CertStore/NoLDAP.java index 868411e63c4..812a978931d 100644 --- a/test/jdk/java/security/cert/CertStore/NoLDAP.java +++ b/test/jdk/java/security/cert/CertStore/NoLDAP.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, 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,20 +25,23 @@ * @bug 8004502 * @summary Sanity check that NoSuchAlgorithmException is thrown when requesting * a CertStore of type "LDAP" and LDAP is not available. + * @library /test/lib */ import java.security.NoSuchAlgorithmException; import java.security.cert.CertStore; import java.security.cert.LDAPCertStoreParameters; +import jtreg.SkippedException; public class NoLDAP { public static void main(String[] args) throws Exception { try { Class.forName("javax.naming.ldap.LdapName"); - System.out.println("LDAP is present, test skipped"); - return; - } catch (ClassNotFoundException ignore) { } + throw new SkippedException("LDAP is present"); + } catch (ClassNotFoundException ignore) { + System.err.println("Expected: class not found exception " + ignore.getMessage()); + } try { CertStore.getInstance("LDAP", new LDAPCertStoreParameters()); From cdf5fbed9bd8366e4ee9ab9cb538db88d7bcc7c0 Mon Sep 17 00:00:00 2001 From: Neha Joshi Date: Wed, 26 Nov 2025 06:16:08 +0000 Subject: [PATCH 009/706] 8334928: Test sun/security/ssl/SSLSocketImpl/ReuseAddr.java failed: java.net.BindException: Address already in use Reviewed-by: rhalade --- test/jdk/javax/net/ssl/templates/SSLSocketTemplate.java | 2 ++ test/jdk/sun/security/ssl/SSLSocketImpl/ReuseAddr.java | 5 +++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/test/jdk/javax/net/ssl/templates/SSLSocketTemplate.java b/test/jdk/javax/net/ssl/templates/SSLSocketTemplate.java index 0891523ac11..51706cec927 100644 --- a/test/jdk/javax/net/ssl/templates/SSLSocketTemplate.java +++ b/test/jdk/javax/net/ssl/templates/SSLSocketTemplate.java @@ -190,6 +190,7 @@ public class SSLSocketTemplate extends SSLContextTemplate { try { sslServerSocket.setSoTimeout(30000); sslSocket = (SSLSocket)sslServerSocket.accept(); + System.out.println("Connection established on port : " +serverPort); } catch (SocketTimeoutException ste) { // Ignore the test case if no connection within 30 seconds. System.out.println( @@ -228,6 +229,7 @@ public class SSLSocketTemplate extends SSLContextTemplate { } } finally { sslSocket.close(); + System.out.println("Connection closed on port : " +serverPort); } } diff --git a/test/jdk/sun/security/ssl/SSLSocketImpl/ReuseAddr.java b/test/jdk/sun/security/ssl/SSLSocketImpl/ReuseAddr.java index f7e677bbbd0..68761f10c59 100644 --- a/test/jdk/sun/security/ssl/SSLSocketImpl/ReuseAddr.java +++ b/test/jdk/sun/security/ssl/SSLSocketImpl/ReuseAddr.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, 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,7 +38,7 @@ import java.net.BindException; public class ReuseAddr extends SSLSocketTemplate { - private static final int MAX_ATTEMPTS = 3; + private static final int MAX_ATTEMPTS = 15; @Override protected void doServerSide() throws Exception { @@ -65,6 +65,7 @@ public class ReuseAddr extends SSLSocketTemplate { System.err.println(msg); throw new AssertionError("Failed to reuse address: " + msg, x); } else { + Thread.sleep(100*i); System.out.println("Retrying..."); } } From f3fddd6e9062e9f70c276d31247a7417b9571390 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Wed, 26 Nov 2025 06:17:44 +0000 Subject: [PATCH 010/706] 8372251: Convert PartialArrayStepper/State to use Atomic Reviewed-by: iwalulya, tschatzl --- .../share/gc/shared/partialArrayState.cpp | 18 +++++++++--------- .../share/gc/shared/partialArrayState.hpp | 13 +++++++------ .../gc/shared/partialArrayTaskStepper.hpp | 5 +++-- .../shared/partialArrayTaskStepper.inline.hpp | 6 ++---- .../gc/shared/test_partialArrayTaskStepper.cpp | 11 ++++++----- 5 files changed, 27 insertions(+), 26 deletions(-) diff --git a/src/hotspot/share/gc/shared/partialArrayState.cpp b/src/hotspot/share/gc/shared/partialArrayState.cpp index 39c1fe4fc78..6f714d48a35 100644 --- a/src/hotspot/share/gc/shared/partialArrayState.cpp +++ b/src/hotspot/share/gc/shared/partialArrayState.cpp @@ -47,7 +47,7 @@ PartialArrayState::PartialArrayState(oop src, oop dst, } void PartialArrayState::add_references(size_t count) { - size_t new_count = AtomicAccess::add(&_refcount, count, memory_order_relaxed); + size_t new_count = _refcount.add_then_fetch(count, memory_order_relaxed); assert(new_count >= count, "reference count overflow"); } @@ -92,7 +92,7 @@ PartialArrayState* PartialArrayStateAllocator::allocate(oop src, oop dst, } void PartialArrayStateAllocator::release(PartialArrayState* state) { - size_t refcount = AtomicAccess::sub(&state->_refcount, size_t(1), memory_order_release); + size_t refcount = state->_refcount.sub_then_fetch(1u, memory_order_release); if (refcount != 0) { assert(refcount + 1 != 0, "refcount underflow"); } else { @@ -116,25 +116,25 @@ PartialArrayStateManager::~PartialArrayStateManager() { } Arena* PartialArrayStateManager::register_allocator() { - uint idx = AtomicAccess::fetch_then_add(&_registered_allocators, 1u, memory_order_relaxed); + uint idx = _registered_allocators.fetch_then_add(1u, memory_order_relaxed); assert(idx < _max_allocators, "exceeded configured max number of allocators"); return ::new (&_arenas[idx]) Arena(mtGC); } #ifdef ASSERT void PartialArrayStateManager::release_allocator() { - uint old = AtomicAccess::fetch_then_add(&_released_allocators, 1u, memory_order_relaxed); - assert(old < AtomicAccess::load(&_registered_allocators), "too many releases"); + uint old = _released_allocators.fetch_then_add(1u, memory_order_relaxed); + assert(old < _registered_allocators.load_relaxed(), "too many releases"); } #endif // ASSERT void PartialArrayStateManager::reset() { - uint count = AtomicAccess::load(&_registered_allocators); - assert(count == AtomicAccess::load(&_released_allocators), + uint count = _registered_allocators.load_relaxed(); + assert(count == _released_allocators.load_relaxed(), "some allocators still active"); for (uint i = 0; i < count; ++i) { _arenas[i].~Arena(); } - AtomicAccess::store(&_registered_allocators, 0u); - DEBUG_ONLY(AtomicAccess::store(&_released_allocators, 0u);) + _registered_allocators.store_relaxed(0u); + DEBUG_ONLY(_released_allocators.store_relaxed(0u);) } diff --git a/src/hotspot/share/gc/shared/partialArrayState.hpp b/src/hotspot/share/gc/shared/partialArrayState.hpp index 3208c6d6807..3dafeb0f14c 100644 --- a/src/hotspot/share/gc/shared/partialArrayState.hpp +++ b/src/hotspot/share/gc/shared/partialArrayState.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, 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 @@ #include "memory/allocation.hpp" #include "oops/oopsHierarchy.hpp" +#include "runtime/atomic.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" @@ -60,8 +61,8 @@ class PartialArrayState { oop _source; oop _destination; size_t _length; - volatile size_t _index; - volatile size_t _refcount; + Atomic _index; + Atomic _refcount; friend class PartialArrayStateAllocator; @@ -90,7 +91,7 @@ public: // A pointer to the start index for the next segment to process, for atomic // update. - volatile size_t* index_addr() { return &_index; } + Atomic* index_addr() { return &_index; } }; // This class provides memory management for PartialArrayStates. @@ -178,8 +179,8 @@ class PartialArrayStateManager : public CHeapObj { // The number of allocators that have been registered/released. // Atomic to support concurrent registration, and concurrent release. // Phasing restriction forbids registration concurrent with release. - volatile uint _registered_allocators; - DEBUG_ONLY(volatile uint _released_allocators;) + Atomic _registered_allocators; + DEBUG_ONLY(Atomic _released_allocators;) // These are all for sole use of the befriended allocator class. Arena* register_allocator(); diff --git a/src/hotspot/share/gc/shared/partialArrayTaskStepper.hpp b/src/hotspot/share/gc/shared/partialArrayTaskStepper.hpp index a68d9bd3612..11499ca2ffe 100644 --- a/src/hotspot/share/gc/shared/partialArrayTaskStepper.hpp +++ b/src/hotspot/share/gc/shared/partialArrayTaskStepper.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, 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 @@ #define SHARE_GC_SHARED_PARTIALARRAYTASKSTEPPER_HPP #include "oops/arrayOop.hpp" +#include "runtime/atomic.hpp" #include "utilities/globalDefinitions.hpp" class PartialArrayState; @@ -73,7 +74,7 @@ private: uint _task_fanout; // For unit tests. - inline Step next_impl(size_t length, volatile size_t* index_addr) const; + inline Step next_impl(size_t length, Atomic* index_addr) const; }; #endif // SHARE_GC_SHARED_PARTIALARRAYTASKSTEPPER_HPP diff --git a/src/hotspot/share/gc/shared/partialArrayTaskStepper.inline.hpp b/src/hotspot/share/gc/shared/partialArrayTaskStepper.inline.hpp index 3693abaf8cf..aaa86e2de16 100644 --- a/src/hotspot/share/gc/shared/partialArrayTaskStepper.inline.hpp +++ b/src/hotspot/share/gc/shared/partialArrayTaskStepper.inline.hpp @@ -46,15 +46,13 @@ PartialArrayTaskStepper::start(size_t length) const { } PartialArrayTaskStepper::Step -PartialArrayTaskStepper::next_impl(size_t length, volatile size_t* index_addr) const { +PartialArrayTaskStepper::next_impl(size_t length, Atomic* index_addr) const { // The start of the next task is in the state's index. // Atomically increment by the chunk size to claim the associated chunk. // Because we limit the number of enqueued tasks to being no more than the // number of remaining chunks to process, we can use an atomic add for the // claim, rather than a CAS loop. - size_t start = AtomicAccess::fetch_then_add(index_addr, - _chunk_size, - memory_order_relaxed); + size_t start = index_addr->fetch_then_add(_chunk_size, memory_order_relaxed); assert(start < length, "invariant: start %zu, length %zu", start, length); assert(((length - start) % _chunk_size) == 0, diff --git a/test/hotspot/gtest/gc/shared/test_partialArrayTaskStepper.cpp b/test/hotspot/gtest/gc/shared/test_partialArrayTaskStepper.cpp index 0ebfc8e01dd..977e7a9d949 100644 --- a/test/hotspot/gtest/gc/shared/test_partialArrayTaskStepper.cpp +++ b/test/hotspot/gtest/gc/shared/test_partialArrayTaskStepper.cpp @@ -24,6 +24,7 @@ #include "gc/shared/partialArrayTaskStepper.inline.hpp" #include "memory/allStatic.hpp" +#include "runtime/atomic.hpp" #include "unittest.hpp" using Step = PartialArrayTaskStepper::Step; @@ -33,7 +34,7 @@ class PartialArrayTaskStepper::TestSupport : AllStatic { public: static Step next(const Stepper* stepper, size_t length, - size_t* to_length_addr) { + Atomic* to_length_addr) { return stepper->next_impl(length, to_length_addr); } }; @@ -42,9 +43,9 @@ using StepperSupport = PartialArrayTaskStepper::TestSupport; static uint simulate(const Stepper* stepper, size_t length, - size_t* to_length_addr) { + Atomic* to_length_addr) { Step init = stepper->start(length); - *to_length_addr = init._index; + to_length_addr->store_relaxed(init._index); uint queue_count = init._ncreate; uint task = 0; for ( ; queue_count > 0; ++task) { @@ -57,9 +58,9 @@ static uint simulate(const Stepper* stepper, static void run_test(size_t length, size_t chunk_size, uint n_workers) { const PartialArrayTaskStepper stepper(n_workers, chunk_size); - size_t to_length; + Atomic to_length; uint tasks = simulate(&stepper, length, &to_length); - ASSERT_EQ(length, to_length); + ASSERT_EQ(length, to_length.load_relaxed()); ASSERT_EQ(tasks, length / chunk_size); } From 3ef3f259bbf4bf40638f53319ec4eea7fdd147e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mar=C3=ADa=20Arias=20de=20Reyna=20Dom=C3=ADnguez?= Date: Wed, 26 Nov 2025 06:39:31 +0000 Subject: [PATCH 011/706] 8372253: Improve logging to show why a class was excluded from AOT Cache Reviewed-by: asmehra, iklam --- src/hotspot/share/cds/aotMetaspace.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/cds/aotMetaspace.cpp b/src/hotspot/share/cds/aotMetaspace.cpp index e1815c2df3c..f56050d4d31 100644 --- a/src/hotspot/share/cds/aotMetaspace.cpp +++ b/src/hotspot/share/cds/aotMetaspace.cpp @@ -1370,8 +1370,11 @@ bool AOTMetaspace::try_link_class(JavaThread* current, InstanceKlass* ik) { ik->link_class(THREAD); if (HAS_PENDING_EXCEPTION) { ResourceMark rm(THREAD); - aot_log_warning(aot)("Preload Warning: Verification failed for %s", - ik->external_name()); + oop message = java_lang_Throwable::message(current->pending_exception()); + aot_log_warning(aot)("Preload Warning: Verification failed for %s because a %s was thrown: %s", + ik->external_name(), + current->pending_exception()->klass()->external_name(), + message == nullptr ? "(no message)" : java_lang_String::as_utf8_string(message)); CLEAR_PENDING_EXCEPTION; SystemDictionaryShared::set_class_has_failed_verification(ik); } else { From 46ee8d550e42f756dd04fa67ed549c93b632df77 Mon Sep 17 00:00:00 2001 From: Anthony Scarpino Date: Wed, 26 Nov 2025 06:48:19 +0000 Subject: [PATCH 012/706] 8372547: New test sun/security/provider/acvp/ML_DSA_Intrinsic_Test.java should be restricted to x86_64 Reviewed-by: dholmes --- test/jdk/sun/security/provider/acvp/ML_DSA_Intrinsic_Test.java | 1 + 1 file changed, 1 insertion(+) diff --git a/test/jdk/sun/security/provider/acvp/ML_DSA_Intrinsic_Test.java b/test/jdk/sun/security/provider/acvp/ML_DSA_Intrinsic_Test.java index 60c0804891d..ea04b3c7eec 100644 --- a/test/jdk/sun/security/provider/acvp/ML_DSA_Intrinsic_Test.java +++ b/test/jdk/sun/security/provider/acvp/ML_DSA_Intrinsic_Test.java @@ -37,6 +37,7 @@ import java.util.HexFormat; */ /* * @test + * @requires os.simpleArch == "x64" * @library /test/lib * @key randomness * @modules java.base/sun.security.provider:+open From 275cb9f28799081878e0a7c53ce1c0450f4e963e Mon Sep 17 00:00:00 2001 From: Christian Hagedorn Date: Wed, 26 Nov 2025 07:55:43 +0000 Subject: [PATCH 013/706] 8360510: C2: Template Assertion Predicates are not cloned to the inner counted loop with -XX:+StressDuplicateBackedge Reviewed-by: epeter, roland --- src/hotspot/share/opto/loopopts.cpp | 45 +++++++++- ...stVerifyLoopOptimizationsHitsMemLimit.java | 6 +- .../assertion/TestAssertionPredicates.java | 13 +++ ...plicateBackedgeWithAssertionPredicate.java | 89 +++++++++++++++++++ 4 files changed, 149 insertions(+), 4 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/predicates/assertion/TestStressDuplicateBackedgeWithAssertionPredicate.java diff --git a/src/hotspot/share/opto/loopopts.cpp b/src/hotspot/share/opto/loopopts.cpp index 3ef6a085b1c..ee3f138b8af 100644 --- a/src/hotspot/share/opto/loopopts.cpp +++ b/src/hotspot/share/opto/loopopts.cpp @@ -4180,6 +4180,33 @@ bool PhaseIdealLoop::partial_peel( IdealLoopTree *loop, Node_List &old_new ) { return true; } +#ifdef ASSERT + +// Moves Template Assertion Predicates to a target loop by cloning and killing the old ones. The target loop is the +// original, not-cloned loop. This is currently only used with StressLoopBackedge which is a develop flag only and +// false with product builds. We can therefore guard it with an ifdef. More details can be found at the use-site. +class MoveAssertionPredicatesVisitor : public PredicateVisitor { + ClonePredicateToTargetLoop _clone_predicate_to_loop; + PhaseIdealLoop* const _phase; + +public: + MoveAssertionPredicatesVisitor(LoopNode* target_loop_head, + const NodeInSingleLoopBody &node_in_loop_body, + PhaseIdealLoop* phase) + : _clone_predicate_to_loop(target_loop_head, node_in_loop_body, phase), + _phase(phase) { + } + NONCOPYABLE(MoveAssertionPredicatesVisitor); + + using PredicateVisitor::visit; + + void visit(const TemplateAssertionPredicate& template_assertion_predicate) override { + _clone_predicate_to_loop.clone_template_assertion_predicate(template_assertion_predicate); + template_assertion_predicate.kill(_phase->igvn()); + } +}; +#endif // ASSERT + // Transform: // // loop<-----------------+ @@ -4248,6 +4275,7 @@ bool PhaseIdealLoop::duplicate_loop_backedge(IdealLoopTree *loop, Node_List &old IfNode* exit_test = nullptr; uint inner; float f; +#ifdef ASSERT if (StressDuplicateBackedge) { if (head->is_strip_mined()) { return false; @@ -4266,7 +4294,9 @@ bool PhaseIdealLoop::duplicate_loop_backedge(IdealLoopTree *loop, Node_List &old } inner = 1; - } else { + } else +#endif //ASSERT + { // Is the shape of the loop that of a counted loop... Node* back_control = loop_exit_control(head, loop); if (back_control == nullptr) { @@ -4457,6 +4487,19 @@ bool PhaseIdealLoop::duplicate_loop_backedge(IdealLoopTree *loop, Node_List &old } } +#ifdef ASSERT + if (StressDuplicateBackedge && head->is_CountedLoop()) { + // The Template Assertion Predicates from the old counted loop are now at the new outer loop - clone them to + // the inner counted loop and kill the old ones. We only need to do this with debug builds because + // StressDuplicateBackedge is a devlop flag and false by default. Without StressDuplicateBackedge 'head' will be a + // non-counted loop, and thus we have no Template Assertion Predicates above the old loop to move down. + PredicateIterator predicate_iterator(outer_head->in(LoopNode::EntryControl)); + NodeInSingleLoopBody node_in_body(this, loop); + MoveAssertionPredicatesVisitor move_assertion_predicates_visitor(head, node_in_body, this); + predicate_iterator.for_each(move_assertion_predicates_visitor); + } +#endif // ASSERT + C->set_major_progress(); C->print_method(PHASE_AFTER_DUPLICATE_LOOP_BACKEDGE, 4, outer_head); diff --git a/test/hotspot/jtreg/compiler/loopopts/TestVerifyLoopOptimizationsHitsMemLimit.java b/test/hotspot/jtreg/compiler/loopopts/TestVerifyLoopOptimizationsHitsMemLimit.java index a2834c26dcc..fbe69ad0e04 100644 --- a/test/hotspot/jtreg/compiler/loopopts/TestVerifyLoopOptimizationsHitsMemLimit.java +++ b/test/hotspot/jtreg/compiler/loopopts/TestVerifyLoopOptimizationsHitsMemLimit.java @@ -37,15 +37,15 @@ package compiler.loopopts; * -XX:CompileCommand=memlimit,compiler.loopopts.TestVerifyLoopOptimizationsHitsMemLimit::test,100M~crash * -XX:-TieredCompilation -Xcomp -XX:PerMethodTrapLimit=0 * -XX:+StressLoopPeeling -XX:+VerifyLoopOptimizations - * -XX:StressSeed=1870557292 + * -XX:StressSeed=1870557292 -XX:-StressDuplicateBackedge * compiler.loopopts.TestVerifyLoopOptimizationsHitsMemLimit * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions * -XX:CompileCommand=compileonly,compiler.loopopts.TestVerifyLoopOptimizationsHitsMemLimit::test * -XX:CompileCommand=memlimit,compiler.loopopts.TestVerifyLoopOptimizationsHitsMemLimit::test,100M~crash * -XX:-TieredCompilation -Xcomp -XX:PerMethodTrapLimit=0 - * -XX:+StressLoopPeeling -XX:+VerifyLoopOptimizations + * -XX:+StressLoopPeeling -XX:+VerifyLoopOptimizations -XX:-StressDuplicateBackedge * compiler.loopopts.TestVerifyLoopOptimizationsHitsMemLimit - * @run main compiler.loopopts.TestVerifyLoopOptimizationsHitsMemLimit + * @run main/othervm -XX:-StressDuplicateBackedge compiler.loopopts.TestVerifyLoopOptimizationsHitsMemLimit */ public class TestVerifyLoopOptimizationsHitsMemLimit { diff --git a/test/hotspot/jtreg/compiler/predicates/assertion/TestAssertionPredicates.java b/test/hotspot/jtreg/compiler/predicates/assertion/TestAssertionPredicates.java index 8f30dce15bc..c3ccf4eff43 100644 --- a/test/hotspot/jtreg/compiler/predicates/assertion/TestAssertionPredicates.java +++ b/test/hotspot/jtreg/compiler/predicates/assertion/TestAssertionPredicates.java @@ -144,6 +144,19 @@ * compiler.predicates.assertion.TestAssertionPredicates DataUpdate */ +/* + * @test id=DataUpdateZGC + * @key randomness + * @bug 8288981 8350577 0360510 + * @requires vm.compiler2.enabled + * @requires vm.gc.Z + * @run main/othervm -Xcomp -XX:+UnlockDiagnosticVMOptions -XX:+StressGCM -XX:+AbortVMOnCompilationFailure -XX:+UseZGC + * -XX:CompileCommand=compileonly,compiler.predicates.assertion.TestAssertionPredicates::* + * -XX:CompileCommand=dontinline,compiler.predicates.assertion.TestAssertionPredicates::* + * -XX:+IgnoreUnrecognizedVMOptions -XX:-KillPathsReachableByDeadTypeNode + * compiler.predicates.assertion.TestAssertionPredicates DataUpdate + */ + /* * @test id=CloneDown * @bug 8288981 8350577 diff --git a/test/hotspot/jtreg/compiler/predicates/assertion/TestStressDuplicateBackedgeWithAssertionPredicate.java b/test/hotspot/jtreg/compiler/predicates/assertion/TestStressDuplicateBackedgeWithAssertionPredicate.java new file mode 100644 index 00000000000..02082137bf0 --- /dev/null +++ b/test/hotspot/jtreg/compiler/predicates/assertion/TestStressDuplicateBackedgeWithAssertionPredicate.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2025, 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 8360510 + * @summary Test that StressDuplicateBackedge correctly clones Template Assertion Predicates to the inner counted loop. + * @run main/othervm -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:+StressDuplicateBackedge + * compiler.predicates.assertion.TestStressDuplicateBackedgeWithAssertionPredicate + * @run main compiler.predicates.assertion.TestStressDuplicateBackedgeWithAssertionPredicate + */ + +package compiler.predicates.assertion; + +public class TestStressDuplicateBackedgeWithAssertionPredicate { + static int[] iArr = new int[100]; + static int iFld; + static long lFld; + + public static void main(String[] strArr) { + for (int i = 0; i < 10000; i++) { + test(); + } + } + + static void test() { + // 5) Once the inner empty loop is removed (step 4), we can apply the "duplicate backedge + // optimization" to the initial outer counted loop which is now the only loop left. Note + // that we can do that even though it is a counted loop: This is stressed with + // StressDuplicateLoopBackedge. + // 6) We do the following "duplicate loop backedge" transformation with current mainline: + // + // Template Assertion + // Template Assertion Predicates + // Predicates | + // | ====> ... + // ... | + // | Loop # Outer Non-Counted Loop (newly added) + // CountedLoop | + // CountedLoop # Inner Counted Loop (old) + // + // 7) After the transformation, the Template Assertion Predicates are still at the Outer Non-Counted Loop. + // As a result, we find them to be useless in the next predicate elimination call with + // EliminateUselessPredicates because they cannot be found from the Inner Counted Loop (we stop at + // Loop which is not a predicate). However, we have verification code in place that checks that we + // can only find useless Template Assertion Predicates if the associated counted loop node is dead. + // This is not the case and we crash with an assertion failure. + // + // The fix is to move the Template Assertion Predicates to the Inner Counted Loop again. + for (int i = 0; i < 100; i++) { + // 3) Loop Predication will hoist this range checkout out of the loop with Template + // Assertion Predicates. + iArr[i] = 34; + + // 1) We need an inner empty loop to make sure the outer counter loop is not strip mined. + // Otherwise, we cannot apply the duplicate backedge optimization to the outer loop. + // 4) Found to be empty and removed. + for (int j = 0; j < 10; j++) {} + + // 2) We need some region inside the outer loop, otherwise, we cannot apply the duplicate + // backedge optimization. + if (i == 3) { + lFld = 34; + } else { + iFld = 2; + } + } + } +} From 5fe731d55a54ace42de4a15d612dba310de9d977 Mon Sep 17 00:00:00 2001 From: Saranya Natarajan Date: Wed, 26 Nov 2025 09:27:31 +0000 Subject: [PATCH 014/706] 8349835: C2: Simplify IGV property printing Reviewed-by: rcastanedalo, dfenacci, chagedorn --- src/hotspot/share/opto/idealGraphPrinter.cpp | 211 +++++++++---------- src/hotspot/share/opto/idealGraphPrinter.hpp | 3 +- 2 files changed, 98 insertions(+), 116 deletions(-) diff --git a/src/hotspot/share/opto/idealGraphPrinter.cpp b/src/hotspot/share/opto/idealGraphPrinter.cpp index 6a738878a1b..b28949e27c2 100644 --- a/src/hotspot/share/opto/idealGraphPrinter.cpp +++ b/src/hotspot/share/opto/idealGraphPrinter.cpp @@ -35,6 +35,96 @@ #ifndef PRODUCT +// Support for printing properties +class PrintProperties +{ +private: + IdealGraphPrinter* _printer; + +public: + PrintProperties(IdealGraphPrinter* printer) : _printer(printer) {} + void print_node_properties(Node* node); + void print_lrg_properties(const LRG& lrg, const char* buffer); + void print_property(int flag, const char* name); + void print_property(int flag, const char* name, const char* val); + void print_property(int flag, const char* name, int val); +}; + +void PrintProperties::print_node_properties(Node* node) { + const jushort flags = node->flags(); + print_property((flags & Node::Flag_is_Copy), "is_copy"); + print_property((flags & Node::Flag_rematerialize), "rematerialize"); + print_property((flags & Node::Flag_needs_anti_dependence_check), "needs_anti_dependence_check"); + print_property((flags & Node::Flag_is_macro), "is_macro"); + print_property((flags & Node::Flag_is_Con), "is_con"); + print_property((flags & Node::Flag_is_cisc_alternate), "is_cisc_alternate"); + print_property((flags & Node::Flag_is_dead_loop_safe), "is_dead_loop_safe"); + print_property((flags & Node::Flag_may_be_short_branch), "may_be_short_branch"); + print_property((flags & Node::Flag_has_call), "has_call"); + print_property((flags & Node::Flag_has_swapped_edges), "has_swapped_edges"); + Matcher* matcher = _printer->C->matcher(); + if (matcher != nullptr) { + print_property(matcher->is_shared(node),"is_shared"); + print_property(!(matcher->is_shared(node)), "is_shared", IdealGraphPrinter::FALSE_VALUE); + print_property(matcher->is_dontcare(node), "is_dontcare"); + print_property(!(matcher->is_dontcare(node)),"is_dontcare", IdealGraphPrinter::FALSE_VALUE); + Node* old = matcher->find_old_node(node); + if (old != nullptr) { + print_property(true, "old_node_idx", old->_idx); + } + } +} + +void PrintProperties::print_lrg_properties(const LRG &lrg, const char *buffer) { + print_property(true, "mask", buffer); + print_property(true, "mask_size", lrg.mask_size()); + if (lrg._degree_valid) { + print_property(true, "degree", lrg.degree()); + } + print_property(true, "num_regs", lrg.num_regs()); + print_property(true, "reg_pressure", lrg.reg_pressure()); + print_property(true, "cost", lrg._cost); + print_property(true, "area", lrg._area); + print_property(true, "score", lrg.score()); + print_property((lrg._risk_bias != 0), "risk_bias", lrg._risk_bias); + print_property((lrg._copy_bias != 0), "copy_bias", lrg._copy_bias); + print_property(lrg.is_singledef(), "is_singledef"); + print_property(lrg.is_multidef(), "is_multidef"); + print_property(lrg._is_oop, "is_oop"); + print_property(lrg._is_float, "is_float"); + print_property(lrg._is_vector, "is_vector"); + print_property(lrg._is_predicate, "is_predicate"); + print_property(lrg._is_scalable, "is_scalable"); + print_property(lrg._was_spilled1, "was_spilled1"); + print_property(lrg._was_spilled2, "was_spilled2"); + print_property(lrg._direct_conflict, "direct_conflict"); + print_property(lrg._fat_proj, "fat_proj"); + print_property(lrg._was_lo, "_was_lo"); + print_property(lrg._has_copy, "has_copy"); + print_property(lrg._at_risk, "at_risk"); + print_property(lrg._must_spill, "must_spill"); + print_property(lrg._is_bound, "is_bound"); + print_property((lrg._msize_valid && lrg._degree_valid && lrg.lo_degree()), "trivial"); +} + +void PrintProperties::print_property(int flag, const char* name) { + if (flag != 0) { + _printer->print_prop(name, IdealGraphPrinter::TRUE_VALUE); + } +} + +void PrintProperties::print_property(int flag, const char* name, const char* val) { + if (flag != 0) { + _printer->print_prop(name, val); + } +} + +void PrintProperties::print_property(int flag, const char* name, int val) { + if (flag != 0) { + _printer->print_prop(name, val); + } +} + // Constants // Keep consistent with Java constants const char *IdealGraphPrinter::INDENT = " "; @@ -522,54 +612,8 @@ void IdealGraphPrinter::visit_node(Node* n, bool edges) { print_prop("jvms", buffer); } - const jushort flags = node->flags(); - if (flags & Node::Flag_is_Copy) { - print_prop("is_copy", "true"); - } - if (flags & Node::Flag_rematerialize) { - print_prop("rematerialize", "true"); - } - if (flags & Node::Flag_needs_anti_dependence_check) { - print_prop("needs_anti_dependence_check", "true"); - } - if (flags & Node::Flag_is_macro) { - print_prop("is_macro", "true"); - } - if (flags & Node::Flag_is_Con) { - print_prop("is_con", "true"); - } - if (flags & Node::Flag_is_cisc_alternate) { - print_prop("is_cisc_alternate", "true"); - } - if (flags & Node::Flag_is_dead_loop_safe) { - print_prop("is_dead_loop_safe", "true"); - } - if (flags & Node::Flag_may_be_short_branch) { - print_prop("may_be_short_branch", "true"); - } - if (flags & Node::Flag_has_call) { - print_prop("has_call", "true"); - } - if (flags & Node::Flag_has_swapped_edges) { - print_prop("has_swapped_edges", "true"); - } - - if (C->matcher() != nullptr) { - if (C->matcher()->is_shared(node)) { - print_prop("is_shared", "true"); - } else { - print_prop("is_shared", "false"); - } - if (C->matcher()->is_dontcare(node)) { - print_prop("is_dontcare", "true"); - } else { - print_prop("is_dontcare", "false"); - } - Node* old = C->matcher()->find_old_node(node); - if (old != nullptr) { - print_prop("old_node_idx", old->_idx); - } - } + PrintProperties print_node(this); + print_node.print_node_properties(node); if (node->is_Proj()) { print_prop("con", (int)node->as_Proj()->_con); @@ -1145,73 +1189,10 @@ void IdealGraphPrinter::print(const char* name, Node* node, GrowableArray { - private: + friend class PrintProperties; +private: static const char *INDENT; static const char *TOP_ELEMENT; static const char *GROUP_ELEMENT; From 5291e1c1e1ddc19d814dbdb3a981049fe40575ea Mon Sep 17 00:00:00 2001 From: Stefan Karlsson Date: Wed, 26 Nov 2025 09:29:55 +0000 Subject: [PATCH 015/706] 8372513: Shenandoah: ShenandoahMaxRegionSize can produce an unaligned heap alignment Reviewed-by: jsikstro, eosterlund, shade --- .../share/gc/shenandoah/shenandoahArguments.cpp | 3 ++- src/hotspot/share/runtime/arguments.cpp | 1 + .../gc/shenandoah/options/TestRegionSizeArgs.java | 11 +++++++++++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahArguments.cpp b/src/hotspot/share/gc/shenandoah/shenandoahArguments.cpp index a7cf8e638dd..c1fa4b964b7 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahArguments.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahArguments.cpp @@ -37,6 +37,7 @@ #include "runtime/globals_extension.hpp" #include "runtime/java.hpp" #include "utilities/defaultStream.hpp" +#include "utilities/powerOfTwo.hpp" void ShenandoahArguments::initialize() { #if !(defined AARCH64 || defined AMD64 || defined PPC64 || defined RISCV64) @@ -205,7 +206,7 @@ void ShenandoahArguments::initialize() { } size_t ShenandoahArguments::conservative_max_heap_alignment() { - size_t align = ShenandoahMaxRegionSize; + size_t align = next_power_of_2(ShenandoahMaxRegionSize); if (UseLargePages) { align = MAX2(align, os::large_page_size()); } diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index 55ee7641a5f..ff1de899bdd 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -1482,6 +1482,7 @@ void Arguments::set_conservative_max_heap_alignment() { os::vm_allocation_granularity(), os::max_page_size(), GCArguments::compute_heap_alignment()); + assert(is_power_of_2(_conservative_max_heap_alignment), "Expected to be a power-of-2"); } jint Arguments::set_ergonomics_flags() { diff --git a/test/hotspot/jtreg/gc/shenandoah/options/TestRegionSizeArgs.java b/test/hotspot/jtreg/gc/shenandoah/options/TestRegionSizeArgs.java index a8d5155584b..80962f0ffa6 100644 --- a/test/hotspot/jtreg/gc/shenandoah/options/TestRegionSizeArgs.java +++ b/test/hotspot/jtreg/gc/shenandoah/options/TestRegionSizeArgs.java @@ -192,6 +192,17 @@ public class TestRegionSizeArgs { output.shouldHaveExitValue(0); } + // This used to assert that _conservative_max_heap_alignment is not a power-of-2. + { + OutputAnalyzer output = ProcessTools.executeLimitedTestJava("-XX:+UnlockExperimentalVMOptions", + "-XX:+UseShenandoahGC", + "-Xms100m", + "-Xmx1g", + "-XX:ShenandoahMaxRegionSize=33m", + "-version"); + output.shouldHaveExitValue(0); + } + } private static void testMaxRegionSize() throws Exception { From ac046628edaee66d1469c49864b70bdefee6570e Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Wed, 26 Nov 2025 10:06:51 +0000 Subject: [PATCH 016/706] 8372336: javac fails with an exception when a class is missing while evaluating conditional expression Reviewed-by: vromero --- .../com/sun/tools/javac/comp/Resolve.java | 7 +- .../tools/javac/recovery/AttrRecovery.java | 103 +++++++++++++++++- 2 files changed, 108 insertions(+), 2 deletions(-) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java index eea766f57c1..07f2a742bcb 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java @@ -2810,7 +2810,12 @@ public class Resolve { Symbol resolveQualifiedMethod(DiagnosticPosition pos, Env env, Symbol location, Type site, Name name, List argtypes, List typeargtypes) { - return resolveQualifiedMethod(new MethodResolutionContext(), pos, env, location, site, name, argtypes, typeargtypes); + try { + return resolveQualifiedMethod(new MethodResolutionContext(), pos, env, location, site, name, argtypes, typeargtypes); + } catch (CompletionFailure cf) { + chk.completionError(pos, cf); + return methodNotFound.access(name, site.tsym); + } } private Symbol resolveQualifiedMethod(MethodResolutionContext resolveContext, DiagnosticPosition pos, Env env, diff --git a/test/langtools/tools/javac/recovery/AttrRecovery.java b/test/langtools/tools/javac/recovery/AttrRecovery.java index f8d02d0ddf1..9a37ce60654 100644 --- a/test/langtools/tools/javac/recovery/AttrRecovery.java +++ b/test/langtools/tools/javac/recovery/AttrRecovery.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8301580 8322159 8333107 8332230 8338678 8351260 8366196 + * @bug 8301580 8322159 8333107 8332230 8338678 8351260 8366196 8372336 * @summary Verify error recovery w.r.t. Attr * @library /tools/lib * @modules jdk.compiler/com.sun.tools.javac.api @@ -32,11 +32,14 @@ * @run main AttrRecovery */ +import com.sun.source.tree.MemberReferenceTree; +import com.sun.source.tree.MethodInvocationTree; import com.sun.source.tree.VariableTree; import com.sun.source.util.TaskEvent; import com.sun.source.util.TaskListener; import com.sun.source.util.TreePathScanner; import com.sun.source.util.Trees; +import java.nio.file.Files; import java.nio.file.Path; import java.util.IdentityHashMap; import java.util.List; @@ -394,4 +397,102 @@ public class AttrRecovery extends TestRunner { error("Expected: " + expected + ", but got: " + actual); } } + + @Test //JDK-8372336 + public void testCompletionFailureNoBreakInvocation() throws Exception { + Path curPath = Path.of("."); + Path lib = curPath.resolve("lib"); + Path classes = lib.resolve("classes"); + Files.createDirectories(classes); + new JavacTask(tb) + .outdir(classes) + .sources(""" + package test; + public class Intermediate extends Base {} + """, + """ + package test; + public class Base { + public int get() { + return -1; + } + } + """) + .run() + .writeAll(); + + Files.delete(classes.resolve("test").resolve("Base.class")); + + record TestCase(String code, String... expectedErrors) {} + TestCase[] testCases = new TestCase[] { + new TestCase(""" + package test; + public class Test { + private void test(Intermediate i) { + int j = i != null ? i.get() : -1; + } + } + """, + "Test.java:4:30: compiler.err.cant.access: test.Base, (compiler.misc.class.file.not.found: test.Base)", + "1 error"), + new TestCase(""" + package test; + public class Test { + private void test(Intermediate i) { + i.get(); + } + } + """, + "Test.java:4:10: compiler.err.cant.access: test.Base, (compiler.misc.class.file.not.found: test.Base)", + "1 error") + }; + + for (TestCase tc : testCases) { + List actual = new JavacTask(tb) + .options("-XDrawDiagnostics", "-XDdev") + .classpath(classes) + .sources(tc.code()) + .outdir(curPath) + .callback(task -> { + task.addTaskListener(new TaskListener() { + @Override + public void finished(TaskEvent e) { + if (e.getKind() != TaskEvent.Kind.ANALYZE) { + return ; + } + Trees trees = Trees.instance(task); + new TreePathScanner() { + @Override + public Void visitMethodInvocation(MethodInvocationTree node, Void p) { + if (!node.toString().contains("super")) { + verifyElement(); + } + return super.visitMethodInvocation(node, p); + } + @Override + public Void visitMemberReference(MemberReferenceTree node, Void p) { + verifyElement(); + return super.visitMemberReference(node, p); + } + private void verifyElement() { + Element el = trees.getElement(getCurrentPath()); + if (!el.getSimpleName().contentEquals("get")) { + error("Expected good Element, but got: " + el); + } + } + }.scan(e.getCompilationUnit(), null); + } + }); + }) + .run(Expect.FAIL) + .writeAll() + .getOutputLines(OutputKind.DIRECT); + + List expected = List.of(tc.expectedErrors); + + if (!Objects.equals(actual, expected)) { + error("Expected: " + expected + ", but got: " + actual); + } + } + } } From 4ae2f31f3d2027daa0a5ccba6180e7bb27413aa5 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Wed, 26 Nov 2025 12:49:42 +0000 Subject: [PATCH 017/706] 8371626: [linux] use icf=all for linking libraries Reviewed-by: goetz, erikj --- make/autoconf/flags-ldflags.m4 | 7 +++++++ make/autoconf/toolchain.m4 | 1 + 2 files changed, 8 insertions(+) diff --git a/make/autoconf/flags-ldflags.m4 b/make/autoconf/flags-ldflags.m4 index ad131b20e27..572790b567b 100644 --- a/make/autoconf/flags-ldflags.m4 +++ b/make/autoconf/flags-ldflags.m4 @@ -50,7 +50,14 @@ AC_DEFUN([FLAGS_SETUP_LDFLAGS_HELPER], # add -z,relro (mark relocations read only) for all libs # add -z,now ("full relro" - more of the Global Offset Table GOT is marked read only) # add --no-as-needed to disable default --as-needed link flag on some GCC toolchains + # add --icf=all (Identical Code Folding — merges identical functions) BASIC_LDFLAGS="-Wl,-z,defs -Wl,-z,relro -Wl,-z,now -Wl,--no-as-needed -Wl,--exclude-libs,ALL" + if test "x$LINKER_TYPE" = "xgold"; then + if test x$DEBUG_LEVEL = xrelease; then + BASIC_LDFLAGS="$BASIC_LDFLAGS -Wl,--icf=all" + fi + fi + # Linux : remove unused code+data in link step if test "x$ENABLE_LINKTIME_GC" = xtrue; then if test "x$OPENJDK_TARGET_CPU" = xs390x; then diff --git a/make/autoconf/toolchain.m4 b/make/autoconf/toolchain.m4 index 4662c62d901..15210efe4a7 100644 --- a/make/autoconf/toolchain.m4 +++ b/make/autoconf/toolchain.m4 @@ -516,6 +516,7 @@ AC_DEFUN([TOOLCHAIN_EXTRACT_LD_VERSION], if [ [[ "$LINKER_VERSION_STRING" == *gold* ]] ]; then [ LINKER_VERSION_NUMBER=`$ECHO $LINKER_VERSION_STRING | \ $SED -e 's/.* \([0-9][0-9]*\(\.[0-9][0-9]*\)*\).*) .*/\1/'` ] + LINKER_TYPE=gold else [ LINKER_VERSION_NUMBER=`$ECHO $LINKER_VERSION_STRING | \ $SED -e 's/.* \([0-9][0-9]*\(\.[0-9][0-9]*\)*\).*/\1/'` ] From c146805da5708b479bf8dd0180acd06657b72788 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20H=C3=BCbner?= Date: Wed, 26 Nov 2025 13:05:41 +0000 Subject: [PATCH 018/706] 8368551: Core dump warning may be confusing Reviewed-by: stuefe, dholmes --- src/hotspot/os/linux/os_linux.cpp | 2 +- src/hotspot/os/posix/os_posix.cpp | 39 ++++++++++++++----- .../TestCrashOnOutOfMemoryError.java | 6 +-- 3 files changed, 33 insertions(+), 14 deletions(-) diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index 30033903ca3..efeeec6f484 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -5163,7 +5163,7 @@ int os::get_core_path(char* buffer, size_t bufferSize) { if (core_pattern[0] == '|') { written = jio_snprintf(buffer, bufferSize, - "\"%s\" (or dumping to %s/core.%d)", + "\"%s\" (alternatively, falling back to %s/core.%d)", &core_pattern[1], p, current_process_id()); } else if (pid_pos != nullptr) { *pid_pos = '\0'; diff --git a/src/hotspot/os/posix/os_posix.cpp b/src/hotspot/os/posix/os_posix.cpp index 1a04cbba0de..8f1f07dd055 100644 --- a/src/hotspot/os/posix/os_posix.cpp +++ b/src/hotspot/os/posix/os_posix.cpp @@ -108,41 +108,60 @@ size_t os::_os_min_stack_allowed = PTHREAD_STACK_MIN; // Check core dump limit and report possible place where core can be found void os::check_core_dump_prerequisites(char* buffer, size_t bufferSize, bool check_only) { + stringStream buf(buffer, bufferSize); if (!FLAG_IS_DEFAULT(CreateCoredumpOnCrash) && !CreateCoredumpOnCrash) { - jio_snprintf(buffer, bufferSize, "CreateCoredumpOnCrash is disabled from command line"); - VMError::record_coredump_status(buffer, false); + buf.print("CreateCoredumpOnCrash is disabled from command line"); + VMError::record_coredump_status(buf.freeze(), false); } else { struct rlimit rlim; bool success = true; bool warn = true; char core_path[PATH_MAX]; if (get_core_path(core_path, PATH_MAX) <= 0) { - jio_snprintf(buffer, bufferSize, "core.%d (may not exist)", current_process_id()); + // In the warning message, let the user know. + if (check_only) { + buf.print("the core path couldn't be determined. It commonly defaults to "); + } + buf.print("core.%d%s", current_process_id(), check_only ? "" : " (may not exist)"); #ifdef LINUX } else if (core_path[0] == '"') { // redirect to user process - jio_snprintf(buffer, bufferSize, "Core dumps may be processed with %s", core_path); + if (check_only) { + buf.print("core dumps may be further processed by the following: "); + } else { + buf.print("Determined by the following: "); + } + buf.print("%s", core_path); #endif } else if (getrlimit(RLIMIT_CORE, &rlim) != 0) { - jio_snprintf(buffer, bufferSize, "%s (may not exist)", core_path); + if (check_only) { + buf.print("the rlimit couldn't be determined. If resource limits permit, the core dump will be located at "); + } + buf.print("%s%s", core_path, check_only ? "" : " (may not exist)"); } else { switch(rlim.rlim_cur) { case RLIM_INFINITY: - jio_snprintf(buffer, bufferSize, "%s", core_path); + buf.print("%s", core_path); warn = false; break; case 0: - jio_snprintf(buffer, bufferSize, "Core dumps have been disabled. To enable core dumping, try \"ulimit -c unlimited\" before starting Java again"); + buf.print("%s dumps have been disabled. To enable core dumping, try \"ulimit -c unlimited\" before starting Java again", check_only ? "core" : "Core"); success = false; break; default: - jio_snprintf(buffer, bufferSize, "%s (max size " UINT64_FORMAT " k). To ensure a full core dump, try \"ulimit -c unlimited\" before starting Java again", core_path, uint64_t(rlim.rlim_cur) / K); + if (check_only) { + buf.print("core dumps are constrained "); + } else { + buf.print( "%s ", core_path); + } + buf.print( "(max size " UINT64_FORMAT " k). To ensure a full core dump, try \"ulimit -c unlimited\" before starting Java again", uint64_t(rlim.rlim_cur) / K); break; } } + const char* result = buf.freeze(); if (!check_only) { - VMError::record_coredump_status(buffer, success); + VMError::record_coredump_status(result, success); } else if (warn) { - warning("CreateCoredumpOnCrash specified, but %s", buffer); + warning("CreateCoredumpOnCrash specified, but %s", result); } } } diff --git a/test/hotspot/jtreg/runtime/ErrorHandling/TestCrashOnOutOfMemoryError.java b/test/hotspot/jtreg/runtime/ErrorHandling/TestCrashOnOutOfMemoryError.java index 0be39d22ebe..26d1f726feb 100644 --- a/test/hotspot/jtreg/runtime/ErrorHandling/TestCrashOnOutOfMemoryError.java +++ b/test/hotspot/jtreg/runtime/ErrorHandling/TestCrashOnOutOfMemoryError.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, 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,8 +72,8 @@ public class TestCrashOnOutOfMemoryError { # # JRE version: OpenJDK Runtime Environment (9.0) (build 1.9.0-internal-debug-cheleswer_2015_10_20_14_32-b00) # Java VM: OpenJDK 64-Bit Server VM (1.9.0-internal-debug-cheleswer_2015_10_20_14_32-b00, mixed mode, tiered, compressed oops, serial gc, linux-amd64) - # Core dump will be written. Default location: Core dumps may be processed with "/usr/share/apport/apport %p %s %c %P" (or dumping to - /home/cheleswer/Desktop/core.6212) + # Core dump will be written. Default location: Determined by the following: + "/usr/share/apport/apport %p %s %c %P" (alternatively, falling back to /home/cheleswer/Desktop/core.6212) # # An error report file with more information is saved as: # /home/cheleswer/Desktop/hs_err_pid6212.log From 74354f23dbb0fc852d216c8f1d3e5f80d406cfc6 Mon Sep 17 00:00:00 2001 From: Christian Hagedorn Date: Wed, 26 Nov 2025 13:25:57 +0000 Subject: [PATCH 019/706] 8372585: TestVerifyLoopOptimizationsHitsMemLimit fails with product builds Reviewed-by: rcastanedalo, thartmann --- .../loopopts/TestVerifyLoopOptimizationsHitsMemLimit.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/hotspot/jtreg/compiler/loopopts/TestVerifyLoopOptimizationsHitsMemLimit.java b/test/hotspot/jtreg/compiler/loopopts/TestVerifyLoopOptimizationsHitsMemLimit.java index fbe69ad0e04..90a8287004f 100644 --- a/test/hotspot/jtreg/compiler/loopopts/TestVerifyLoopOptimizationsHitsMemLimit.java +++ b/test/hotspot/jtreg/compiler/loopopts/TestVerifyLoopOptimizationsHitsMemLimit.java @@ -45,7 +45,8 @@ package compiler.loopopts; * -XX:-TieredCompilation -Xcomp -XX:PerMethodTrapLimit=0 * -XX:+StressLoopPeeling -XX:+VerifyLoopOptimizations -XX:-StressDuplicateBackedge * compiler.loopopts.TestVerifyLoopOptimizationsHitsMemLimit - * @run main/othervm -XX:-StressDuplicateBackedge compiler.loopopts.TestVerifyLoopOptimizationsHitsMemLimit + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-StressDuplicateBackedge + * compiler.loopopts.TestVerifyLoopOptimizationsHitsMemLimit */ public class TestVerifyLoopOptimizationsHitsMemLimit { From 85d4f551b1f82f1b43155a4ac3c5026ac580410e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Walln=C3=B6fer?= Date: Wed, 26 Nov 2025 13:36:58 +0000 Subject: [PATCH 020/706] 8372055: Fragment link tag does not work in package info Reviewed-by: liach --- .../com/sun/tools/javac/api/JavacTrees.java | 18 ++- .../formats/html/taglets/LinkTaglet.java | 5 + .../jdk/javadoc/internal/doclint/Checker.java | 15 +- .../testSeeLinkAnchor/TestSeeLinkAnchor.java | 139 ++++++++++++++++-- 4 files changed, 156 insertions(+), 21 deletions(-) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTrees.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTrees.java index f933ef36565..22ee2393a02 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTrees.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTrees.java @@ -413,7 +413,18 @@ public class JavacTrees extends DocTrees { } if (ref.qualifierExpression == null) { - tsym = env.enclClass.sym; + // Resolve target for unqualified reference based on declaring element + tsym = switch (path.getLeaf().getKind()) { + case PACKAGE -> env.toplevel.packge; + case MODULE -> env.toplevel.modle; + case COMPILATION_UNIT -> + // Treat unqualified reference in legacy package.html as package reference. + // Unqualified references in doc-files only need to work locally, so null is fine. + path.getCompilationUnit().getSourceFile().isNameCompatible("package", JavaFileObject.Kind.HTML) + ? env.toplevel.packge + : null; + default -> env.enclClass.sym; // Class or class member reference + }; memberName = (Name) ref.memberName; } else { // Check if qualifierExpression is a type or package, using the methods javac provides. @@ -470,8 +481,11 @@ public class JavacTrees extends DocTrees { } } - if (memberName == null) + if (memberName == null) { return tsym; + } else if (tsym == null || tsym.getKind() == ElementKind.PACKAGE || tsym.getKind() == ElementKind.MODULE) { + return null; // Non-null member name in non-class context + } if (tsym.type.isPrimitive()) { return null; diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/LinkTaglet.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/LinkTaglet.java index 914f70ced47..62b003afd96 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/LinkTaglet.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/LinkTaglet.java @@ -50,6 +50,7 @@ import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper; import jdk.javadoc.internal.doclets.toolkit.util.DocLink; import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable; import jdk.javadoc.internal.html.Content; +import jdk.javadoc.internal.html.HtmlId; import jdk.javadoc.internal.html.HtmlTree; import jdk.javadoc.internal.html.Text; @@ -159,6 +160,10 @@ public class LinkTaglet extends BaseTaglet { Optional.of(refSignature)); } refFragment = refFragment.substring(1); + if (ref == null && refSignature.startsWith("##")) { + // Unqualified local anchor link in doc-file + return htmlWriter.links.createLink(HtmlId.of(refFragment), labelContent); + } } if (refClass == null) { ModuleElement refModule = ch.getReferencedModule(ref); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/Checker.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/Checker.java index 3669c800a8e..43405c3ebb0 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/Checker.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/Checker.java @@ -1004,12 +1004,15 @@ public class Checker extends DocTreePathScanner { @Override @DefinedBy(Api.COMPILER_TREE) public Void visitReference(ReferenceTree tree, Void ignore) { - Element e = env.trees.getElement(getCurrentPath()); - if (e == null) { - reportBadReference(tree); - } else if ((inLink || inSee) - && e.getKind() == ElementKind.CLASS && e.asType().getKind() != TypeKind.DECLARED) { - reportBadReference(tree); + // Exclude same-file anchor links from reference checks + if (!tree.getSignature().startsWith("##")) { + Element e = env.trees.getElement(getCurrentPath()); + if (e == null) { + reportBadReference(tree); + } else if ((inLink || inSee) + && e.getKind() == ElementKind.CLASS && e.asType().getKind() != TypeKind.DECLARED) { + reportBadReference(tree); + } } return super.visitReference(tree, ignore); } diff --git a/test/langtools/jdk/javadoc/doclet/testSeeLinkAnchor/TestSeeLinkAnchor.java b/test/langtools/jdk/javadoc/doclet/testSeeLinkAnchor/TestSeeLinkAnchor.java index 626e4870401..f59de2e5e70 100644 --- a/test/langtools/jdk/javadoc/doclet/testSeeLinkAnchor/TestSeeLinkAnchor.java +++ b/test/langtools/jdk/javadoc/doclet/testSeeLinkAnchor/TestSeeLinkAnchor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, 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 @@ -77,7 +77,11 @@ public class TestSeeLinkAnchor extends JavadocTester { """ Link to heading in package p2""", """ - Plain link to sub heading above""", + Plain link to heading in Class2""", + """ +

  • unqualified link to heading above
  • +
  • qualified link to heading above
  • + """, """
  • See main heading in p2.Class2
  • See heading in p2
  • @@ -89,13 +93,19 @@ public class TestSeeLinkAnchor extends JavadocTester { Plain link to Class1."""); checkOrder("p2/package-summary.html", """ - See sub heading in p2.Class2"""); +
  • See sub heading in p2.Class2
  • +
  • local qualified link
  • +
  • local unqualified link
  • + """); checkOrder("p2/doc-files/file.html", """ Plain link to heading in p1.ClassA.""", """ - See main heading in p2.ClassB"""); +
  • See main heading in p2.ClassB
  • +
  • package link
  • +
  • local anchor
  • + """); } @Test @@ -112,12 +122,57 @@ public class TestSeeLinkAnchor extends JavadocTester { checkOrder("m1/module-summary.html", """ See main heading in Class2"""); + checkOrder("m1/com/m1/package-summary.html", + """ +
    Link to local anchor. + """, + """ + package-anchor
    + """, + """ + + """); checkOrder("m1/com/m1/Class1.html", """ sub heading in Class2.""", """ -
  • See main heading in Class2
  • -
  • See heading in module m1
  • +

    More links: +

    + """, + """ +
    See Also:
    +
    + + """); + checkOrder("m2/module-summary.html", + """ + Plain link to local anchor."""); + checkOrder("m2/com/m2/package-summary.html", + """ + Plain link to local anchor. + """, + """ + """); checkOrder("m2/com/m2/Class2.html", """ @@ -126,9 +181,14 @@ public class TestSeeLinkAnchor extends JavadocTester { Plain link to sub heading above."""); checkOrder("m2/doc-files/file.html", """ - Link to heading in Class2.""", + Link to heading in Class2. + Plain link to local anchor. + """, """ -
  • Heading in module m1
  • """); +
      +
    • Heading in module m1
    • +
    • See local anchor
    • + """); } @Test @@ -197,7 +257,9 @@ public class TestSeeLinkAnchor extends JavadocTester {

      Class1 Main

      Link to {@link p2##package-p2-heading heading in package p2}

      Class1 Sub

      - Plain link to {@linkplain p2.Class2##class2-sub-heading sub heading above} + Plain link to {@linkplain p2.Class2##class2-sub-heading heading in Class2} + @see ##main unqualified link to heading above + @see p1.Class1##main qualified link to heading above """) .addMembers(mb) .write(src); @@ -216,6 +278,8 @@ public class TestSeeLinkAnchor extends JavadocTester { *

      Package p2

      * * @see p2.Class2##class2-sub-heading See sub heading in p2.Class2 + * @see p2##package-p2-heading local qualified link + * @see ##package-p2-heading local unqualified link */ package p2; """); @@ -227,6 +291,8 @@ public class TestSeeLinkAnchor extends JavadocTester {

      Package p2 HTML File

      Plain link to {@linkplain p1.Class1##main heading in p1.ClassA}. @see p2.Class2##class2main See main heading in p2.ClassB + @see p2##package-p2-heading package link + @see ##package-p2-html-file-heading local anchor """); @@ -235,13 +301,33 @@ public class TestSeeLinkAnchor extends JavadocTester { void generateModuleSources() throws Exception { new ModuleBuilder(tb, "m1") .exports("com.m1") + .requires("m2") .classes(""" package com.m1; + + import com.m2.Class2; + /** * Link to the {@link m2/com.m2.Class2##sub sub heading in Class2}. * - * @see m2/com.m2.Class2##main-heading See main heading in Class2 - * @see m1/##module-m1-heading See heading in module m1 + *

      More links: + *

        + *
      • {@linkplain com.m2.Class2##sub qualified remote link}
      • + *
      • {@linkplain Class2##sub unqualified remote link}
      • + *
      • {@linkplain m1/##module-m1-heading module anchor link}
      • + *
      • {@linkplain com.m1##package-anchor package anchor link}
      • + *
      • {@linkplain Class1##class1-anchor qualified local anchor link}
      • + *
      • {@linkplain ##class1-anchor unqualified local anchor link}
      • + *
      + * + *

      {@index class1-anchor} + * + * @see com.m2.Class2##main-heading qualified remote link + * @see Class2##main-heading unqualified remote link + * @see m1/##module-m1-heading module anchor link + * @see com.m1##package-anchor package anchor link + * @see Class1##class1-anchor qualified local anchor link + * @see ##class1-anchor unqualified local anchor link */ public class Class1 {} """) @@ -250,6 +336,17 @@ public class TestSeeLinkAnchor extends JavadocTester { @see m2/com.m2.Class2##main-heading See main heading in Class2 """) .write(src); + tb.writeFile(src.resolve("m1/com/m1/package-info.java"), """ + /** + * {@linkplain ##package-anchor Link to local anchor}. + * {@index package-anchor} + * + * @see ##package-anchor unqualified local anchor + * @see com.m1##package-anchor qualified local anchor + * @see m1/com.m1##package-anchor fully qualified local anchor + */ + package com.m1; + """); new ModuleBuilder(tb, "m2") .exports("com.m2") .classes(""" @@ -264,14 +361,30 @@ public class TestSeeLinkAnchor extends JavadocTester { public class Class2 {} """) .write(src); + tb.writeFile(src.resolve("m2/com/m2/package.html"), """ + + Package com.m2 + + {@linkplain ##pkg-heading Plain link to local anchor}. + +

      Package com.m2

      + + @see ##pkg-heading See local anchor + + + """); Path docFiles = src.resolve("m2").resolve("doc-files"); tb.writeFile(docFiles.resolve("file.html"), """ Module m2 HTML File -

      Module m2 HTML File

      + +

      Module m2 HTML File

      Link to {@link com.m2.Class2##main-heading heading in Class2}. + {@linkplain ##docfile-heading Plain link to local anchor}. + @see m1/##module-m1-heading Heading in module m1 + @see ##docfile-heading See local anchor """); @@ -297,4 +410,4 @@ public class TestSeeLinkAnchor extends JavadocTester { """) .write(src); } -} \ No newline at end of file +} From 0a3809f0be94c92c2c46f00fe5ff981afdd55cf0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Walln=C3=B6fer?= Date: Wed, 26 Nov 2025 14:07:06 +0000 Subject: [PATCH 021/706] 8369531: Wrong tooltip used in external class links Reviewed-by: liach --- .../formats/html/HtmlDocletWriter.java | 7 +- .../doclets/formats/html/HtmlLinkFactory.java | 4 +- .../doclets/formats/html/markup/Links.java | 4 +- .../html/resources/standard.properties | 1 - .../html/resources/standard_de.properties | 1 - .../html/resources/standard_ja.properties | 1 - .../html/resources/standard_zh_CN.properties | 1 - .../TestClassCrossReferences.java | 39 ++++---- .../TestDocRootInlineTag.java | 6 +- .../TestExternalOverriddenMethod.java | 18 ++-- .../TestGenericTypeLink.java | 91 +++++++++---------- .../doclet/testLinkOption/TestLinkOption.java | 41 ++++----- .../TestLinkOptionWithAutomaticModule.java | 8 +- .../TestLinkOptionWithModule.java | 14 +-- .../testLinkOption/TestRedirectLinks.java | 9 +- .../testLinkPlatform/TestLinkPlatform.java | 40 ++++---- .../TestLinkTagletWithModule.java | 23 ++--- .../testMarkdown/TestMarkdownLinks.java | 12 +-- .../doclet/testModules/TestModules.java | 4 +- .../doclet/testPreview/TestPreview.java | 6 +- .../testSeeTag/TestSeeTagWithModule.java | 22 ++--- .../testSnippetTag/TestSnippetMarkup.java | 2 +- .../testTitleInHref/TestTitleInHref.java | 2 +- 23 files changed, 171 insertions(+), 185 deletions(-) diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java index 6896b86279f..1f2c4d97dd3 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java @@ -908,12 +908,13 @@ public abstract class HtmlDocletWriter { * @param refMemName the name of the member being referenced. This should * be null or empty string if no member is being referenced. * @param label the label for the external link. + * @param title the title for the link * @param style optional style for the link. * @param code true if the label should be code font. * @return the link */ public Content getCrossClassLink(TypeElement classElement, String refMemName, - Content label, HtmlStyle style, boolean code) { + Content label, String title, HtmlStyle style, boolean code) { if (classElement != null) { String className = utils.getSimpleName(classElement); PackageElement packageElement = utils.containingPackage(classElement); @@ -931,9 +932,7 @@ public abstract class HtmlDocletWriter { DocLink link = configuration.extern.getExternalLink(packageElement, pathToRoot, className + ".html", refMemName); return links.createLink(link, - (label == null) || label.isEmpty() ? defaultLabel : label, style, - resources.getText("doclet.Href_Class_Or_Interface_Title", - getLocalizedPackageName(packageElement)), true); + (label == null) || label.isEmpty() ? defaultLabel : label, style, title, true); } } return null; diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlLinkFactory.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlLinkFactory.java index 4dbbd5e172a..cb8b3dbfd40 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlLinkFactory.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlLinkFactory.java @@ -305,7 +305,7 @@ public class HtmlLinkFactory { } else { Content crossLink = m_writer.getCrossClassLink( typeElement, linkInfo.getFragment(), - label, linkInfo.getStyle(), true); + label, linkInfo.getTitle(), linkInfo.getStyle(), true); if (crossLink != null) { link.add(crossLink); addSuperscript(link, flags, null, typeElement, previewTarget, restrictedTarget); @@ -361,7 +361,7 @@ public class HtmlLinkFactory { if (fileName != null) { return m_writer.links.createLink(fileName.fragment(id.name()), label); } else if (typeElement != null) { - return (m_writer.getCrossClassLink(typeElement, id.name(), label, null, false)); + return (m_writer.getCrossClassLink(typeElement, id.name(), label, null, null, false)); } else { return label; } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Links.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Links.java index 0af29135654..285ab260e0e 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Links.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Links.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, 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 @@ -197,7 +197,7 @@ public class Links { if (style != null) { l.setStyle(style); } - if (title != null && title.length() != 0) { + if (title != null && !title.isEmpty()) { l.put(HtmlAttr.TITLE, title); } if (isExternal) { diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard.properties b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard.properties index df3c2fc3a53..4366295477b 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard.properties +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard.properties @@ -51,7 +51,6 @@ doclet.Href_Annotation_Interface_Title=annotation interface in {0} doclet.Href_Enum_Title=enum in {0} doclet.Href_Enum_Class_Title=enum class in {0} doclet.Href_Type_Param_Title=type parameter in {0} -doclet.Href_Class_Or_Interface_Title=class or interface in {0} doclet.Summary=Summary: doclet.Detail=Detail: doclet.Module_Sub_Nav=Module: diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard_de.properties b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard_de.properties index 2669aa9bdc0..4cbb4b97774 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard_de.properties +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard_de.properties @@ -51,7 +51,6 @@ doclet.Href_Annotation_Interface_Title=Annotationsschnittstelle in {0} doclet.Href_Enum_Title=Enum in {0} doclet.Href_Enum_Class_Title=Enum-Klasse in {0} doclet.Href_Type_Param_Title=Typparameter in {0} -doclet.Href_Class_Or_Interface_Title=Klasse oder Schnittstelle in {0} doclet.Summary=Übersicht: doclet.Detail=Details: doclet.Module_Sub_Nav=Modul: diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard_ja.properties b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard_ja.properties index 1694dc980bc..2151b3f4a2e 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard_ja.properties +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard_ja.properties @@ -51,7 +51,6 @@ doclet.Href_Annotation_Interface_Title={0}内の注釈インタフェース doclet.Href_Enum_Title={0}内の列挙型 doclet.Href_Enum_Class_Title={0}の列挙クラス doclet.Href_Type_Param_Title={0}内の型パラメータ -doclet.Href_Class_Or_Interface_Title={0}内のクラスまたはインタフェース doclet.Summary=概要: doclet.Detail=詳細: doclet.Module_Sub_Nav=モジュール: diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard_zh_CN.properties b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard_zh_CN.properties index 8881171351e..66620d158bb 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard_zh_CN.properties +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard_zh_CN.properties @@ -51,7 +51,6 @@ doclet.Href_Annotation_Interface_Title={0} 中的批注接口 doclet.Href_Enum_Title={0}中的枚举 doclet.Href_Enum_Class_Title={0} 中的枚举类 doclet.Href_Type_Param_Title={0}中的类型参数 -doclet.Href_Class_Or_Interface_Title={0}中的类或接口 doclet.Summary=概要: doclet.Detail=详细资料: doclet.Module_Sub_Nav=模块: diff --git a/test/langtools/jdk/javadoc/doclet/testClassCrossReferences/TestClassCrossReferences.java b/test/langtools/jdk/javadoc/doclet/testClassCrossReferences/TestClassCrossReferences.java index 982e38dafaa..1e9461454f7 100644 --- a/test/langtools/jdk/javadoc/doclet/testClassCrossReferences/TestClassCrossReferences.java +++ b/test/langtools/jdk/javadoc/doclet/testClassCrossReferences/TestClassCrossReferences.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2025, 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,7 @@ /* * @test * @bug 4652655 4857717 8025633 8026567 8071982 8164407 8182765 8205593 8240169 + * 8369531 * @summary This test verifies that class cross references work properly. * @library ../../lib * @modules jdk.javadoc/jdk.javadoc.internal.tool @@ -58,18 +59,18 @@ public class TestClassCrossReferences extends JavadocTester { "Link to math package""", "Link to AttributeContext inn\ - erclass""", + javax/swing/text/AbstractDocument.AttributeContext.html" title="interface in jav\ + ax.swing.text" class="external-link">Link to AttributeContext innerclass""", "Link to external class BigDecimal""", + java/math/BigDecimal.html" title="class in java.math" class="external-link">Link to external class BigDecimal""", "Link to external member gcd""", + java/math/BigInteger.html#gcd-java.math.BigInteger-" class="external-link">Link to external member gcd""", "Link to external member URI""", + javax/tools/SimpleJavaFileObject.html#uri" class="external-link">Link to e\ + xternal member URI""", """
      Overrides:
      @@ -95,18 +96,18 @@ public class TestClassCrossReferences extends JavadocTester { "Link to math package""", "Link to AttributeContext inn\ - erclass""", + javax/swing/text/AbstractDocument.AttributeContext.html" title="interface in jav\ + ax.swing.text" class="external-link">Link to AttributeContext innerclass""", "Link to external class BigDecimal""", + java/math/BigDecimal.html" title="class in java.math" class="external-link">Link to external class BigDecimal""", "Link to external member gcd""", + java/math/BigInteger.html#gcd-java.math.BigInteger-" class="external-link">Link to external member gcd""", "Link to external member URI""", + javax/tools/SimpleJavaFileObject.html#uri" class="external-link">Link to e\ + xternal member URI""", """
      Overrides:
      diff --git a/test/langtools/jdk/javadoc/doclet/testDocRootInlineTag/TestDocRootInlineTag.java b/test/langtools/jdk/javadoc/doclet/testDocRootInlineTag/TestDocRootInlineTag.java index 04d1e0f14db..a1f97282c50 100644 --- a/test/langtools/jdk/javadoc/doclet/testDocRootInlineTag/TestDocRootInlineTag.java +++ b/test/langtools/jdk/javadoc/doclet/testDocRootInlineTag/TestDocRootInlineTag.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2025, 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 @@ -57,11 +57,11 @@ public class TestDocRootInlineTag extends JavadocTester { checkOutput("TestDocRootTag.html", true, "File""", + /java/io/File.html" title="class in java.io" class="external-link">File""", """ index""", "Second File Link""", + /java/io/File.html" title="class in java.io" class="external-link">Second File Link""", "The value of @docRoot is \"./\""); checkOutput("index-all.html", true, diff --git a/test/langtools/jdk/javadoc/doclet/testExternalOverriddenMethod/TestExternalOverriddenMethod.java b/test/langtools/jdk/javadoc/doclet/testExternalOverriddenMethod/TestExternalOverriddenMethod.java index 889b2edd1b5..7fd5c054f89 100644 --- a/test/langtools/jdk/javadoc/doclet/testExternalOverriddenMethod/TestExternalOverriddenMethod.java +++ b/test/langtools/jdk/javadoc/doclet/testExternalOverriddenMethod/TestExternalOverriddenMethod.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, 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 @@ -23,7 +23,7 @@ /* * @test - * @bug 4857717 8025633 8026567 8164407 8182765 8205593 + * @bug 4857717 8025633 8026567 8164407 8182765 8205593 8369531 * @summary Test to make sure that externally overridden and implemented methods * are documented properly. The method should still include "implements" or * "overrides" documentation even though the method is external. @@ -56,15 +56,17 @@ public class TestExternalOverriddenMethod extends JavadocTester { """
      Overrides:
      read in class FilterReader
      """, + /java/io/FilterReader.html#read--" class="external-link">read in \ + class Filter\ + Reader
    """, """
    Specified by:
    readInt in interface DataInput
    """ + /java/io/DataInput.html#readInt--" class="external-link">readInt \ + in interface DataI\ + nput""" ); } } diff --git a/test/langtools/jdk/javadoc/doclet/testGenericTypeLink/TestGenericTypeLink.java b/test/langtools/jdk/javadoc/doclet/testGenericTypeLink/TestGenericTypeLink.java index b6317a1e581..72554ef34fe 100644 --- a/test/langtools/jdk/javadoc/doclet/testGenericTypeLink/TestGenericTypeLink.java +++ b/test/langtools/jdk/javadoc/doclet/testGenericTypeLink/TestGenericTypeLink.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8177280 8262992 8259499 8307377 8352249 + * @bug 8177280 8262992 8259499 8307377 8352249 8369531 * @summary see and link tag syntax should allow generic types * @library ../../lib * @modules jdk.javadoc/jdk.javadoc.internal.tool @@ -53,13 +53,13 @@ public class TestGenericTypeLink extends JavadocTester { checkOutput("pkg1/A.html", true, """
    List<\ - ;String> - List<? extends CharSequence> + ist.html" title="interface in java.util" class="external-link">List<String> + List<? extends CharSequence> someMethod(ArrayList<Integer>\ ;, int) otherMethod(Map<String, Stri\ @@ -72,20 +72,19 @@ public class TestGenericTypeLink extends JavadocTester {
    Here's a generic link: A<Object, \ - RuntimeExcepti\ - on>.Inner"""); + html" title="class in java.lang" class="external-link">Object, RuntimeException>.Inner"""); } /** diff --git a/test/langtools/jdk/javadoc/doclet/testLinkOption/TestLinkOption.java b/test/langtools/jdk/javadoc/doclet/testLinkOption/TestLinkOption.java index a645ef31dec..d13e6617247 100644 --- a/test/langtools/jdk/javadoc/doclet/testLinkOption/TestLinkOption.java +++ b/test/langtools/jdk/javadoc/doclet/testLinkOption/TestLinkOption.java @@ -24,7 +24,7 @@ /* * @test * @bug 4720957 5020118 8026567 8038976 8184969 8164407 8182765 8205593 - * 8216497 + * 8216497 8369531 * @summary Test to make sure that -link and -linkoffline link to * right files, and URLs with and without trailing slash are accepted. * @library ../../lib @@ -73,8 +73,8 @@ public class TestLinkOption extends JavadocTester { checkOutput("pkg/C.html", true, "Link to String Class""", + java/lang/String.html" title="class in java.lang" class="external-link">Li\ + nk to String Class""", //Make sure the parameters are formatted properly when the -link option is used. """ (int p1, @@ -84,20 +84,20 @@ public class TestLinkOption extends JavadocTester { (int p1, int p2, Object p3)"""); + java/lang/Object.html" title="class in java.lang" class="external-link">Object p3)"""); checkOutput("pkg/B.html", true, """
    A method with html tag the method getSystemClassLoader() \ - as the parent class loader.
    """, + java/lang/ClassLoader.html#getSystemClassLoader--" class="external-link"><\ + b>getSystemClassLoader() as the parent class loader.
    """, """
    is equivalent to invoking createTempFile(prefix, s\ uffix, null).
    """, "Link-Plain to String Class""", + java/lang/String.html" title="class in java.lang" class="external-link">Link-Pla\ + in to String Class""", "getSystemClassLoader()", "createTempFile(prefix, suffix, null)", """ @@ -121,8 +121,8 @@ public class TestLinkOption extends JavadocTester {
    public abstract class StringBuilderChild extends Object
    """ + java/lang/Object.html" title="class in java.lang" class="external-link">Object""" ); // Generate the documentation using -linkoffline and a relative path as the first parameter. @@ -137,7 +137,7 @@ public class TestLinkOption extends JavadocTester { checkOutput("pkg2/C2.html", true, """ This is a link to Class C.""" + /pkg/C.html" title="class in pkg" class="external-link">Class C.""" ); String out3 = "out3"; @@ -168,12 +168,12 @@ public class TestLinkOption extends JavadocTester { extends java.lang.Object
    + link to mylib.lang.StringBuilderChild\ + . """ ); @@ -193,12 +193,11 @@ public class TestLinkOption extends JavadocTester { extends java.lang.Object + link to mylib.lang.StringBuilderChild. """ ); diff --git a/test/langtools/jdk/javadoc/doclet/testLinkOption/TestLinkOptionWithAutomaticModule.java b/test/langtools/jdk/javadoc/doclet/testLinkOption/TestLinkOptionWithAutomaticModule.java index fb31822d0e9..3f1682946b3 100644 --- a/test/langtools/jdk/javadoc/doclet/testLinkOption/TestLinkOptionWithAutomaticModule.java +++ b/test/langtools/jdk/javadoc/doclet/testLinkOption/TestLinkOptionWithAutomaticModule.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, 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 @@ -104,7 +104,7 @@ public class TestLinkOptionWithAutomaticModule extends JavadocTester { checkExit(Exit.OK); checkOutput("p/MyClass.html", true, """ - extends LibClass"""); } @@ -129,7 +129,7 @@ public class TestLinkOptionWithAutomaticModule extends JavadocTester { checkExit(Exit.OK); checkOutput("my.module/p/MyClass.html", true, """ - extends LibClass"""); } @@ -154,7 +154,7 @@ public class TestLinkOptionWithAutomaticModule extends JavadocTester { checkExit(Exit.OK); checkOutput("my.module/p/MyClass.html", true, """ - extends LibClass"""); } } diff --git a/test/langtools/jdk/javadoc/doclet/testLinkOption/TestLinkOptionWithModule.java b/test/langtools/jdk/javadoc/doclet/testLinkOption/TestLinkOptionWithModule.java index 113cde3c60d..f2f095b255b 100644 --- a/test/langtools/jdk/javadoc/doclet/testLinkOption/TestLinkOptionWithModule.java +++ b/test/langtools/jdk/javadoc/doclet/testLinkOption/TestLinkOptionWithModule.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, 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 @@ -79,7 +79,7 @@ public class TestLinkOptionWithModule extends JavadocTester { checkExit(Exit.OK); checkOutput("com.ex2/com/ex2/B.html", true, """ - A"""); + A"""); } @Test @@ -98,7 +98,7 @@ public class TestLinkOptionWithModule extends JavadocTester { checkExit(Exit.OK); checkOutput("com/ex2/B.html", true, """ - A"""); + A"""); } @Test @@ -121,7 +121,7 @@ public class TestLinkOptionWithModule extends JavadocTester { + "in ../out3a/ are in the unnamed module"); checkOutput("com.ex2/com/ex2/B.html", true, """ - A"""); + A"""); } @Test @@ -143,7 +143,7 @@ public class TestLinkOptionWithModule extends JavadocTester { + "in ../out4a/ are in named modules"); checkOutput("com/ex2/B.html", true, """ - A"""); + A"""); } @Test @@ -167,7 +167,7 @@ public class TestLinkOptionWithModule extends JavadocTester { + "in ../out5a/ are in the unnamed module"); checkOutput("com.ex2/com/ex2/B.html", true, """ - A"""); + A"""); } @Test @@ -193,7 +193,7 @@ public class TestLinkOptionWithModule extends JavadocTester { + "in ../out6a/ are in named modules"); checkOutput("com/ex2/B.html", true, """ - A"""); + A"""); } void initModulesAndPackages() throws Exception{ diff --git a/test/langtools/jdk/javadoc/doclet/testLinkOption/TestRedirectLinks.java b/test/langtools/jdk/javadoc/doclet/testLinkOption/TestRedirectLinks.java index 3c51b938396..2a415141229 100644 --- a/test/langtools/jdk/javadoc/doclet/testLinkOption/TestRedirectLinks.java +++ b/test/langtools/jdk/javadoc/doclet/testLinkOption/TestRedirectLinks.java @@ -162,11 +162,12 @@ public class TestRedirectLinks extends JavadocTester { checkExit(Exit.OK); checkOutput("pkg/B.html", true, "Link-Plain to String Class"""); checkOutput("pkg/C.html", true, "Object"""); + /java.base/java/lang/Object.html" title="class in java.lang" class=\ + "external-link">Object"""); } private Path libApi = Path.of("libApi"); @@ -272,10 +273,10 @@ public class TestRedirectLinks extends JavadocTester { "warning: URL " + oldURL + "/element-list was redirected to " + newURL + "/element-list"); checkOutput("mC/p5/C5.html", true, "extends C1"""); + /mA/p1/C1.html" title="class in p1" class="external-link">C1"""); checkOutput("mC/p6/C6.html", true, "C4"""); + /mB/p4/C4.html" title="class in p4" class="external-link">C4"""); } finally { if (oldServer != null) { out.println("Stopping old server on " + oldServer.getAddress()); diff --git a/test/langtools/jdk/javadoc/doclet/testLinkPlatform/TestLinkPlatform.java b/test/langtools/jdk/javadoc/doclet/testLinkPlatform/TestLinkPlatform.java index 5c22d6abb6d..5b2a751a295 100644 --- a/test/langtools/jdk/javadoc/doclet/testLinkPlatform/TestLinkPlatform.java +++ b/test/langtools/jdk/javadoc/doclet/testLinkPlatform/TestLinkPlatform.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, 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 @@ -23,7 +23,7 @@ /* * @test - * @bug 8216497 8297437 + * @bug 8216497 8297437 8369531 * @summary javadoc should auto-link to platform classes * @library /tools/lib ../../lib * @modules @@ -106,15 +106,15 @@ public class TestLinkPlatform extends JavadocTester { if (version <= 9) { checkOutput("p/q/A.html", true, "", - "", - ""); + "", + "", + ""); } else { checkOutput("p/q/A.html", true, "", - "", - ""); + "", + "", + ""); } } } @@ -136,15 +136,15 @@ public class TestLinkPlatform extends JavadocTester { if (version <= 9) { checkOutput("p/q/A.html", true, "", - "", - ""); + "", + "", + ""); } else { checkOutput("p/q/A.html", true, "", - "", - ""); + "", + "", + ""); } } } @@ -166,15 +166,15 @@ public class TestLinkPlatform extends JavadocTester { if (version <= 9) { checkOutput("p/q/A.html", true, "", - "", - ""); + "", + "", + ""); } else { checkOutput("p/q/A.html", true, "", - "", - ""); + "", + "", + ""); } } } diff --git a/test/langtools/jdk/javadoc/doclet/testLinkTaglet/TestLinkTagletWithModule.java b/test/langtools/jdk/javadoc/doclet/testLinkTaglet/TestLinkTagletWithModule.java index b10c746bde4..1b30fe365a4 100644 --- a/test/langtools/jdk/javadoc/doclet/testLinkTaglet/TestLinkTagletWithModule.java +++ b/test/langtools/jdk/javadoc/doclet/testLinkTaglet/TestLinkTagletWithModule.java @@ -107,20 +107,15 @@ public class TestLinkTagletWithModule extends JavadocTester { + Lib + class link + Lib.method(String) """); } @@ -164,9 +159,9 @@ public class TestLinkTagletWithModule extends JavadocTester { """); diff --git a/test/langtools/jdk/javadoc/doclet/testMarkdown/TestMarkdownLinks.java b/test/langtools/jdk/javadoc/doclet/testMarkdown/TestMarkdownLinks.java index 7bfb17d6864..76fa87f4fff 100644 --- a/test/langtools/jdk/javadoc/doclet/testMarkdown/TestMarkdownLinks.java +++ b/test/langtools/jdk/javadoc/doclet/testMarkdown/TestMarkdownLinks.java @@ -245,19 +245,19 @@ public class TestMarkdownLinks extends JavadocTester { "/api/java.base/java/util/package-summary.html\" class=\"external-link\">java.util", "class String", + "/api/java.base/java/lang/String.html\" title=\"class in java.lang\" class=\"external-link\">String", "interface Runnable", + "/api/java.base/java/lang/Runnable.html\" title=\"interface in java.lang\" class=\"external-link\">Runnable", "a field String.CASE_INSENSITIVE_ORDER", + "/api/java.base/java/lang/String.html#CASE_INSENSITIVE_ORDER\" class=\"external-link\">String.CASE_INSENSITIVE_ORDER", "a constructor String()", + "/api/java.base/java/lang/String.html#%3Cinit%3E()\" class=\"external-link\">String()", "a method String.chars()"); + "/api/java.base/java/lang/String.html#chars()\" class=\"external-link\">String.chars()"); } /// Test the ability to include array elements in method signatures for @@ -346,4 +346,4 @@ public class TestMarkdownLinks extends JavadocTester { """); } -} \ No newline at end of file +} diff --git a/test/langtools/jdk/javadoc/doclet/testModules/TestModules.java b/test/langtools/jdk/javadoc/doclet/testModules/TestModules.java index 5f140cc2c03..33a7249b596 100644 --- a/test/langtools/jdk/javadoc/doclet/testModules/TestModules.java +++ b/test/langtools/jdk/javadoc/doclet/testModules/TestModules.java @@ -1331,8 +1331,8 @@ public class TestModules extends JavadocTester { checkOutput("moduleB/testpkg3mdlB/package-summary.html", true, """ Link to \ - String Class"""); + ml" title="class in java.lang" class="external-link">Link to String Class<\ + /code>"""); checkOutput("moduleB/testpkg3mdlB/package-summary.html", true, """ TestPreviewDeclaration"); checkOutput("m/pkg/TestPreviewAPIUse.html", true, - "CorePREVIEW"); checkOutput("m/pkg/DocAnnotation.html", true, "public @interface DocAnnotation"); @@ -254,7 +254,7 @@ public class TestPreview extends JavadocTester { checkOutput("api2/api/API.html", true, "

    test()

    ", "

    testNoPreviewInSig()

    ", - "title=\"class or interface in java.util\" class=\"external-link\">List<List<APIPREVIEW>"); checkOutput("api2/api/API2.html", true, diff --git a/test/langtools/jdk/javadoc/doclet/testSeeTag/TestSeeTagWithModule.java b/test/langtools/jdk/javadoc/doclet/testSeeTag/TestSeeTagWithModule.java index 810db378394..9c4c4da70e3 100644 --- a/test/langtools/jdk/javadoc/doclet/testSeeTag/TestSeeTagWithModule.java +++ b/test/langtools/jdk/javadoc/doclet/testSeeTag/TestSeeTagWithModule.java @@ -113,19 +113,15 @@ public class TestSeeTagWithModule extends JavadocTester {
  • m1
  • m1
  • m1/com.m1.lib
  • -
  • Lib
  • -
  • Lib.method(String)
  • -
  • Lib.method(String)
  • +
  • Lib
  • +
  • Lib.method(String)
  • +
  • Lib.method(String)
  • m2
  • m2
  • m2/com.m2.lib
  • -
  • Lib
  • -
  • Lib.method(String)
  • -
  • Lib.method(String)
  • +
  • Lib
  • +
  • Lib.method(String)
  • +
  • Lib.method(String)
  • """); } @@ -175,9 +171,9 @@ public class TestSeeTagWithModule extends JavadocTester {
  • com.ex1
  • com.ex1
  • com.ex1/com.ex1
  • -
  • A
  • -
  • A.m()
  • -
  • A.m()
  • +
  • A
  • +
  • A.m()
  • +
  • A.m()
  • com.ex2
  • com.ex2
  • """); diff --git a/test/langtools/jdk/javadoc/doclet/testSnippetTag/TestSnippetMarkup.java b/test/langtools/jdk/javadoc/doclet/testSnippetTag/TestSnippetMarkup.java index be60a114040..c8b91dcba67 100644 --- a/test/langtools/jdk/javadoc/doclet/testSnippetTag/TestSnippetMarkup.java +++ b/test/langtools/jdk/javadoc/doclet/testSnippetTag/TestSnippetMarkup.java @@ -1123,7 +1123,7 @@ First line // @highlight : } String output = fileManager.getFileString(DOCUMENTATION_OUTPUT, "A.html"); // use the [^<>] regex to select HTML elements that immediately enclose "content" - Matcher m = Pattern.compile("(?is)(]*\" title=\"[^<>]*\" class=\"[^<>]*\">)" + Matcher m = Pattern.compile("(?is)(]*\" class=\"[^<>]*\">)" + LABEL_PLACEHOLDER + "()").matcher(output); if (!m.find()) { throw new IOException(output); diff --git a/test/langtools/jdk/javadoc/doclet/testTitleInHref/TestTitleInHref.java b/test/langtools/jdk/javadoc/doclet/testTitleInHref/TestTitleInHref.java index 98ffc9e99a4..70a77fad5a7 100644 --- a/test/langtools/jdk/javadoc/doclet/testTitleInHref/TestTitleInHref.java +++ b/test/langtools/jdk/javadoc/doclet/testTitleInHref/TestTitleInHref.java @@ -59,7 +59,7 @@ public class TestTitleInHref extends JavadocTester { """, //Test to make sure that the title shows up in cross link shows up "\ + /java/io/File.html" title="class in java.io" class="external-link">\ This is a cross link to class File"""); } } From e3a085581bfa70437b73d4b0527a084e0c5c9aac Mon Sep 17 00:00:00 2001 From: Emanuel Peter Date: Wed, 26 Nov 2025 14:58:50 +0000 Subject: [PATCH 022/706] 8371146: C2 SuperWord: VTransform::add_speculative_check uses pre_init that is pinned after Auto_Vectorization_Check, leading to bad graph Reviewed-by: roland, chagedorn --- src/hotspot/share/opto/vectorization.cpp | 33 +++-- src/hotspot/share/opto/vectorization.hpp | 24 ++++ ...TestAliasingCheckPreLimitNotAvailable.java | 116 ++++++++++++++++++ 3 files changed, 164 insertions(+), 9 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/loopopts/superword/TestAliasingCheckPreLimitNotAvailable.java diff --git a/src/hotspot/share/opto/vectorization.cpp b/src/hotspot/share/opto/vectorization.cpp index 98f3d79c9f5..15b2df663b6 100644 --- a/src/hotspot/share/opto/vectorization.cpp +++ b/src/hotspot/share/opto/vectorization.cpp @@ -1022,27 +1022,39 @@ bool VPointer::can_make_speculative_aliasing_check_with(const VPointer& other) c // or at the multiversion_if. That is before the pre-loop. From the construction of // VPointer, we already know that all its variables (except iv) are pre-loop invariant. // - // For the computation of main_init, we also need the pre_limit, and so we need - // to check that this value is pre-loop invariant. In the case of non-equal iv_scales, - // we also need the main_limit in the aliasing check, and so this value must then - // also be pre-loop invariant. + // In VPointer::make_speculative_aliasing_check_with we compute main_init in all + // cases. For this, we require pre_init and pre_limit. These values must be available + // for the speculative check, i.e. their control must dominate the speculative check. + // Further, "if vp1.iv_scale() != vp2.iv_scale()" we additionally need to have + // main_limit available for the speculative check. + // Note: no matter if the speculative check is inserted as a predicate or at the + // multiversion if, the speculative check happens before (dominates) the + // pre-loop. + Node* pre_init = _vloop.pre_loop_end()->init_trip(); Opaque1Node* pre_limit_opaq = _vloop.pre_loop_end()->limit()->as_Opaque1(); Node* pre_limit = pre_limit_opaq->in(1); Node* main_limit = _vloop.cl()->limit(); - - if (!_vloop.is_pre_loop_invariant(pre_limit)) { + if (!_vloop.is_available_for_speculative_check(pre_init)) { #ifdef ASSERT if (_vloop.is_trace_speculative_aliasing_analysis()) { - tty->print_cr("VPointer::can_make_speculative_aliasing_check_with: pre_limit is not pre-loop independent!"); + tty->print_cr("VPointer::can_make_speculative_aliasing_check_with: pre_limit is not available at speculative check!"); + } +#endif + return false; + } + if (!_vloop.is_available_for_speculative_check(pre_limit)) { +#ifdef ASSERT + if (_vloop.is_trace_speculative_aliasing_analysis()) { + tty->print_cr("VPointer::can_make_speculative_aliasing_check_with: pre_limit is not available at speculative check!"); } #endif return false; } - if (vp1.iv_scale() != vp2.iv_scale() && !_vloop.is_pre_loop_invariant(main_limit)) { + if (vp1.iv_scale() != vp2.iv_scale() && !_vloop.is_available_for_speculative_check(main_limit)) { #ifdef ASSERT if (_vloop.is_trace_speculative_aliasing_analysis()) { - tty->print_cr("VPointer::can_make_speculative_aliasing_check_with: main_limit is not pre-loop independent!"); + tty->print_cr("VPointer::can_make_speculative_aliasing_check_with: main_limit is not available at speculative check!"); } #endif return false; @@ -1119,6 +1131,8 @@ BoolNode* VPointer::make_speculative_aliasing_check_with(const VPointer& other, Node* pre_limit = pre_limit_opaq->in(1); assert(_vloop.is_pre_loop_invariant(pre_init), "needed for aliasing check before pre-loop"); assert(_vloop.is_pre_loop_invariant(pre_limit), "needed for aliasing check before pre-loop"); + assert(_vloop.is_available_for_speculative_check(pre_init), "ctrl must be early enough to avoid cycles"); + assert(_vloop.is_available_for_speculative_check(pre_limit), "ctrl must be early enough to avoid cycles"); Node* pre_initL = new ConvI2LNode(pre_init); Node* pre_limitL = new ConvI2LNode(pre_limit); @@ -1180,6 +1194,7 @@ BoolNode* VPointer::make_speculative_aliasing_check_with(const VPointer& other, jint main_iv_stride = _vloop.iv_stride(); Node* main_limit = _vloop.cl()->limit(); assert(_vloop.is_pre_loop_invariant(main_limit), "needed for aliasing check before pre-loop"); + assert(_vloop.is_available_for_speculative_check(main_limit), "ctrl must be early enough to avoid cycles"); Node* main_limitL = new ConvI2LNode(main_limit); phase->register_new_node_with_ctrl_of(main_limitL, pre_init); diff --git a/src/hotspot/share/opto/vectorization.hpp b/src/hotspot/share/opto/vectorization.hpp index f7099b5b7c0..aacd406f798 100644 --- a/src/hotspot/share/opto/vectorization.hpp +++ b/src/hotspot/share/opto/vectorization.hpp @@ -236,6 +236,8 @@ public: // Some nodes must be pre-loop invariant, so that they can be used for conditions // before or inside the pre-loop. For example, alignment of main-loop vector // memops must be achieved in the pre-loop, via the exit check in the pre-loop. + // Note: this condition is NOT strong enough for speculative checks, those happen + // before the pre-loop. See is_available_for_speculative_check bool is_pre_loop_invariant(Node* n) const { // Must be in the main-loop, otherwise we can't access the pre-loop. // This fails during SuperWord::unrolling_analysis, but that is ok. @@ -257,6 +259,28 @@ public: return is_before_pre_loop(early); } + // Nodes that are to be used in speculative checks must be available early enough. + // Note: the speculative check happens before the pre-loop, either at the auto + // vectorization predicate or the multiversion if. This is before the + // pre-loop, and thus the condition here is stronger then the one from + // is_pre_loop_invariant. + bool is_available_for_speculative_check(Node* n) const { + assert(are_speculative_checks_possible(), "meaningless without speculative check"); + ParsePredicateSuccessProj* parse_predicate_proj = auto_vectorization_parse_predicate_proj(); + // Find the control of the predicate: + ProjNode* proj = (parse_predicate_proj != nullptr) ? parse_predicate_proj : multiversioning_fast_proj(); + Node* check_ctrl = proj->in(0)->as_If()->in(0); + + // Often, the control of n already dominates that of the predicate. + Node* n_ctrl = phase()->get_ctrl(n); + if (phase()->is_dominator(n_ctrl, check_ctrl)) { return true; } + + // But in some cases, the ctrl of n is after that of the predicate, + // but the early ctrl is before the predicate. + Node* n_early = phase()->compute_early_ctrl(n, n_ctrl); + return phase()->is_dominator(n_early, check_ctrl); + } + // Check if the loop passes some basic preconditions for vectorization. // Return indicates if analysis succeeded. bool check_preconditions(); diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestAliasingCheckPreLimitNotAvailable.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestAliasingCheckPreLimitNotAvailable.java new file mode 100644 index 00000000000..e7009e87ae2 --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestAliasingCheckPreLimitNotAvailable.java @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2025, 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 id=all-flags-fixed-stress-seed + * @bug 8371146 + * @summary Test where the pre_init was pinned before the pre-loop but after the + * Auto_Vectorization_Check, and so it should not be used for the auto + * vectorization aliasing check, to avoid a bad (circular) graph. + * @requires vm.gc == "ZGC" | vm.gc == "null" + * @run main/othervm + * -XX:+IgnoreUnrecognizedVMOptions + * -XX:CompileCommand=compileonly,*TestAliasingCheckPreLimitNotAvailable::test + * -XX:-TieredCompilation + * -Xcomp + * -XX:+UseZGC + * -XX:+UnlockDiagnosticVMOptions -XX:+StressLoopPeeling -XX:StressSeed=4 + * -XX:LoopUnrollLimit=48 + * compiler.loopopts.superword.TestAliasingCheckPreLimitNotAvailable + */ + +/* + * @test id=all-flags-no-stress-seed + * @bug 8371146 + * @requires vm.gc == "ZGC" | vm.gc == "null" + * @run main/othervm + * -XX:+IgnoreUnrecognizedVMOptions + * -XX:CompileCommand=compileonly,*TestAliasingCheckPreLimitNotAvailable::test + * -XX:-TieredCompilation + * -Xcomp + * -XX:+UseZGC + * -XX:+UnlockDiagnosticVMOptions -XX:+StressLoopPeeling + * -XX:LoopUnrollLimit=48 + * compiler.loopopts.superword.TestAliasingCheckPreLimitNotAvailable + */ + +/* + * @test id=fewer-flags + * @bug 8371146 + * @run main/othervm + * -XX:+IgnoreUnrecognizedVMOptions + * -XX:CompileCommand=compileonly,*TestAliasingCheckPreLimitNotAvailable::test + * -XX:-TieredCompilation + * -Xcomp + * -XX:LoopUnrollLimit=48 + * compiler.loopopts.superword.TestAliasingCheckPreLimitNotAvailable + */ + +/* + * @test id=minimal-flags + * @bug 8371146 + * @run main/othervm + * -XX:+IgnoreUnrecognizedVMOptions + * -XX:CompileCommand=compileonly,*TestAliasingCheckPreLimitNotAvailable::test + * -XX:-TieredCompilation + * -Xcomp + * compiler.loopopts.superword.TestAliasingCheckPreLimitNotAvailable + */ + +/* + * @test id=vanilla + * @bug 8371146 + * @run main compiler.loopopts.superword.TestAliasingCheckPreLimitNotAvailable + */ + +package compiler.loopopts.superword; + +public class TestAliasingCheckPreLimitNotAvailable { + static int sum; + static boolean condition; + static int zero; + static int twoDimensional[][] = new int[20][20]; + + static void test() { + int innerCount = 0; + int conditionCount = 0; + int oneDimensional[] = new int[10]; + for (int i = 2; i > 0; --i) { + for (int j = i; j < 10; j++) { + innerCount += 1; + oneDimensional[1] += innerCount; + oneDimensional[j] += zero; + if (condition) { + conditionCount += 1; + oneDimensional[1] += conditionCount; + sum += oneDimensional[1]; + } + twoDimensional[j] = twoDimensional[j + 1]; + } + } + } + + public static void main(String[] args) { + test(); + } +} From 1ce2a44e9f4fa9d558602dbd0489fefb0c9563ef Mon Sep 17 00:00:00 2001 From: Per Minborg Date: Wed, 26 Nov 2025 15:11:10 +0000 Subject: [PATCH 023/706] 8371571: Consolidate and enhance bulk memory segment ops benchmarks Reviewed-by: jvernee --- .../bench/java/lang/foreign/BulkOps.java | 211 ------------------ .../java/lang/foreign/SegmentBulkCopy.java | 161 +++++++++---- .../java/lang/foreign/SegmentBulkFill.java | 164 +++++++------- .../java/lang/foreign/SegmentBulkHash.java | 126 ++++++++--- .../lang/foreign/SegmentBulkMismatch.java | 155 +++++++++---- 5 files changed, 396 insertions(+), 421 deletions(-) delete mode 100644 test/micro/org/openjdk/bench/java/lang/foreign/BulkOps.java diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/BulkOps.java b/test/micro/org/openjdk/bench/java/lang/foreign/BulkOps.java deleted file mode 100644 index 60f36d9f157..00000000000 --- a/test/micro/org/openjdk/bench/java/lang/foreign/BulkOps.java +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Copyright (c) 2020, 2025, 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.java.lang.foreign; - -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; -import org.openjdk.jmh.annotations.OutputTimeUnit; -import org.openjdk.jmh.annotations.Setup; -import org.openjdk.jmh.annotations.State; -import org.openjdk.jmh.annotations.TearDown; -import org.openjdk.jmh.annotations.Warmup; -import jdk.internal.misc.Unsafe; - -import java.lang.foreign.Arena; -import java.lang.foreign.MemorySegment; -import java.nio.ByteBuffer; -import java.nio.IntBuffer; -import java.util.concurrent.TimeUnit; - -import static java.lang.foreign.ValueLayout.JAVA_INT; -import static java.lang.foreign.ValueLayout.JAVA_INT_UNALIGNED; - -@BenchmarkMode(Mode.AverageTime) -@Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS) -@Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) -@State(org.openjdk.jmh.annotations.Scope.Thread) -@OutputTimeUnit(TimeUnit.MILLISECONDS) -@Fork(value = 3, jvmArgs = { "--add-opens=java.base/jdk.internal.misc=ALL-UNNAMED" }) -public class BulkOps { - - static final Unsafe unsafe = Utils.unsafe; - - static final int ELEM_SIZE = 1_000_000; - static final int CARRIER_SIZE = (int)JAVA_INT.byteSize(); - static final int ALLOC_SIZE = ELEM_SIZE * CARRIER_SIZE; - - final Arena arena = Arena.ofShared(); - - final long unsafe_addr = unsafe.allocateMemory(ALLOC_SIZE); - final MemorySegment segment = arena.allocate(ALLOC_SIZE, 1); - - final IntBuffer buffer = IntBuffer.allocate(ELEM_SIZE); - - final int[] ints = new int[ELEM_SIZE]; - final MemorySegment bytesSegment = MemorySegment.ofArray(ints); - final long UNSAFE_INT_OFFSET = unsafe.arrayBaseOffset(int[].class); - - // large(ish) segments/buffers with same content, 0, for mismatch, non-multiple-of-8 sized - static final int SIZE_WITH_TAIL = (1024 * 1024) + 7; - final MemorySegment mismatchSegmentLarge1; - - { - mismatchSegmentLarge1 = arena.allocate(SIZE_WITH_TAIL, 1); - } - - final MemorySegment mismatchSegmentLarge2 = arena.allocate(SIZE_WITH_TAIL, 1); - final ByteBuffer mismatchBufferLarge1 = ByteBuffer.allocateDirect(SIZE_WITH_TAIL); - final ByteBuffer mismatchBufferLarge2 = ByteBuffer.allocateDirect(SIZE_WITH_TAIL); - - // mismatch at first byte - final MemorySegment mismatchSegmentSmall1 = arena.allocate(7, 1); - final MemorySegment mismatchSegmentSmall2 = arena.allocate(7, 1); - final ByteBuffer mismatchBufferSmall1 = ByteBuffer.allocateDirect(7); - final ByteBuffer mismatchBufferSmall2 = ByteBuffer.allocateDirect(7); - - @Setup - public void setup() { - mismatchSegmentSmall1.fill((byte) 0xFF); - mismatchBufferSmall1.put((byte) 0xFF).clear(); - // verify expected mismatch indices - long si = mismatchSegmentLarge1.mismatch(mismatchSegmentLarge2); - if (si != -1) - throw new AssertionError("Unexpected mismatch index:" + si); - int bi = mismatchBufferLarge1.mismatch(mismatchBufferLarge2); - if (bi != -1) - throw new AssertionError("Unexpected mismatch index:" + bi); - si = mismatchSegmentSmall1.mismatch(mismatchSegmentSmall2); - if (si != 0) - throw new AssertionError("Unexpected mismatch index:" + si); - bi = mismatchBufferSmall1.mismatch(mismatchBufferSmall2); - if (bi != 0) - throw new AssertionError("Unexpected mismatch index:" + bi); - - for (int i = 0; i < ints.length ; i++) { - ints[i] = i; - } - } - - @TearDown - public void tearDown() { - arena.close(); - } - - @Benchmark - @OutputTimeUnit(TimeUnit.NANOSECONDS) - public void unsafe_fill() { - unsafe.setMemory(unsafe_addr, ALLOC_SIZE, (byte)42); - } - - @Benchmark - @OutputTimeUnit(TimeUnit.NANOSECONDS) - public void segment_fill() { - segment.fill((byte)42); - } - - @Benchmark - @OutputTimeUnit(TimeUnit.NANOSECONDS) - public void unsafe_copy() { - unsafe.copyMemory(ints, UNSAFE_INT_OFFSET, null, unsafe_addr, ALLOC_SIZE); - } - - @Benchmark - @OutputTimeUnit(TimeUnit.NANOSECONDS) - public void segment_copy() { - segment.copyFrom(bytesSegment); - } - - @Benchmark - @OutputTimeUnit(TimeUnit.NANOSECONDS) - public void segment_copy_static() { - MemorySegment.copy(ints, 0, segment, JAVA_INT_UNALIGNED, 0, ints.length); - } - - @Benchmark - @OutputTimeUnit(TimeUnit.NANOSECONDS) - public void segment_copy_static_small() { - MemorySegment.copy(ints, 0, segment, JAVA_INT_UNALIGNED, 0, 10); - } - - @Benchmark - @CompilerControl(CompilerControl.Mode.DONT_INLINE) - @OutputTimeUnit(TimeUnit.NANOSECONDS) - public void segment_copy_static_small_dontinline() { - MemorySegment.copy(ints, 0, segment, JAVA_INT_UNALIGNED, 0, 10); - } - - @Benchmark - @OutputTimeUnit(TimeUnit.NANOSECONDS) - public void unsafe_copy_small() { - unsafe.copyMemory(ints, UNSAFE_INT_OFFSET, null, unsafe_addr, 10 * CARRIER_SIZE); - } - - @Benchmark - @OutputTimeUnit(TimeUnit.NANOSECONDS) - public void buffer_copy_small() { - buffer.put(0, ints, 0, 10); - } - - @Benchmark - @OutputTimeUnit(TimeUnit.NANOSECONDS) - public void buffer_copy() { - buffer.put(0, ints, 0, ints.length); - } - - @Benchmark - @CompilerControl(CompilerControl.Mode.DONT_INLINE) - @OutputTimeUnit(TimeUnit.NANOSECONDS) - public void segment_copy_static_dontinline() { - MemorySegment.copy(ints, 0, segment, JAVA_INT_UNALIGNED, 0, ints.length); - } - - @Benchmark - @OutputTimeUnit(TimeUnit.NANOSECONDS) - public long mismatch_large_segment() { - return mismatchSegmentLarge1.mismatch(mismatchSegmentLarge2); - } - - @Benchmark - @OutputTimeUnit(TimeUnit.NANOSECONDS) - public int mismatch_large_bytebuffer() { - return mismatchBufferLarge1.mismatch(mismatchBufferLarge2); - } - - @Benchmark - @OutputTimeUnit(TimeUnit.NANOSECONDS) - public long mismatch_small_segment() { - return mismatchSegmentSmall1.mismatch(mismatchSegmentSmall2); - } - - @Benchmark - @OutputTimeUnit(TimeUnit.NANOSECONDS) - public int mismatch_small_bytebuffer() { - return mismatchBufferSmall1.mismatch(mismatchBufferSmall2); - } -} diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/SegmentBulkCopy.java b/test/micro/org/openjdk/bench/java/lang/foreign/SegmentBulkCopy.java index ca6f21d20e9..83522bd4f3c 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/SegmentBulkCopy.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/SegmentBulkCopy.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, 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,9 +38,13 @@ import org.openjdk.jmh.annotations.Warmup; import java.lang.foreign.Arena; import java.lang.foreign.MemorySegment; +import java.lang.foreign.ValueLayout; import java.nio.ByteBuffer; +import java.util.Random; import java.util.concurrent.TimeUnit; +import static java.lang.foreign.ValueLayout.JAVA_LONG; + @BenchmarkMode(Mode.AverageTime) @Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS) @Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) @@ -49,63 +53,122 @@ import java.util.concurrent.TimeUnit; @Fork(value = 3) public class SegmentBulkCopy { - @Param({"2", "3", "4", "5", "6", "7", "8", "64", "512", - "4096", "32768", "262144", "2097152", "16777216", "134217728"}) - public int ELEM_SIZE; + @Param({"2", "4", "8", "12", "16", "64", "512", "4096", "32768", "262144", "2097152", "16777216", "134217728"}) + public int size; - byte[] srcArray; - byte[] dstArray; - MemorySegment heapSrcSegment; - MemorySegment heapDstSegment; - MemorySegment nativeSrcSegment; - MemorySegment nativeDstSegment; - ByteBuffer srcBuffer; - ByteBuffer dstBuffer; + public static class Array extends SegmentBulkCopy { + + byte[] srcArray; + byte[] dstArray; + + ByteBuffer srcBuffer; + ByteBuffer dstBuffer; + + @Setup + public void setup() { + srcArray = new byte[size]; + var rnd = new Random(42); + rnd.nextBytes(srcArray); + dstArray = new byte[size]; + srcBuffer = ByteBuffer.wrap(srcArray); + dstBuffer = ByteBuffer.wrap(dstArray); + } + + @Benchmark + public void arrayCopy() { + System.arraycopy(srcArray, 0, dstArray, 0, size); + } + + @Benchmark + public void bufferCopy() { + dstBuffer.put(0, srcBuffer, 0, size); + } - @Setup - public void setup() { - srcArray = new byte[ELEM_SIZE]; - dstArray = new byte[ELEM_SIZE]; - heapSrcSegment = MemorySegment.ofArray(srcArray); - heapDstSegment = MemorySegment.ofArray(dstArray); - nativeSrcSegment = Arena.ofAuto().allocate(ELEM_SIZE); - nativeDstSegment = Arena.ofAuto().allocate(ELEM_SIZE); - srcBuffer = ByteBuffer.wrap(srcArray); - dstBuffer = ByteBuffer.wrap(dstArray); } - @Benchmark - public void arrayCopy() { - System.arraycopy(srcArray, 0, dstArray, 0, ELEM_SIZE); - } + public static class Segment extends SegmentBulkCopy { - @Benchmark - public void bufferCopy() { - dstBuffer.put(srcBuffer); - } + enum SegmentType {HEAP, NATIVE} + enum Alignment {ALIGNED, UNALIGNED} - @Fork(value = 3, jvmArgs = {"-Djava.lang.foreign.native.threshold.power.copy=31"}) - @Benchmark - public void heapSegmentCopyJava() { - MemorySegment.copy(heapSrcSegment, 0, heapDstSegment, 0, ELEM_SIZE); - } + @Param({"HEAP", "NATIVE"}) + String segmentType; - @Fork(value = 3, jvmArgs = {"-Djava.lang.foreign.native.threshold.power.copy=0"}) - @Benchmark - public void heapSegmentCopyUnsafe() { - MemorySegment.copy(heapSrcSegment, 0, heapDstSegment, 0, ELEM_SIZE); - } + @Param({"ALIGNED", "UNALIGNED"}) + String alignment; - @Fork(value = 3, jvmArgs = {"-Djava.lang.foreign.native.threshold.power.copy=31"}) - @Benchmark - public void nativeSegmentCopyJava() { - MemorySegment.copy(nativeSrcSegment, 0, nativeDstSegment, 0, ELEM_SIZE); - } + MemorySegment srcSegment; + MemorySegment dstSegment; + + @Setup + public void setup() { + // A long array is likely to be aligned at 8-byte boundaries + long[] baseArray; + + baseArray = new long[size / Long.BYTES + 1]; + var rnd = new Random(42); + for (int i = 0; i < baseArray.length; i++) { + baseArray[i] = rnd.nextLong(); + } + + switch (SegmentType.valueOf(segmentType)) { + case HEAP -> { + srcSegment = MemorySegment.ofArray(baseArray); + dstSegment = MemorySegment.ofArray(baseArray.clone()); + } + case NATIVE -> { + srcSegment = Arena.ofAuto().allocateFrom(JAVA_LONG, baseArray); + dstSegment = Arena.ofAuto().allocateFrom(JAVA_LONG, baseArray); + } + } + switch (Alignment.valueOf(alignment)) { + case ALIGNED -> { + srcSegment = srcSegment.asSlice(0, size); + dstSegment = dstSegment.asSlice(0, size); + } + case UNALIGNED -> { + srcSegment = srcSegment.asSlice(1, size); + dstSegment = dstSegment.asSlice(1, size); + } + } + } + + @Benchmark + @Fork(value = 3, jvmArgs = {"-Djava.lang.foreign.native.threshold.power.copy=31"}) + public void copy() { + MemorySegment.copy(srcSegment, 0, dstSegment, 0, size); + } + + @Benchmark + public void copyLoopIntInt() { + for (int i = 0; i < (int) srcSegment.byteSize(); i++) { + final byte v = srcSegment.get(ValueLayout.JAVA_BYTE, i); + dstSegment.set(ValueLayout.JAVA_BYTE, i, v); + } + } + + @Benchmark + public void copyLoopIntLong() { + for (int i = 0; i < srcSegment.byteSize(); i++) { + final byte v = srcSegment.get(ValueLayout.JAVA_BYTE, i); + dstSegment.set(ValueLayout.JAVA_BYTE, i, v); + } + } + + @Benchmark + public void copyLoopLongLong() { + for (long i = 0; i < srcSegment.byteSize(); i++) { + final byte v = srcSegment.get(ValueLayout.JAVA_BYTE, i); + dstSegment.set(ValueLayout.JAVA_BYTE, i, v); + } + } + + @Fork(value = 3, jvmArgs = {"-Djava.lang.foreign.native.threshold.power.copy=0"}) + @Benchmark + public void copyUnsafe() { + MemorySegment.copy(srcSegment, 0, dstSegment, 0, size); + } - @Fork(value = 3, jvmArgs = {"-Djava.lang.foreign.native.threshold.power.copy=0"}) - @Benchmark - public void nativeSegmentCopyUnsafe() { - MemorySegment.copy(nativeSrcSegment, 0, nativeDstSegment, 0, ELEM_SIZE); } } diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/SegmentBulkFill.java b/test/micro/org/openjdk/bench/java/lang/foreign/SegmentBulkFill.java index 96cf62cc5f6..3c4770731b6 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/SegmentBulkFill.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/SegmentBulkFill.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, 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,6 +43,8 @@ import java.nio.ByteBuffer; import java.util.Arrays; import java.util.concurrent.TimeUnit; +import static java.lang.foreign.ValueLayout.JAVA_LONG; + @BenchmarkMode(Mode.AverageTime) @Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS) @Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) @@ -51,99 +53,105 @@ import java.util.concurrent.TimeUnit; @Fork(value = 3) public class SegmentBulkFill { - @Param({"2", "3", "4", "5", "6", "7", "8", "64", "512", - "4096", "32768", "262144", "2097152", "16777216", "134217728"}) - public int ELEM_SIZE; + private static final byte ZERO = 0; - byte[] array; - MemorySegment heapSegment; - MemorySegment nativeSegment; - MemorySegment unalignedSegment; - ByteBuffer buffer; + @Param({"2", "4", "8", "12", "16", "64", "512", "4096", "32768", "262144", "2097152", "16777216", "134217728"}) + public int size; - @Setup - public void setup() { - array = new byte[ELEM_SIZE]; - heapSegment = MemorySegment.ofArray(array); - nativeSegment = Arena.ofAuto().allocate(ELEM_SIZE, 8); - unalignedSegment = Arena.ofAuto().allocate(ELEM_SIZE + 1, 8).asSlice(1); - buffer = ByteBuffer.wrap(array); - } + public static class Array extends SegmentBulkFill { - @Benchmark - public void arraysFill() { - Arrays.fill(array, (byte) 0); - } + byte[] array; + ByteBuffer buffer; - @Benchmark - public void arraysFillLoop() { - for (int i = 0; i < array.length; i++) { - array[i] = 0; + @Setup + public void setup() { + array = new byte[size]; + buffer = ByteBuffer.wrap(array); } - } - @Benchmark - public void bufferFillLoop() { - for (int i = 0; i < array.length; i++) { - buffer.put(i, (byte)0); + @Benchmark + public void arraysFill() { + Arrays.fill(array, ZERO); } - } - @Fork(value = 3, jvmArgs = {"-Djava.lang.foreign.native.threshold.power.fill=31"}) - @Benchmark - public void heapSegmentFillJava() { - heapSegment.fill((byte) 0); - } - - @Fork(value = 3, jvmArgs = {"-Djava.lang.foreign.native.threshold.power.fill=0"}) - @Benchmark - public void heapSegmentFillUnsafe() { - heapSegment.fill((byte) 0); - } - - @Benchmark - public void heapSegmentFillLoop() { - for (long i = 0; i < heapSegment.byteSize(); i++) { - heapSegment.set(ValueLayout.JAVA_BYTE, i, (byte) 0); + @Benchmark + public void arraysFillLoop() { + for (int i = 0; i < array.length; i++) { + array[i] = ZERO; + } } - } - @Fork(value = 3, jvmArgs = {"-Djava.lang.foreign.native.threshold.power.fill=31"}) - @Benchmark - public void nativeSegmentFillJava() { - nativeSegment.fill((byte) 0); - } - - @Fork(value = 3, jvmArgs = {"-Djava.lang.foreign.native.threshold.power.fill=0"}) - @Benchmark - public void nativeSegmentFillUnsafe() { - nativeSegment.fill((byte) 0); - } - - @Benchmark - public void nativeSegmentFillLoop() { - for (long i = 0; i < nativeSegment.byteSize(); i++) { - nativeSegment.set(ValueLayout.JAVA_BYTE, i, (byte) 0); + @Benchmark + public void bufferFillLoop() { + for (int i = 0; i < array.length; i++) { + buffer.put(i, ZERO); + } } + } - @Fork(value = 3, jvmArgs = {"-Djava.lang.foreign.native.threshold.power.fill=31"}) - @Benchmark - public void unalignedSegmentFillJava() { - unalignedSegment.fill((byte) 0); - } + public static class Segment extends SegmentBulkFill { - @Fork(value = 3, jvmArgs = {"-Djava.lang.foreign.native.threshold.power.fill=0"}) - @Benchmark - public void unalignedSegmentFillUnsafe() { - unalignedSegment.fill((byte) 0); - } + enum SegmentType {HEAP, NATIVE} + enum Alignment {ALIGNED, UNALIGNED} - @Benchmark - public void unalignedSegmentFillLoop() { - for (long i = 0; i < unalignedSegment.byteSize(); i++) { - unalignedSegment.set(ValueLayout.JAVA_BYTE, i, (byte) 0); + @Param({"HEAP", "NATIVE"}) + String segmentType; + + @Param({"ALIGNED", "UNALIGNED"}) + String alignment; + + MemorySegment segment; + + @Setup + public void setup() { + // A long array is likely to be aligned at 8-byte boundaries + long[] baseArray = new long[size / Long.BYTES + 1]; + var heapSegment = MemorySegment.ofArray(baseArray); + + segment = switch (SegmentType.valueOf(segmentType)) { + case HEAP -> heapSegment; + case NATIVE -> Arena.ofAuto().allocateFrom(JAVA_LONG, baseArray); + }; + segment = switch (Alignment.valueOf(alignment)) { + case ALIGNED -> segment.asSlice(0, size); + case UNALIGNED -> segment.asSlice(1, size); + }; } + + @Benchmark + @Fork(value = 3, jvmArgs = {"-Djava.lang.foreign.native.threshold.power.fill=31"}) + public void fill() { + segment.fill(ZERO); + } + + @Benchmark + public void fillLoopIntInt() { + for (int i = 0; i < (int)segment.byteSize(); i++) { + segment.set(ValueLayout.JAVA_BYTE, i, ZERO); + } + } + + @Benchmark + public void fillLoopIntLong() { + for (int i = 0; i < segment.byteSize(); i++) { + segment.set(ValueLayout.JAVA_BYTE, i, ZERO); + } + } + + @Benchmark + public void fillLoopLongLong() { + for (long i = 0; i < segment.byteSize(); i++) { + segment.set(ValueLayout.JAVA_BYTE, i, ZERO); + } + } + + @Benchmark + @Fork(value = 3, jvmArgs = {"-Djava.lang.foreign.native.threshold.power.fill=0"}) + public void fillUnsafe() { + segment.fill(ZERO); + } + } } diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/SegmentBulkHash.java b/test/micro/org/openjdk/bench/java/lang/foreign/SegmentBulkHash.java index 927a7d3fb1f..0213916fcd6 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/SegmentBulkHash.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/SegmentBulkHash.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, 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 @@ -45,6 +45,7 @@ import java.util.Random; import java.util.concurrent.TimeUnit; import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import static java.lang.foreign.ValueLayout.JAVA_LONG; @BenchmarkMode(Mode.AverageTime) @Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS) @@ -54,47 +55,98 @@ import static java.lang.foreign.ValueLayout.JAVA_BYTE; @Fork(value = 3, jvmArgs = {"--add-exports=java.base/jdk.internal.foreign=ALL-UNNAMED"}) public class SegmentBulkHash { - @Param({"8", "64"}) - public int ELEM_SIZE; + @Param({"2", "4", "8", "12", "16", "64", "512", "4096", "32768", "262144", "2097152", "16777216", "134217728"}) + public int size; - byte[] array; - AbstractMemorySegmentImpl heapSegment; - AbstractMemorySegmentImpl nativeSegment; + public static class Array extends SegmentBulkHash { - @Setup - public void setup() { - // Always use the same alignment regardless of size - nativeSegment = (AbstractMemorySegmentImpl) Arena.ofAuto().allocate(ELEM_SIZE, 16); - var rnd = new Random(42); - for (int i = 0; i < ELEM_SIZE; i++) { - nativeSegment.set(JAVA_BYTE, i, (byte) rnd.nextInt(Byte.MIN_VALUE, Byte.MAX_VALUE)); + byte[] array; + + @Setup + public void setup() { + byte[] randomArray = new byte[size + 1]; + var rnd = new Random(42); + rnd.nextBytes(randomArray); + + array = Arrays.copyOf(randomArray, size); } - array = nativeSegment.toArray(JAVA_BYTE); - heapSegment = (AbstractMemorySegmentImpl) MemorySegment.ofArray(array); - } - @Benchmark - public int array() { - return Arrays.hashCode(array); - } - - @Benchmark - public int heapSegment() { - return SegmentBulkOperations.contentHash(heapSegment, 0, ELEM_SIZE); - } - - @Benchmark - public int nativeSegment() { - return SegmentBulkOperations.contentHash(nativeSegment, 0, ELEM_SIZE); - } - - @Benchmark - public int nativeSegmentJava() { - int result = 1; - for (long i = 0; i < ELEM_SIZE; i++) { - result = 31 * result + nativeSegment.get(JAVA_BYTE, i); + @Benchmark + public int array() { + return Arrays.hashCode(array); } - return result; + + } + + public static class Segment extends SegmentBulkHash { + + enum SegmentType {HEAP, NATIVE} + enum Alignment {ALIGNED, UNALIGNED} + + @Param({"HEAP", "NATIVE"}) + String segmentType; + + @Param({"ALIGNED", "UNALIGNED"}) + String alignment; + + AbstractMemorySegmentImpl segment; + + @Setup + public void setup() { + // A long array is likely to be aligned at 8-byte boundaries + long[] baseArray; + + baseArray = new long[size / Long.BYTES + 1]; + var rnd = new Random(42); + for (int i = 0; i < baseArray.length; i++) { + baseArray[i] = rnd.nextLong(); + } + var heapSegment = MemorySegment.ofArray(baseArray); + + var s = switch (SegmentType.valueOf(segmentType)) { + case HEAP -> heapSegment; + case NATIVE -> Arena.ofAuto().allocateFrom(JAVA_LONG, baseArray); + }; + s = switch (Alignment.valueOf(alignment)) { + case ALIGNED -> s.asSlice(0, size); + case UNALIGNED -> s.asSlice(1, size); + }; + + segment = (AbstractMemorySegmentImpl) s; + } + + @Benchmark + public int hash() { + return SegmentBulkOperations.contentHash(segment, 0, size); + } + + @Benchmark + public int hashLoopIntInt() { + int result = 1; + for (int i = 0; i < (int)segment.byteSize(); i++) { + result = 31 * result + segment.get(JAVA_BYTE, i); + } + return result; + } + + @Benchmark + public int hashLoopIntLong() { + int result = 1; + for (int i = 0; i < segment.byteSize(); i++) { + result = 31 * result + segment.get(JAVA_BYTE, i); + } + return result; + } + + @Benchmark + public int hashLoopLongLong() { + int result = 1; + for (long i = 0; i < segment.byteSize(); i++) { + result = 31 * result + segment.get(JAVA_BYTE, i); + } + return result; + } + } } diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/SegmentBulkMismatch.java b/test/micro/org/openjdk/bench/java/lang/foreign/SegmentBulkMismatch.java index 61ceb7b956e..aa4dd0b68f9 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/SegmentBulkMismatch.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/SegmentBulkMismatch.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, 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 org.openjdk.jmh.annotations.Warmup; import java.lang.foreign.Arena; import java.lang.foreign.MemorySegment; +import java.lang.foreign.ValueLayout; import java.util.Arrays; import java.util.Random; import java.util.concurrent.TimeUnit; @@ -52,60 +53,122 @@ import static java.lang.foreign.ValueLayout.*; @Fork(value = 3) public class SegmentBulkMismatch { - @Param({"2", "3", "4", "5", "6", "7", "8", "64", "512", - "4096", "32768", "262144", "2097152", "16777216", "134217728"}) - public int ELEM_SIZE; + @Param({"2", "4", "8", "12", "16", "64", "512", "4096", "32768", "262144", "2097152", "16777216", "134217728"}) + public int size; - MemorySegment srcNative; - MemorySegment dstNative; - byte[] srcArray; - byte[] dstArray; - MemorySegment srcHeap; - MemorySegment dstHeap; + public static class Array extends SegmentBulkMismatch { - @Setup - public void setup() { - // Always use the same alignment regardless of size - srcNative = Arena.ofAuto().allocate(ELEM_SIZE,16); - dstNative = Arena.ofAuto().allocate(ELEM_SIZE, 16); - var rnd = new Random(42); - for (int i = 0; i < ELEM_SIZE; i++) { - srcNative.set(JAVA_BYTE, i, (byte) rnd.nextInt(Byte.MIN_VALUE, Byte.MAX_VALUE)); + byte[] srcArray; + byte[] dstArray; + + @Setup + public void setup() { + srcArray = new byte[size]; + var rnd = new Random(42); + rnd.nextBytes(srcArray); + dstArray = Arrays.copyOf(srcArray, size); } - dstNative.copyFrom(srcNative); - srcArray = srcNative.toArray(JAVA_BYTE); - dstArray = dstNative.toArray(JAVA_BYTE); - srcHeap = MemorySegment.ofArray(srcArray); - dstHeap = MemorySegment.ofArray(dstArray); + + @Benchmark + public long array() { + return Arrays.mismatch(srcArray, dstArray); + } + } - @Fork(value = 3, jvmArgs = {"-Djava.lang.foreign.native.threshold.power.mismatch=31"}) - @Benchmark - public long nativeSegmentJava() { - return srcNative.mismatch(dstNative); - } + public static class Segment extends SegmentBulkMismatch { - @Fork(value = 3, jvmArgs = {"-Djava.lang.foreign.native.threshold.power.mismatch=31"}) - @Benchmark - public long heapSegmentJava() { - return srcHeap.mismatch(dstHeap); - } + enum SegmentType {HEAP, NATIVE} + enum Alignment {ALIGNED, UNALIGNED} - @Fork(value = 3, jvmArgs = {"-Djava.lang.foreign.native.threshold.power.mismatch=0"}) - @Benchmark - public long nativeSegmentUnsafe() { - return srcNative.mismatch(dstNative); - } + @Param({"HEAP", "NATIVE"}) + String segmentType; - @Fork(value = 3, jvmArgs = {"-Djava.lang.foreign.native.threshold.power.mismatch=0"}) - @Benchmark - public long heapSegmentUnsafe() { - return srcHeap.mismatch(dstHeap); - } + @Param({"ALIGNED", "UNALIGNED"}) + String alignment; + + MemorySegment srcSegment; + MemorySegment dstSegment; + + @Setup + public void setup() { + // A long array is likely to be aligned at 8-byte boundaries + long[] baseArray; + + baseArray = new long[size / Long.BYTES + 1]; + var rnd = new Random(42); + for (int i = 0; i < baseArray.length; i++) { + baseArray[i] = rnd.nextLong(); + } + + switch (SegmentType.valueOf(segmentType)) { + case HEAP -> { + srcSegment = MemorySegment.ofArray(baseArray); + dstSegment = MemorySegment.ofArray(baseArray.clone()); + } + case NATIVE -> { + var s = MemorySegment.ofArray(baseArray); + srcSegment = Arena.ofAuto().allocateFrom(JAVA_LONG, baseArray); + dstSegment = Arena.ofAuto().allocateFrom(JAVA_LONG, baseArray); + } + } + switch (Alignment.valueOf(alignment)) { + case ALIGNED -> { + srcSegment = srcSegment.asSlice(0, size); + dstSegment = dstSegment.asSlice(0, size); + } + case UNALIGNED -> { + srcSegment = srcSegment.asSlice(1, size); + dstSegment = dstSegment.asSlice(1, size); + } + } + } + + @Fork(value = 3, jvmArgs = {"-Djava.lang.foreign.native.threshold.power.mismatch=31"}) + @Benchmark + public long mismatch() { + return srcSegment.mismatch(dstSegment); + } + + @Fork(value = 3, jvmArgs = {"-Djava.lang.foreign.native.threshold.power.mismatch=0"}) + @Benchmark + public long mismatchUnsafe() { + return srcSegment.mismatch(dstSegment); + } + + @Benchmark + public long mismatchLoopIntInt() { + // Simplified version that assumes the segments are of equal size + for (int i = 0; i < (int)srcSegment.byteSize(); i++) { + if (srcSegment.get(ValueLayout.JAVA_BYTE, i) != dstSegment.get(ValueLayout.JAVA_BYTE, i)) { + return i; + } + } + return -1; + } + + @Benchmark + public long mismatchLoopIntLong() { + // Simplified version that assumes the segments are of equal size + for (int i = 0; i < srcSegment.byteSize(); i++) { + if (srcSegment.get(ValueLayout.JAVA_BYTE, i) != dstSegment.get(ValueLayout.JAVA_BYTE, i)) { + return i; + } + } + return -1; + } + + @Benchmark + public long mismatchLoopLongLong() { + // Simplified version that assumes the segments are of equal size + for (long i = 0; i < srcSegment.byteSize(); i++) { + if (srcSegment.get(ValueLayout.JAVA_BYTE, i) != dstSegment.get(ValueLayout.JAVA_BYTE, i)) { + return i; + } + } + return -1; + } - @Benchmark - public long array() { - return Arrays.mismatch(srcArray, dstArray); } } From 10ba0ab3c0017858bafb65b49a4cadd9a0351fb4 Mon Sep 17 00:00:00 2001 From: Harald Eilertsen Date: Wed, 26 Nov 2025 15:33:16 +0000 Subject: [PATCH 024/706] 8371637: allocateNativeInternal sometimes return incorrectly aligned memory Co-authored-by: Kurt Miller Reviewed-by: mcimadamore, jvernee --- .../classes/jdk/internal/foreign/SegmentFactories.java | 4 +++- test/jdk/java/foreign/TestMemoryAlignment.java | 8 +++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/java.base/share/classes/jdk/internal/foreign/SegmentFactories.java b/src/java.base/share/classes/jdk/internal/foreign/SegmentFactories.java index 3edcac2e44c..728ee235547 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/SegmentFactories.java +++ b/src/java.base/share/classes/jdk/internal/foreign/SegmentFactories.java @@ -212,7 +212,9 @@ public class SegmentFactories { allocationBase = allocateMemoryWrapper(allocationSize); result = Utils.alignUp(allocationBase, byteAlignment); } else { - allocationSize = alignedSize; + // always allocate at least 'byteAlignment' bytes, so that malloc is guaranteed to + // return a pointer aligned to that alignment, for cases where byteAlignment > alignedSize + allocationSize = Math.max(alignedSize, byteAlignment); if (shouldReserve) { AbstractMemorySegmentImpl.NIO_ACCESS.reserveMemory(allocationSize, byteSize); } diff --git a/test/jdk/java/foreign/TestMemoryAlignment.java b/test/jdk/java/foreign/TestMemoryAlignment.java index 44d28a07b05..a73635c8f08 100644 --- a/test/jdk/java/foreign/TestMemoryAlignment.java +++ b/test/jdk/java/foreign/TestMemoryAlignment.java @@ -60,8 +60,14 @@ public class TestMemoryAlignment { assertEquals(aligned.byteAlignment(), align); //unreasonable alignment here, to make sure access throws VarHandle vh = aligned.varHandle(); try (Arena arena = Arena.ofConfined()) { - MemorySegment segment = arena.allocate(aligned);; + MemorySegment segment = arena.allocate(aligned); vh.set(segment, 0L, -42); + + // Allocate another segment and fill it with data to + // check that the first segment is not overwritten + MemorySegment nextSegment = arena.allocate(aligned); + vh.set(nextSegment, 0L, 0xffffff); + int val = (int)vh.get(segment, 0L); assertEquals(val, -42); } From c028369dcb0a677541b89117b0800125bc7c6c33 Mon Sep 17 00:00:00 2001 From: Trevor Bond Date: Wed, 26 Nov 2025 15:44:14 +0000 Subject: [PATCH 025/706] 8350938: ResourceParsingClassHierarchyResolver inflates all Utf8 CP entries Reviewed-by: liach, jpai --- .../classfile/impl/ClassHierarchyImpl.java | 37 ++++--------------- 1 file changed, 8 insertions(+), 29 deletions(-) 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 5be14f42baa..e4e67afb17f 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, 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,12 +25,11 @@ */ package jdk.internal.classfile.impl; -import java.io.BufferedInputStream; -import java.io.DataInputStream; import java.io.IOException; import java.io.InputStream; import java.io.UncheckedIOException; import java.lang.classfile.ClassHierarchyResolver; +import java.lang.classfile.constantpool.ClassEntry; import java.lang.constant.ClassDesc; import java.util.Collection; import java.util.HashMap; @@ -38,7 +37,6 @@ import java.util.Map; import java.util.function.Function; import static java.lang.classfile.ClassFile.ACC_INTERFACE; -import static java.lang.classfile.constantpool.PoolEntry.*; import static java.lang.constant.ConstantDescs.CD_Object; import static java.util.Objects.requireNonNull; import static jdk.internal.constant.ConstantUtils.referenceClassDesc; @@ -164,31 +162,12 @@ public final class ClassHierarchyImpl { public ClassHierarchyResolver.ClassHierarchyInfo getClassInfo(ClassDesc classDesc) { var ci = streamProvider.apply(classDesc); if (ci == null) return null; - try (var in = new DataInputStream(new BufferedInputStream(ci))) { - in.skipBytes(8); - int cpLength = in.readUnsignedShort(); - String[] cpStrings = new String[cpLength]; - int[] cpClasses = new int[cpLength]; - for (int i = 1; i < cpLength; i++) { - int tag; - switch (tag = in.readUnsignedByte()) { - case TAG_UTF8 -> cpStrings[i] = in.readUTF(); - case TAG_CLASS -> cpClasses[i] = in.readUnsignedShort(); - 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++; - } - default -> throw new IllegalStateException("Bad tag (" + tag + ") at index (" + i + ")"); - } - } - boolean isInterface = (in.readUnsignedShort() & ACC_INTERFACE) != 0; - in.skipBytes(2); - int superIndex = in.readUnsignedShort(); - var superClass = superIndex > 0 ? ClassDesc.ofInternalName(cpStrings[cpClasses[superIndex]]) : null; + try (ci) { + var reader = new ClassReaderImpl(ci.readAllBytes(), ClassFileImpl.DEFAULT_CONTEXT); + boolean isInterface = (reader.flags() & ACC_INTERFACE) != 0; + ClassDesc superClass = reader.superclassEntry() + .map(ClassEntry::asSymbol) + .orElse(null); return new ClassHierarchyInfoImpl(superClass, isInterface); } catch (IOException ioe) { throw new UncheckedIOException(ioe); From 6e920fbdab17201886804bb53b59188b362f541d Mon Sep 17 00:00:00 2001 From: David Holmes Date: Wed, 26 Nov 2025 20:01:29 +0000 Subject: [PATCH 026/706] 8372380: Make hs_err reporting more robust for unattached threads Reviewed-by: shade, aboldtch, kevinw --- src/hotspot/share/compiler/compilationMemoryStatistic.cpp | 6 ++++-- src/hotspot/share/gc/g1/g1CollectedHeap.cpp | 3 ++- src/hotspot/share/gc/shared/gcLogPrecious.cpp | 4 +++- src/hotspot/share/utilities/vmError.cpp | 3 ++- 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/hotspot/share/compiler/compilationMemoryStatistic.cpp b/src/hotspot/share/compiler/compilationMemoryStatistic.cpp index d1e2f6f34a0..1951fd066fc 100644 --- a/src/hotspot/share/compiler/compilationMemoryStatistic.cpp +++ b/src/hotspot/share/compiler/compilationMemoryStatistic.cpp @@ -1010,8 +1010,10 @@ void CompilationMemoryStatistic::print_error_report(outputStream* st) { oom_stats->print_peak_state_on(st); st->cr(); } - st->print_cr("Compiler Memory Statistic, 10 most expensive compilations:"); - print_all_by_size(st, false, false, 0, 10); + if (Thread::current_or_null_safe() != nullptr) { + st->print_cr("Compiler Memory Statistic, 10 most expensive compilations:"); + print_all_by_size(st, false, false, 0, 10); + } } void CompilationMemoryStatistic::print_final_report(outputStream* st) { diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp index 5567d84bee4..061241c24e2 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp @@ -2355,7 +2355,8 @@ static void print_region_type(outputStream* st, const char* type, uint count, bo } void G1CollectedHeap::print_heap_on(outputStream* st) const { - size_t heap_used = Heap_lock->owned_by_self() ? used() : used_unlocked(); + size_t heap_used = (Thread::current_or_null_safe() != nullptr && + Heap_lock->owned_by_self()) ? used() : used_unlocked(); st->print("%-20s", "garbage-first heap"); st->print(" total reserved %zuK, committed %zuK, used %zuK", _hrm.reserved().byte_size()/K, capacity()/K, heap_used/K); diff --git a/src/hotspot/share/gc/shared/gcLogPrecious.cpp b/src/hotspot/share/gc/shared/gcLogPrecious.cpp index 43bd58db1aa..d556eed1b69 100644 --- a/src/hotspot/share/gc/shared/gcLogPrecious.cpp +++ b/src/hotspot/share/gc/shared/gcLogPrecious.cpp @@ -25,6 +25,7 @@ #include "runtime/mutex.hpp" #include "runtime/mutexLocker.hpp" #include "runtime/os.hpp" +#include "runtime/thread.hpp" #include "utilities/ostream.hpp" stringStream* GCLogPrecious::_lines = nullptr; @@ -83,7 +84,8 @@ void GCLogPrecious::print_on_error(outputStream* st) { return; } - if (!_lock->try_lock_without_rank_check()) { + if (Thread::current_or_null_safe() == nullptr || + !_lock->try_lock_without_rank_check()) { st->print_cr("\n"); return; } diff --git a/src/hotspot/share/utilities/vmError.cpp b/src/hotspot/share/utilities/vmError.cpp index e0cbb60c744..a290602e0be 100644 --- a/src/hotspot/share/utilities/vmError.cpp +++ b/src/hotspot/share/utilities/vmError.cpp @@ -664,6 +664,7 @@ void VMError::report(outputStream* st, bool _verbose) { BEGIN if (MemTracker::enabled() && NmtVirtualMemory_lock != nullptr && + _thread != nullptr && NmtVirtualMemory_lock->owned_by_self()) { // Manually unlock to avoid reentrancy due to mallocs in detailed mode. NmtVirtualMemory_lock->unlock(); @@ -1305,7 +1306,7 @@ void VMError::report(outputStream* st, bool _verbose) { os::print_signal_handlers(st, buf, sizeof(buf)); st->cr(); - STEP_IF("Native Memory Tracking", _verbose) + STEP_IF("Native Memory Tracking", _verbose && _thread != nullptr) MemTracker::error_report(st); st->cr(); From 42db9ab629a6209aa471de8b3034c053b77629dd Mon Sep 17 00:00:00 2001 From: Sergey Bylokhov Date: Wed, 26 Nov 2025 22:12:41 +0000 Subject: [PATCH 027/706] 8298432: Investigate the benefits of usage of GetPrimitiveArrayCritical in the cmm code Reviewed-by: psadhukhan, jdv, azvegint --- .../classes/sun/java2d/cmm/lcms/LCMS.java | 5 +- .../sun/java2d/cmm/lcms/LCMSImageLayout.java | 20 +----- .../sun/java2d/cmm/lcms/LCMSTransform.java | 3 +- src/java.desktop/share/native/liblcms/LCMS.c | 66 ++++--------------- 4 files changed, 19 insertions(+), 75 deletions(-) diff --git a/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMS.java b/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMS.java index 63a1359323f..24b50003e3c 100644 --- a/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMS.java +++ b/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMS.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2025, 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 @@ -136,8 +136,7 @@ final class LCMS implements PCMM { static native void colorConvert(long trans, int width, int height, int srcOffset, int srcNextRowOffset, int dstOffset, int dstNextRowOffset, - Object srcData, Object dstData, - int srcType, int dstType); + Object srcData, Object dstData); private LCMS() {} diff --git a/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMSImageLayout.java b/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMSImageLayout.java index 663e11ff172..c7bae875282 100644 --- a/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMSImageLayout.java +++ b/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMSImageLayout.java @@ -31,7 +31,6 @@ import java.awt.image.ColorModel; import java.awt.image.ComponentColorModel; import java.awt.image.ComponentSampleModel; import java.awt.image.Raster; -import java.lang.annotation.Native; import java.nio.ByteOrder; import sun.awt.image.ByteComponentRaster; @@ -69,14 +68,7 @@ final class LCMSImageLayout { // private static final int PT_BGRA_8 = PT_ABGR_8 | SWAPFIRST; private static final int SWAP_ENDIAN = ByteOrder.nativeOrder() == LITTLE_ENDIAN ? DOSWAP : 0; - @Native - private static final int DT_BYTE = 0; - @Native - private static final int DT_SHORT = 1; - @Native - private static final int DT_INT = 2; int pixelType; - int dataType; int width; int height; int nextRowOffset; @@ -93,12 +85,10 @@ final class LCMSImageLayout { * @param data the storage of pixels: {@code byte[], short[] or int[]} * @param length the length of the data array * @param nc the number of color components - * @param dt the type of data array: DT_BYTE, DT_SHORT or DT_INT * @param size the size of one color component in bytes */ - private LCMSImageLayout(Object data, int length, int nc, int dt, int size) { + private LCMSImageLayout(Object data, int length, int nc, int size) { dataArray = data; - dataType = dt; dataArrayLength = length * size; pixelType = CHANNELS_SH(nc) | BYTES_SH(size); width = length / nc; @@ -109,11 +99,11 @@ final class LCMSImageLayout { } LCMSImageLayout(byte[] data, int nc) { - this(data, data.length, nc, DT_BYTE, Byte.BYTES); + this(data, data.length, nc, Byte.BYTES); } LCMSImageLayout(short[] data, int nc) { - this(data, data.length, nc, DT_SHORT, Short.BYTES); + this(data, data.length, nc, Short.BYTES); } private LCMSImageLayout() { @@ -186,7 +176,6 @@ final class LCMSImageLayout { l.offset = safeMult(4, intRaster.getDataOffset(0)); l.dataArray = intRaster.getDataStorage(); l.dataArrayLength = 4 * intRaster.getDataStorage().length; - l.dataType = DT_INT; } case BufferedImage.TYPE_BYTE_GRAY, BufferedImage.TYPE_3BYTE_BGR, BufferedImage.TYPE_4BYTE_ABGR, @@ -201,7 +190,6 @@ final class LCMSImageLayout { l.offset = byteRaster.getDataOffset(firstBand); l.dataArray = byteRaster.getDataStorage(); l.dataArrayLength = byteRaster.getDataStorage().length; - l.dataType = DT_BYTE; } case BufferedImage.TYPE_USHORT_GRAY -> { if (!(raster instanceof ShortComponentRaster shortRaster)) { @@ -212,7 +200,6 @@ final class LCMSImageLayout { l.offset = safeMult(2, shortRaster.getDataOffset(0)); l.dataArray = shortRaster.getDataStorage(); l.dataArrayLength = 2 * shortRaster.getDataStorage().length; - l.dataType = DT_SHORT; } default -> { return null; @@ -319,7 +306,6 @@ final class LCMSImageLayout { l.nextPixelOffset = br.getPixelStride(); l.offset = br.getDataOffset(firstBand); - l.dataType = DT_BYTE; byte[] data = br.getDataStorage(); l.dataArray = data; l.dataArrayLength = data.length; diff --git a/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMSTransform.java b/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMSTransform.java index 881a6556ace..3f4f510cf94 100644 --- a/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMSTransform.java +++ b/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMSTransform.java @@ -121,8 +121,7 @@ final class LCMSTransform implements ColorTransform { } LCMS.colorConvert(tfm.ID, in.width, in.height, in.offset, in.nextRowOffset, out.offset, out.nextRowOffset, - in.dataArray, out.dataArray, - in.dataType, out.dataType); + in.dataArray, out.dataArray); Reference.reachabilityFence(tfm); // prevent deallocation of "tfm.ID" } diff --git a/src/java.desktop/share/native/liblcms/LCMS.c b/src/java.desktop/share/native/liblcms/LCMS.c index 5cf7ee6c436..5d4ace7a624 100644 --- a/src/java.desktop/share/native/liblcms/LCMS.c +++ b/src/java.desktop/share/native/liblcms/LCMS.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2025, 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,7 +27,6 @@ #include #include #include "sun_java2d_cmm_lcms_LCMS.h" -#include "sun_java2d_cmm_lcms_LCMSImageLayout.h" #include "jni_util.h" #include "Trace.h" #include "Disposer.h" @@ -46,10 +45,6 @@ #define SigHead TagIdConst('h','e','a','d') -#define DT_BYTE sun_java2d_cmm_lcms_LCMSImageLayout_DT_BYTE -#define DT_SHORT sun_java2d_cmm_lcms_LCMSImageLayout_DT_SHORT -#define DT_INT sun_java2d_cmm_lcms_LCMSImageLayout_DT_INT - /* Default temp profile list size */ #define DF_ICC_BUF_SIZE 32 @@ -464,46 +459,17 @@ JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_setTagDataNative } } -static void *getILData(JNIEnv *env, jobject data, jint type) { - switch (type) { - case DT_BYTE: - return (*env)->GetByteArrayElements(env, data, 0); - case DT_SHORT: - return (*env)->GetShortArrayElements(env, data, 0); - case DT_INT: - return (*env)->GetIntArrayElements(env, data, 0); - default: - return NULL; - } -} - -static void releaseILData(JNIEnv *env, void *pData, jint type, jobject data, - jint mode) { - switch (type) { - case DT_BYTE: - (*env)->ReleaseByteArrayElements(env, data, (jbyte *) pData, mode); - break; - case DT_SHORT: - (*env)->ReleaseShortArrayElements(env, data, (jshort *) pData, mode); - break; - case DT_INT: - (*env)->ReleaseIntArrayElements(env, data, (jint *) pData, mode); - break; - } -} - /* * Class: sun_java2d_cmm_lcms_LCMS * Method: colorConvert - * Signature: (JIIIIIIZZLjava/lang/Object;Ljava/lang/Object;)V + * Signature: (JIIIIIILjava/lang/Object;Ljava/lang/Object;)V */ JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_colorConvert (JNIEnv *env, jclass cls, jlong ID, jint width, jint height, jint srcOffset, jint srcNextRowOffset, jint dstOffset, jint dstNextRowOffset, - jobject srcData, jobject dstData, jint srcDType, jint dstDType) + jobject srcData, jobject dstData) { cmsHTRANSFORM sTrans = jlong_to_ptr(ID); - if (sTrans == NULL) { J2dRlsTraceLn(J2D_TRACE_ERROR, "LCMS_colorConvert: transform == NULL"); JNU_ThrowByName(env, "java/awt/color/CMMException", @@ -511,28 +477,22 @@ JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_colorConvert return; } - void *inputBuffer = getILData(env, srcData, srcDType); + void *inputBuffer = (*env)->GetPrimitiveArrayCritical(env, srcData, NULL); if (inputBuffer == NULL) { - J2dRlsTraceLn(J2D_TRACE_ERROR, ""); // An exception should have already been thrown. return; } + void *outputBuffer = (*env)->GetPrimitiveArrayCritical(env, dstData, NULL); + if (outputBuffer != NULL) { + char *input = (char *) inputBuffer + srcOffset; + char *output = (char *) outputBuffer + dstOffset; - void *outputBuffer = getILData(env, dstData, dstDType); - if (outputBuffer == NULL) { - releaseILData(env, inputBuffer, srcDType, srcData, JNI_ABORT); - // An exception should have already been thrown. - return; + cmsDoTransformLineStride(sTrans, input, output, width, height, + srcNextRowOffset, dstNextRowOffset, 0, 0); + + (*env)->ReleasePrimitiveArrayCritical(env, dstData, outputBuffer, 0); } - - char *input = (char *) inputBuffer + srcOffset; - char *output = (char *) outputBuffer + dstOffset; - - cmsDoTransformLineStride(sTrans, input, output, width, height, - srcNextRowOffset, dstNextRowOffset, 0, 0); - - releaseILData(env, inputBuffer, srcDType, srcData, JNI_ABORT); - releaseILData(env, outputBuffer, dstDType, dstData, 0); + (*env)->ReleasePrimitiveArrayCritical(env, srcData, inputBuffer, JNI_ABORT); } static cmsBool _getHeaderInfo(cmsHPROFILE pf, jbyte* pBuffer, jint bufferSize) From 847fbab7924848e0e88d112db1d5d0b71372d597 Mon Sep 17 00:00:00 2001 From: Leonid Mesnik Date: Wed, 26 Nov 2025 22:17:19 +0000 Subject: [PATCH 028/706] 8352654: [REDO] nsk/jvmti/ tests should fail when nsk_jvmti_setFailStatus() is called Reviewed-by: amenkov, sspitsyn --- test/hotspot/jtreg/ProblemList.txt | 1 + .../jtreg/vmTestbase/nsk/share/jvmti/agent_tools.cpp | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index 934ef03a987..55a43663568 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -167,6 +167,7 @@ vmTestbase/metaspace/gc/firstGC_99m/TestDescription.java 8208250 generic-all vmTestbase/metaspace/gc/firstGC_default/TestDescription.java 8208250 generic-all vmTestbase/nsk/jvmti/scenarios/capability/CM03/cm03t001/TestDescription.java 8073470 linux-all +vmTestbase/nsk/jvmti/scenarios/events/EM02/em02t006/TestDescription.java 8372206 generic-all vmTestbase/nsk/jvmti/InterruptThread/intrpthrd003/TestDescription.java 8288911 macosx-all vmTestbase/jit/escape/LockCoarsening/LockCoarsening001.java 8148743 generic-all diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jvmti/agent_tools.cpp b/test/hotspot/jtreg/vmTestbase/nsk/share/jvmti/agent_tools.cpp index 0b43e5ac782..ae2fb040dde 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/share/jvmti/agent_tools.cpp +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jvmti/agent_tools.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, 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 @@ -21,6 +21,7 @@ * questions. */ +#include #include #include @@ -62,6 +63,9 @@ static volatile int currentAgentStatus = NSK_STATUS_PASSED; void nsk_jvmti_setFailStatus() { currentAgentStatus = NSK_STATUS_FAILED; + printf("Test failed by setFailStatus(). See log."); + fflush(stdout); + exit(97); } int nsk_jvmti_isFailStatus() { From b054a5657105ace7e66f6044692e14bb075dfb6c Mon Sep 17 00:00:00 2001 From: Alexander Matveev Date: Thu, 27 Nov 2025 03:06:14 +0000 Subject: [PATCH 029/706] 8351095: [macos] Add more jpackage tests for --mac-app-store option Reviewed-by: asemenyuk --- .../test/LauncherAsServiceVerifier.java | 10 ++++- .../helpers/jdk/jpackage/test/MacHelper.java | 9 +++++ .../jdk/jpackage/test/PropertyFinder.java | 6 ++- .../tools/jpackage/macosx/PkgScriptsTest.java | 39 +++++++++++-------- .../jdk/tools/jpackage/share/ServiceTest.java | 26 ++++++++++--- 5 files changed, 65 insertions(+), 25 deletions(-) diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherAsServiceVerifier.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherAsServiceVerifier.java index 0be6cf685f6..09a46ecb7d1 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherAsServiceVerifier.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherAsServiceVerifier.java @@ -149,7 +149,11 @@ public final class LauncherAsServiceVerifier { applyToAdditionalLauncher(target); } target.test().ifPresent(pkg -> { - pkg.addInstallVerifier(this::verifyLauncherExecuted); + pkg.addInstallVerifier(cmd -> { + if (!MacHelper.isForAppStore(cmd)) { + verifyLauncherExecuted(cmd); + } + }); }); } @@ -239,7 +243,9 @@ public final class LauncherAsServiceVerifier { } static boolean launcherAsService(JPackageCommand cmd, String launcherName) { - if (cmd.isMainLauncher(launcherName)) { + if (MacHelper.isForAppStore(cmd)) { + return false; + } else if (cmd.isMainLauncher(launcherName)) { return PropertyFinder.findLauncherProperty(cmd, null, PropertyFinder.cmdlineBooleanOption("--launcher-as-service"), PropertyFinder.nop(), diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java index a6d24af2b25..caeb0a206fc 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java @@ -797,6 +797,15 @@ public final class MacHelper { ).orElseGet(cmd::name); } + public static boolean isForAppStore(JPackageCommand cmd) { + return PropertyFinder.findAppProperty(cmd, + PropertyFinder.cmdlineBooleanOption("--mac-app-store"), + PropertyFinder.appImageFile(appImageFile -> { + return Boolean.toString(appImageFile.macAppStore()); + }) + ).map(Boolean::parseBoolean).orElse(false); + } + public static boolean isXcodeDevToolsInstalled() { return Inner.XCODE_DEV_TOOLS_INSTALLED; } diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PropertyFinder.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PropertyFinder.java index 6c612fa9ba5..3d7ac490350 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PropertyFinder.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PropertyFinder.java @@ -106,7 +106,11 @@ final class PropertyFinder { static Finder cmdlineBooleanOption(String optionName) { return target -> { - return Optional.of(target.hasArgument(optionName)).map(Boolean::valueOf).map(Object::toString); + if (target.hasArgument(optionName)) { + return Optional.of(Boolean.TRUE.toString()); + } else { + return Optional.empty(); + } }; } diff --git a/test/jdk/tools/jpackage/macosx/PkgScriptsTest.java b/test/jdk/tools/jpackage/macosx/PkgScriptsTest.java index f52191f4a05..9ee85ae5245 100644 --- a/test/jdk/tools/jpackage/macosx/PkgScriptsTest.java +++ b/test/jdk/tools/jpackage/macosx/PkgScriptsTest.java @@ -22,6 +22,7 @@ */ import java.nio.file.Path; +import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.List; @@ -32,6 +33,7 @@ import jdk.jpackage.test.Annotations.ParameterSupplier; import jdk.jpackage.test.Annotations.Test; import jdk.jpackage.test.JPackageCommand; import jdk.jpackage.test.JPackageStringBundle; +import jdk.jpackage.test.MacHelper; import jdk.jpackage.test.PackageTest; import jdk.jpackage.test.PackageType; import jdk.jpackage.test.TKit; @@ -50,24 +52,23 @@ import jdk.jpackage.test.TKit; */ public class PkgScriptsTest { - public static Collection input() { - return List.of(new Object[][]{ - { new PkgInstallScript[]{ - PkgInstallScript.PREINSTALL, - PkgInstallScript.POSTINSTALL }, - }, - { new PkgInstallScript[]{ - PkgInstallScript.PREINSTALL }, - }, - { new PkgInstallScript[]{ - PkgInstallScript.POSTINSTALL }, - }, - }); + public static Collection input() { + List data = new ArrayList<>(); + for (var appStore : List.of(true, false)) { + for (var scriptRoles : List.of( + List.of(PkgInstallScript.PREINSTALL, PkgInstallScript.POSTINSTALL), + List.of(PkgInstallScript.PREINSTALL), + List.of(PkgInstallScript.POSTINSTALL) + )) { + data.add(new Object[] {scriptRoles.toArray(PkgInstallScript[]::new), appStore}); + } + } + return data; } @Test @ParameterSupplier("input") - public void test(PkgInstallScript[] customScriptRoles) { + public void test(PkgInstallScript[] customScriptRoles, boolean appStore) { var responseDir = TKit.createTempDirectory("response"); var customScripts = Stream.of(customScriptRoles).map(role -> { @@ -80,6 +81,9 @@ public class PkgScriptsTest { .forTypes(PackageType.MAC_PKG) .configureHelloApp() .addInitializer(cmd -> { + if (appStore) { + cmd.addArgument("--mac-app-store"); + } cmd.addArguments("--resource-dir", TKit.createTempDirectory("resources")); customScripts.forEach(customScript -> { customScript.createFor(cmd); @@ -156,10 +160,13 @@ public class PkgScriptsTest { } void verify(JPackageCommand cmd) { + var scriptsEnabled = !MacHelper.isForAppStore(cmd); if (cmd.isPackageUnpacked()) { - role.verifyExists(cmd, true); - } else { + role.verifyExists(cmd, scriptsEnabled); + } else if (scriptsEnabled) { TKit.assertFileExists(responseFilePath(cmd)); + } else { + TKit.assertPathExists(responseFilePath(cmd), false); } } diff --git a/test/jdk/tools/jpackage/share/ServiceTest.java b/test/jdk/tools/jpackage/share/ServiceTest.java index 226f8f16bdc..94d3421a2cd 100644 --- a/test/jdk/tools/jpackage/share/ServiceTest.java +++ b/test/jdk/tools/jpackage/share/ServiceTest.java @@ -33,6 +33,7 @@ import java.util.Optional; import java.util.function.Consumer; import java.util.stream.Stream; import jdk.jpackage.test.AdditionalLauncher; +import jdk.internal.util.OperatingSystem; import jdk.jpackage.test.Annotations.Parameter; import jdk.jpackage.test.Annotations.Test; import jdk.jpackage.test.ConfigurationTarget; @@ -155,14 +156,21 @@ public class ServiceTest { } @Test - @Parameter("true") - @Parameter("false") - public void testAddL(boolean mainLauncherAsService) { + @Parameter(value = {"true", "false"}) + @Parameter(value = {"false", "false"}) + @Parameter(value = {"true", "true"}, ifOS = OperatingSystem.MACOS) + @Parameter(value = {"false", "true"}, ifOS = OperatingSystem.MACOS) + public void testAddL(boolean mainLauncherAsService, boolean isMacAppStore) { final var uniqueOutputFile = uniqueOutputFile(); createPackageTest() .addHelloAppInitializer("com.buz.AddLaunchersServiceTest") + .addInitializer(cmd -> { + if (isMacAppStore) { + cmd.addArgument("--mac-app-store"); + } + }) .mutate(test -> { if (mainLauncherAsService) { LauncherAsServiceVerifier.build() @@ -199,9 +207,11 @@ public class ServiceTest { } @Test - @Parameter("true") - @Parameter("false") - public void testAddLFromAppImage(boolean mainLauncherAsService) { + @Parameter(value = {"true", "false"}) + @Parameter(value = {"false", "false"}) + @Parameter(value = {"true", "true"}, ifOS = OperatingSystem.MACOS) + @Parameter(value = {"false", "true"}, ifOS = OperatingSystem.MACOS) + public void testAddLFromAppImage(boolean mainLauncherAsService, boolean isMacAppStore) { var uniqueOutputFile = uniqueOutputFile(); @@ -213,6 +223,10 @@ public class ServiceTest { appImageCmd.addInitializer(JPackageCommand::ignoreFakeRuntime); } + if (isMacAppStore) { + appImageCmd.cmd().orElseThrow().addArgument("--mac-app-store"); + } + if (mainLauncherAsService) { LauncherAsServiceVerifier.build() .mutate(uniqueOutputFile).appendAppOutputFileNamePrefix("-") From 55362e191d447c2116f111cef438700eca24aab1 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Thu, 27 Nov 2025 04:18:20 +0000 Subject: [PATCH 030/706] 8372385: tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/MainTest.java fails Reviewed-by: almatvee --- .../jdk/jpackage/internal/cli/MainTest.java | 65 +++++++++++++++++-- 1 file changed, 59 insertions(+), 6 deletions(-) diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/MainTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/MainTest.java index 41142382c39..246b3722cbf 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/MainTest.java +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/MainTest.java @@ -36,6 +36,8 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Objects; +import java.util.Optional; +import java.util.function.BiFunction; import java.util.stream.Stream; import jdk.internal.util.OperatingSystem; import jdk.jpackage.test.JUnitAdapter; @@ -58,7 +60,9 @@ public class MainTest extends JUnitAdapter.TestSrcInitializer { // Print the tool version build().args("--version").expectVersion(), // Print the tool version - build().args("foo", "bar").expectErrors(I18N.format("error.non-option-arguments", 2)), + // Additional error messages may be printed if the default bundling operation + // can not be identified; don't verify these errors in the output. + build().args("foo", "bar").stderrMatchType(OutputMatchType.STARTS_WITH).expectErrors(I18N.format("error.non-option-arguments", 2)), // Valid command line requesting to print the full help. build().args("-h").expectFullHelp(), // Valid command line requesting to build a package and print the full help. @@ -68,12 +72,14 @@ public class MainTest extends JUnitAdapter.TestSrcInitializer { // Valid command line requesting to print the full help and the version of the tool. build().args("--help", "--version").expectVersionWithHelp(), // Invalid command line requesting to print the version of the tool. - build().args("foo", "--version").expectErrors(I18N.format("error.non-option-arguments", 1)) + // Additional error messages may be printed if the default bundling operation + // can not be identified; don't verify these errors in the output. + build().args("foo", "--version").stderrMatchType(OutputMatchType.STARTS_WITH).expectErrors(I18N.format("error.non-option-arguments", 1)) ).map(TestSpec.Builder::create).toList(); } - record TestSpec(List args, int expectedExitCode, List expectedStdout, List expectedStderr) { + record TestSpec(List args, int expectedExitCode, ExpectedOutput expectedStdout, ExpectedOutput expectedStderr) { TestSpec { Objects.requireNonNull(args); @@ -84,15 +90,19 @@ public class MainTest extends JUnitAdapter.TestSrcInitializer { void run() { var result = ExecutionResult.create(args.toArray(String[]::new)); assertEquals(expectedExitCode, result.exitCode()); - assertEquals(expectedStdout, result.stdout()); - assertEquals(expectedStderr, result.stderr()); + expectedStdout.test(result.stdout()); + expectedStderr.test(result.stderr()); } static final class Builder { TestSpec create() { - return new TestSpec(args, expectedExitCode, expectedStdout, expectedStderr); + return new TestSpec( + args, + expectedExitCode, + new ExpectedOutput(expectedStdout, Optional.ofNullable(stdoutMatchType).orElse(OutputMatchType.EQUALS)), + new ExpectedOutput(expectedStderr, Optional.ofNullable(stderrMatchType).orElse(OutputMatchType.EQUALS))); } Builder args(String... v) { @@ -104,6 +114,16 @@ public class MainTest extends JUnitAdapter.TestSrcInitializer { return this; } + Builder stdoutMatchType(OutputMatchType v) { + stdoutMatchType = v; + return this; + } + + Builder stderrMatchType(OutputMatchType v) { + stderrMatchType = v; + return this; + } + Builder expectStdout(String... lines) { return expectStdout(List.of(lines)); } @@ -164,6 +184,8 @@ public class MainTest extends JUnitAdapter.TestSrcInitializer { private List args = new ArrayList<>(); private int expectedExitCode; + private OutputMatchType stdoutMatchType; + private OutputMatchType stderrMatchType; private List expectedStdout = new ArrayList<>(); private List expectedStderr = new ArrayList<>(); } @@ -188,6 +210,37 @@ public class MainTest extends JUnitAdapter.TestSrcInitializer { } + private enum OutputMatchType { + EQUALS((_, actual) -> actual), + STARTS_WITH((expected, actual) -> { + if (expected.size() < actual.size()) { + return actual.subList(0, expected.size()); + } + return actual; + }), + ; + + OutputMatchType(BiFunction, List, List> mapper) { + this.mapper = Objects.requireNonNull(mapper); + } + + private final BiFunction, List, List> mapper; + } + + + private record ExpectedOutput(List content, OutputMatchType type) { + ExpectedOutput { + Objects.requireNonNull(content); + Objects.requireNonNull(type); + } + + void test(List lines) { + var filteredLines = type.mapper.apply(content, lines); + assertEquals(content, filteredLines); + } + } + + private static TestSpec.Builder build() { return new TestSpec.Builder(); } From 848c0c79b69c489db6c6bbb24644134fe33fd0ec Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Thu, 27 Nov 2025 05:29:46 +0000 Subject: [PATCH 031/706] 8372285: G1: Micro-optimize x86 barrier code Reviewed-by: tschatzl, ayang --- .../x86/gc/g1/g1BarrierSetAssembler_x86.cpp | 130 ++++++++---------- 1 file changed, 61 insertions(+), 69 deletions(-) diff --git a/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.cpp b/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.cpp index 586135fcebc..34de9403ccf 100644 --- a/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.cpp @@ -89,10 +89,10 @@ void G1BarrierSetAssembler::gen_write_ref_array_pre_barrier(MacroAssembler* masm void G1BarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators, Register addr, Register count, Register tmp) { - Label done; + Label L_done; __ testptr(count, count); - __ jcc(Assembler::zero, done); + __ jccb(Assembler::zero, L_done); // Calculate end address in "count". Address::ScaleFactor scale = UseCompressedOops ? Address::times_4 : Address::times_8; @@ -111,31 +111,31 @@ void G1BarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* mas __ shrptr(count, CardTable::card_shift()); __ addptr(count, tmp); - Label loop; + Label L_loop; // Iterate from start card to end card (inclusive). - __ bind(loop); + __ bind(L_loop); - Label is_clean_card; + Label L_is_clean_card; if (UseCondCardMark) { __ cmpb(Address(addr, 0), G1CardTable::clean_card_val()); - __ jcc(Assembler::equal, is_clean_card); + __ jccb(Assembler::equal, L_is_clean_card); } else { __ movb(Address(addr, 0), G1CardTable::dirty_card_val()); } - Label next_card; - __ bind(next_card); + Label L_next_card; + __ bind(L_next_card); __ addptr(addr, sizeof(CardTable::CardValue)); __ cmpptr(addr, count); - __ jcc(Assembler::belowEqual, loop); - __ jmp(done); + __ jccb(Assembler::belowEqual, L_loop); + __ jmpb(L_done); - __ bind(is_clean_card); - // Card was clean. Dirty card and go to next.. + __ bind(L_is_clean_card); + // Card was clean. Dirty card and go to next. __ movb(Address(addr, 0), G1CardTable::dirty_card_val()); - __ jmp(next_card); + __ jmpb(L_next_card); - __ bind(done); + __ bind(L_done); } void G1BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, @@ -157,22 +157,6 @@ void G1BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorator } } -static void generate_queue_insertion(MacroAssembler* masm, ByteSize index_offset, ByteSize buffer_offset, Label& runtime, - const Register thread, const Register value, const Register temp) { - // This code assumes that buffer index is pointer sized. - STATIC_ASSERT(in_bytes(SATBMarkQueue::byte_width_of_index()) == sizeof(intptr_t)); - // Can we store a value in the given thread's buffer? - // (The index field is typed as size_t.) - __ movptr(temp, Address(thread, in_bytes(index_offset))); // temp := *(index address) - __ testptr(temp, temp); // index == 0? - __ jcc(Assembler::zero, runtime); // jump to runtime if index == 0 (full buffer) - // The buffer is not full, store value into it. - __ subptr(temp, wordSize); // temp := next index - __ movptr(Address(thread, in_bytes(index_offset)), temp); // *(index address) := next index - __ addptr(temp, Address(thread, in_bytes(buffer_offset))); // temp := buffer address + next index - __ movptr(Address(temp, 0), value); // *(buffer address + next index) := value -} - static void generate_pre_barrier_fast_path(MacroAssembler* masm, const Register thread) { Address in_progress(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset())); @@ -190,21 +174,40 @@ static void generate_pre_barrier_slow_path(MacroAssembler* masm, const Register pre_val, const Register thread, const Register tmp, - Label& done, - Label& runtime) { + Label& L_done) { + Address index_addr(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset())); + Address buffer_addr(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset())); + + // This code assumes that buffer index is pointer sized. + STATIC_ASSERT(in_bytes(SATBMarkQueue::byte_width_of_index()) == sizeof(intptr_t)); + + Label L_runtime; + // Do we need to load the previous value? if (obj != noreg) { __ load_heap_oop(pre_val, Address(obj, 0), noreg, AS_RAW); } + // Is the previous value null? - __ cmpptr(pre_val, NULL_WORD); - __ jcc(Assembler::equal, done); - generate_queue_insertion(masm, - G1ThreadLocalData::satb_mark_queue_index_offset(), - G1ThreadLocalData::satb_mark_queue_buffer_offset(), - runtime, - thread, pre_val, tmp); - __ jmp(done); + __ testptr(pre_val, pre_val); + __ jcc(Assembler::equal, L_done); + + // Can we store a value in the given thread's buffer? + // (The index field is typed as size_t.) + __ movptr(tmp, index_addr); // temp := *(index address) + __ testptr(tmp, tmp); // index == 0? + __ jccb(Assembler::zero, L_runtime); // jump to runtime if index == 0 (full buffer) + + // The buffer is not full, store value into it. + __ subptr(tmp, wordSize); // temp := next index + __ movptr(index_addr, tmp); // *(index address) := next index + __ addptr(tmp, buffer_addr); // temp := buffer address + next index + __ movptr(Address(tmp, 0), pre_val); // *(buffer address + next index) := value + + // Jump out if done, or fall-through to runtime. + // "L_done" is far away, so jump cannot be short. + __ jmp(L_done); + __ bind(L_runtime); } void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm, @@ -219,7 +222,6 @@ void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm, const Register thread = r15_thread; Label done; - Label runtime; assert(pre_val != noreg, "check this code"); @@ -231,9 +233,7 @@ void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm, generate_pre_barrier_fast_path(masm, thread); // If marking is not active (*(mark queue active address) == 0), jump to done __ jcc(Assembler::equal, done); - generate_pre_barrier_slow_path(masm, obj, pre_val, thread, tmp, done, runtime); - - __ bind(runtime); + generate_pre_barrier_slow_path(masm, obj, pre_val, thread, tmp, done); // Determine and save the live input values __ push_call_clobbered_registers(); @@ -272,23 +272,23 @@ static void generate_post_barrier(MacroAssembler* masm, const Register store_addr, const Register new_val, const Register tmp1, - Label& done, bool new_val_may_be_null) { assert_different_registers(store_addr, new_val, tmp1, noreg); Register thread = r15_thread; + Label L_done; // Does store cross heap regions? __ movptr(tmp1, store_addr); // tmp1 := store address __ xorptr(tmp1, new_val); // tmp1 := store address ^ new value __ shrptr(tmp1, G1HeapRegion::LogOfHRGrainBytes); // ((store address ^ new value) >> LogOfHRGrainBytes) == 0? - __ jcc(Assembler::equal, done); + __ jccb(Assembler::equal, L_done); // Crosses regions, storing null? if (new_val_may_be_null) { - __ cmpptr(new_val, NULL_WORD); // new value == null? - __ jcc(Assembler::equal, done); + __ testptr(new_val, new_val); // new value == null? + __ jccb(Assembler::equal, L_done); } __ movptr(tmp1, store_addr); // tmp1 := store address @@ -298,20 +298,19 @@ static void generate_post_barrier(MacroAssembler* masm, __ addptr(tmp1, card_table_addr); // tmp1 := card address if (UseCondCardMark) { __ cmpb(Address(tmp1, 0), G1CardTable::clean_card_val()); // *(card address) == clean_card_val? - __ jcc(Assembler::notEqual, done); + __ jccb(Assembler::notEqual, L_done); } // Storing a region crossing, non-null oop, card is clean. // Dirty card. __ movb(Address(tmp1, 0), G1CardTable::dirty_card_val()); // *(card address) := dirty_card_val + __ bind(L_done); } void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm, Register store_addr, Register new_val, Register tmp) { - Label done; - generate_post_barrier(masm, store_addr, new_val, tmp, done, true /* new_val_may_be_null */); - __ bind(done); + generate_post_barrier(masm, store_addr, new_val, tmp, true /* new_val_may_be_null */); } #if defined(COMPILER2) @@ -354,7 +353,6 @@ void G1BarrierSetAssembler::g1_write_barrier_pre_c2(MacroAssembler* masm, void G1BarrierSetAssembler::generate_c2_pre_barrier_stub(MacroAssembler* masm, G1PreBarrierStubC2* stub) const { Assembler::InlineSkippedInstructionsCounter skip_counter(masm); - Label runtime; Register obj = stub->obj(); Register pre_val = stub->pre_val(); Register thread = stub->thread(); @@ -362,9 +360,8 @@ void G1BarrierSetAssembler::generate_c2_pre_barrier_stub(MacroAssembler* masm, assert(stub->tmp2() == noreg, "not needed in this platform"); __ bind(*stub->entry()); - generate_pre_barrier_slow_path(masm, obj, pre_val, thread, tmp, *stub->continuation(), runtime); + generate_pre_barrier_slow_path(masm, obj, pre_val, thread, tmp, *stub->continuation()); - __ bind(runtime); generate_c2_barrier_runtime_call(masm, stub, pre_val, CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_pre_entry)); __ jmp(*stub->continuation()); } @@ -374,9 +371,7 @@ void G1BarrierSetAssembler::g1_write_barrier_post_c2(MacroAssembler* masm, Register new_val, Register tmp, bool new_val_may_be_null) { - Label done; - generate_post_barrier(masm, store_addr, new_val, tmp, done, new_val_may_be_null); - __ bind(done); + generate_post_barrier(masm, store_addr, new_val, tmp, new_val_may_be_null); } #endif // COMPILER2 @@ -449,7 +444,7 @@ void G1BarrierSetAssembler::gen_pre_barrier_stub(LIR_Assembler* ce, G1PreBarrier ce->mem2reg(stub->addr(), stub->pre_val(), T_OBJECT, stub->patch_code(), stub->info(), false /*wide*/); } - __ cmpptr(pre_val_reg, NULL_WORD); + __ testptr(pre_val_reg, pre_val_reg); __ jcc(Assembler::equal, *stub->continuation()); ce->store_parameter(stub->pre_val()->as_register(), 0); __ call(RuntimeAddress(bs->pre_barrier_c1_runtime_code_blob()->code_begin())); @@ -465,9 +460,7 @@ void G1BarrierSetAssembler::g1_write_barrier_post_c1(MacroAssembler* masm, Register thread, Register tmp1, Register tmp2 /* unused on x86 */) { - Label done; - generate_post_barrier(masm, store_addr, new_val, tmp1, done, true /* new_val_may_be_null */); - masm->bind(done); + generate_post_barrier(masm, store_addr, new_val, tmp1, true /* new_val_may_be_null */); } #define __ sasm-> @@ -490,8 +483,7 @@ void G1BarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAssembler* Address queue_index(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset())); Address buffer(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset())); - Label done; - Label runtime; + Label L_done, L_runtime; // Is marking still active? if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { @@ -500,13 +492,13 @@ void G1BarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAssembler* assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); __ cmpb(queue_active, 0); } - __ jcc(Assembler::equal, done); + __ jcc(Assembler::equal, L_done); // Can we store original value in the thread's buffer? __ movptr(tmp, queue_index); __ testptr(tmp, tmp); - __ jcc(Assembler::zero, runtime); + __ jccb(Assembler::zero, L_runtime); __ subptr(tmp, wordSize); __ movptr(queue_index, tmp); __ addptr(tmp, buffer); @@ -514,9 +506,9 @@ void G1BarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAssembler* // prev_val (rax) __ load_parameter(0, pre_val); __ movptr(Address(tmp, 0), pre_val); - __ jmp(done); + __ jmp(L_done); - __ bind(runtime); + __ bind(L_runtime); __ push_call_clobbered_registers(); @@ -526,7 +518,7 @@ void G1BarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAssembler* __ pop_call_clobbered_registers(); - __ bind(done); + __ bind(L_done); __ pop_ppx(rdx); __ pop_ppx(rax); From 7cd3d7f157708ebb6ce972b46a1a90379f63d08f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20=C3=96sterlund?= Date: Thu, 27 Nov 2025 07:15:30 +0000 Subject: [PATCH 032/706] 8372376: ZGC: Inaccurate verification of raw nulls in flip promoting pages Reviewed-by: stefank, sjohanss, aboldtch --- src/hotspot/share/gc/z/zVerify.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/gc/z/zVerify.cpp b/src/hotspot/share/gc/z/zVerify.cpp index 55f13be9b44..db3db14afa2 100644 --- a/src/hotspot/share/gc/z/zVerify.cpp +++ b/src/hotspot/share/gc/z/zVerify.cpp @@ -130,7 +130,10 @@ static void z_verify_root_oop_object(zaddress addr, void* p) { static void z_verify_old_oop(zpointer* p) { const zpointer o = *p; - assert(o != zpointer::null, "Old should not contain raw null"); + if (o == zpointer::null) { + guarantee(ZGeneration::young()->is_phase_mark_complete(), "Only possible when flip promoting"); + guarantee(ZHeap::heap()->page(p)->is_allocating(), "Raw nulls only possible in allocating pages"); + } if (!z_is_null_relaxed(o)) { if (ZPointer::is_mark_good(o)) { // Even though the pointer is mark good, we can't verify that it should From de546d0e03ff1823b73c32db1861b77efa9552d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20Sikstr=C3=B6m?= Date: Thu, 27 Nov 2025 09:02:18 +0000 Subject: [PATCH 033/706] 8371702: ZGC: NUMA-Affinity for Worker Threads in the Relocation Phase Co-authored-by: Axel Boldt-Christmas Reviewed-by: aboldtch, eosterlund --- src/hotspot/share/gc/z/zRelocate.cpp | 51 +++++++++++++++------------- 1 file changed, 27 insertions(+), 24 deletions(-) diff --git a/src/hotspot/share/gc/z/zRelocate.cpp b/src/hotspot/share/gc/z/zRelocate.cpp index 180ce22b041..24c4bdeac16 100644 --- a/src/hotspot/share/gc/z/zRelocate.cpp +++ b/src/hotspot/share/gc/z/zRelocate.cpp @@ -1087,7 +1087,6 @@ private: ZRelocateSmallAllocator _small_allocator; ZRelocateMediumAllocator _medium_allocator; const size_t _total_forwardings; - volatile size_t _numa_local_forwardings; public: ZRelocateTask(ZRelocationSet* relocation_set, @@ -1104,8 +1103,7 @@ public: _medium_targets(medium_targets), _small_allocator(_generation), _medium_allocator(_generation, shared_medium_targets), - _total_forwardings(relocation_set->nforwardings()), - _numa_local_forwardings(0) { + _total_forwardings(relocation_set->nforwardings()) { for (uint32_t i = 0; i < ZNUMA::count(); i++) { ZRelocationSetParallelIterator* const iter = _iters->addr(i); @@ -1124,18 +1122,17 @@ public: // Signal that we're not using the queue anymore. Used mostly for asserts. _queue->deactivate(); - - if (ZNUMA::is_enabled()) { - log_debug(gc, reloc, numa)("Forwardings relocated NUMA-locally: %zu / %zu (%.0f%%)", - _numa_local_forwardings, _total_forwardings, percent_of(_numa_local_forwardings, _total_forwardings)); - } } virtual void work() { ZRelocateWork small(&_small_allocator, _small_targets->addr(), _generation); ZRelocateWork medium(&_medium_allocator, _medium_targets->addr(), _generation); + const uint32_t num_nodes = ZNUMA::count(); - uint32_t numa_local_forwardings_worker = 0; + const uint32_t start_node = ZNUMA::id(); + uint32_t current_node = start_node; + bool has_affinity = false; + bool has_affinity_current_node = false; const auto do_forwarding = [&](ZForwarding* forwarding) { ZPage* const page = forwarding->page(); @@ -1167,26 +1164,30 @@ public: const auto do_forwarding_one_from_iter = [&]() { ZForwarding* forwarding; - const uint32_t start_node = ZNUMA::id(); - uint32_t current_node = start_node; - for (uint32_t i = 0; i < num_nodes; i++) { + for (;;) { if (_iters->get(current_node).next_if(&forwarding, check_numa_local, current_node)) { - claim_and_do_forwarding(forwarding); - - if (current_node == start_node) { - // Track if this forwarding was relocated on the local NUMA node - numa_local_forwardings_worker++; + // Set thread affinity for NUMA-local processing (if needed) + if (UseNUMA && !has_affinity_current_node) { + os::numa_set_thread_affinity(Thread::current(), ZNUMA::numa_id_to_node(current_node)); + has_affinity = true; + has_affinity_current_node = true; } + // Perform the forwarding task + claim_and_do_forwarding(forwarding); return true; } - // Check next node. + // No work found on the current node, move to the next node current_node = (current_node + 1) % num_nodes; - } + has_affinity_current_node = false; - return false; + // If we've looped back to the starting node there's no more work to do + if (current_node == start_node) { + return false; + } + } }; for (;;) { @@ -1209,11 +1210,13 @@ public: } } - if (ZNUMA::is_enabled()) { - AtomicAccess::add(&_numa_local_forwardings, numa_local_forwardings_worker, memory_order_relaxed); - } - _queue->leave(); + + if (UseNUMA && has_affinity) { + // Restore the affinity of the thread so that it isn't bound to a specific + // node any more + os::numa_set_thread_affinity(Thread::current(), -1); + } } virtual void resize_workers(uint nworkers) { From 141aebca38bc683cbff8a2dfe0cb98d3f0186a8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20Gr=C3=B6nlund?= Date: Thu, 27 Nov 2025 09:08:34 +0000 Subject: [PATCH 034/706] 8372586: Crashes on ppc64(le) after JDK-8371368 Reviewed-by: mbaesken --- src/hotspot/share/jfr/periodic/sampling/jfrThreadSampling.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampling.cpp b/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampling.cpp index b5720351bdf..534c9996cfe 100644 --- a/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampling.cpp +++ b/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampling.cpp @@ -217,7 +217,8 @@ static bool compute_top_frame(const JfrSampleRequest& request, frame& top_frame, const PcDesc* const pc_desc = get_pc_desc(sampled_nm, sampled_pc); if (is_valid(pc_desc)) { intptr_t* const synthetic_sp = sender_sp - sampled_nm->frame_size(); - top_frame = frame(synthetic_sp, synthetic_sp, sender_sp - 2, pc_desc->real_pc(sampled_nm), sampled_nm); + intptr_t* const synthetic_fp = sender_sp AARCH64_ONLY( - frame::sender_sp_offset); + top_frame = frame(synthetic_sp, synthetic_sp, synthetic_fp, pc_desc->real_pc(sampled_nm), sampled_nm); in_continuation = is_in_continuation(top_frame, jt); return true; } From 86aae125f1a4e16dfe2dd0faf63f96ae1ca7bcd0 Mon Sep 17 00:00:00 2001 From: David Briemann Date: Thu, 27 Nov 2025 09:08:50 +0000 Subject: [PATCH 035/706] 8367487: Test compiler/loopopts/superword/TestReinterpretAndCast.java fails on Linux aarch64 with Cavium CPU Reviewed-by: epeter, mdoerr --- .../superword/TestReinterpretAndCast.java | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestReinterpretAndCast.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestReinterpretAndCast.java index a72126ebad5..ab2801179f2 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/TestReinterpretAndCast.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestReinterpretAndCast.java @@ -162,7 +162,13 @@ public class TestReinterpretAndCast { IRNode.STORE_VECTOR, "> 0", IRNode.VECTOR_REINTERPRET, "> 0"}, // We have at least I2F applyIfPlatform = {"64-bit", "true"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeature = {"avx", "true"}) + @IR(counts = {IRNode.LOAD_VECTOR_I, IRNode.VECTOR_SIZE + "min(max_int, max_float, max_short)", "> 0", + IRNode.VECTOR_CAST_F2HF, IRNode.VECTOR_SIZE + "min(max_int, max_float, max_short)", "> 0", + IRNode.STORE_VECTOR, "> 0", + IRNode.VECTOR_REINTERPRET, "> 0"}, // We have at least I2F + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureAnd = {"asimd", "true", "fphp", "true", "asimdhp", "true"}) public static void test2(int[] a, short[] b) { for (int i = 0; i < SIZE; i++) { int v0 = a[i]; @@ -202,7 +208,14 @@ public class TestReinterpretAndCast { IRNode.STORE_VECTOR, "> 0", IRNode.VECTOR_REINTERPRET, "> 0"}, // We have at least F2I applyIfPlatform = {"64-bit", "true"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeature = {"avx", "true"}) + @IR(counts = {IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE + "min(max_float, max_short, max_long)", "> 0", + IRNode.VECTOR_CAST_HF2F, IRNode.VECTOR_SIZE + "min(max_float, max_short, max_long)", "> 0", + IRNode.VECTOR_CAST_I2L, IRNode.VECTOR_SIZE + "min(max_float, max_short, max_long)", "> 0", + IRNode.STORE_VECTOR, "> 0", + IRNode.VECTOR_REINTERPRET, "> 0"}, // We have at least F2I + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureAnd = {"asimd", "true", "fphp", "true", "asimdhp", "true"}) public static void test3(short[] a, long[] b) { for (int i = 0; i < SIZE; i++) { short v0 = a[i]; From 1f417e77615c570ca3002b13a1398b647133ad67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Jeli=C5=84ski?= Date: Thu, 27 Nov 2025 09:27:02 +0000 Subject: [PATCH 036/706] 8371887: HttpClient: SSLParameters with no protocols configured disable HTTP2+ support Reviewed-by: jpai, dfuchs --- .../jdk/internal/net/quic/QuicTLSContext.java | 2 +- .../jdk/internal/net/http/HttpClientImpl.java | 36 ++++++++++++++++--- .../jdk/internal/net/http/HttpConnection.java | 22 +----------- .../internal/net/http/HttpQuicConnection.java | 21 +---------- .../java/net/httpclient/TlsContextTest.java | 27 ++++++++++++-- .../net/httpclient/http2/TLSConnection.java | 10 ++++-- .../http3/H3UnsupportedSSLParametersTest.java | 15 ++++++++ 7 files changed, 81 insertions(+), 52 deletions(-) diff --git a/src/java.base/share/classes/jdk/internal/net/quic/QuicTLSContext.java b/src/java.base/share/classes/jdk/internal/net/quic/QuicTLSContext.java index 5cf0c999fb9..15b3c450d03 100644 --- a/src/java.base/share/classes/jdk/internal/net/quic/QuicTLSContext.java +++ b/src/java.base/share/classes/jdk/internal/net/quic/QuicTLSContext.java @@ -74,7 +74,7 @@ public final class QuicTLSContext { /** * {@return {@code true} if protocols of the given {@code parameters} support QUIC TLS, {@code false} otherwise} */ - public static boolean isQuicCompatible(SSLParameters parameters) { + private static boolean isQuicCompatible(SSLParameters parameters) { String[] protocols = parameters.getProtocols(); return protocols != null && Arrays.asList(protocols).contains("TLSv1.3"); } diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/HttpClientImpl.java b/src/java.net.http/share/classes/jdk/internal/net/http/HttpClientImpl.java index af9fd3b96ba..54bad66d4fa 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/HttpClientImpl.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/HttpClientImpl.java @@ -53,6 +53,7 @@ import java.security.NoSuchAlgorithmException; import java.time.Duration; import java.time.temporal.ChronoUnit; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashSet; import java.util.Iterator; import java.util.List; @@ -126,6 +127,8 @@ final class HttpClientImpl extends HttpClient implements Trackable { // Defaults to value used for HTTP/1 Keep-Alive Timeout. Can be overridden by jdk.httpclient.keepalive.timeout.h2 property. static final long IDLE_CONNECTION_TIMEOUT_H2 = getTimeoutProp("jdk.httpclient.keepalive.timeout.h2", KEEP_ALIVE_TIMEOUT); static final long IDLE_CONNECTION_TIMEOUT_H3 = getTimeoutProp("jdk.httpclient.keepalive.timeout.h3", IDLE_CONNECTION_TIMEOUT_H2); + private final boolean hasRequiredH3TLS; + private final boolean hasRequiredH2TLS; static final UseVTForSelector USE_VT_FOR_SELECTOR = Utils.useVTForSelector("jdk.internal.httpclient.tcp.selector.useVirtualThreads", "default"); @@ -477,10 +480,17 @@ final class HttpClientImpl extends HttpClient implements Trackable { "HTTP3 is not supported")); } sslParams = requireNonNullElseGet(builder.sslParams, sslContext::getDefaultSSLParameters); - boolean sslParamsSupportedForH3 = sslParams.getProtocols() == null - || sslParams.getProtocols().length == 0 - || isQuicCompatible(sslParams); - if (version == Version.HTTP_3 && !sslParamsSupportedForH3) { + String[] sslProtocols = sslParams.getProtocols(); + if (sslProtocols == null) { + sslProtocols = requireNonNullElseGet(sslContext.getDefaultSSLParameters().getProtocols(), + () -> new String[0]); + } + // HTTP/3 MUST use TLS version 1.3 or higher + hasRequiredH3TLS = Arrays.asList(sslProtocols).contains("TLSv1.3"); + // HTTP/2 MUST use TLS version 1.2 or higher for HTTP/2 over TLS + hasRequiredH2TLS = hasRequiredH3TLS || Arrays.asList(sslProtocols).contains("TLSv1.2"); + + if (version == Version.HTTP_3 && !hasRequiredH3TLS) { throw new UncheckedIOException(new UnsupportedProtocolVersionException( "HTTP3 is not supported - TLSv1.3 isn't configured on SSLParameters")); } @@ -507,7 +517,7 @@ final class HttpClientImpl extends HttpClient implements Trackable { debug.log("proxySelector is %s (user-supplied=%s)", this.proxySelector, userProxySelector != null); authenticator = builder.authenticator; - boolean h3Supported = sslCtxSupportedForH3 && sslParamsSupportedForH3; + boolean h3Supported = sslCtxSupportedForH3 && hasRequiredH3TLS; registry = new AltServicesRegistry(id); connections = new ConnectionPool(id); client2 = new Http2ClientImpl(this); @@ -530,6 +540,22 @@ final class HttpClientImpl extends HttpClient implements Trackable { assert facadeRef.get() != null; } + /** + * Returns true if the SSL parameter protocols contains at + * least one TLS version that HTTP/3 requires. + */ + boolean hasRequiredHTTP3TLSVersion() { + return hasRequiredH3TLS; + } + + /** + * Returns true if the SSL parameter protocols contains at + * least one TLS version that HTTP/2 requires. + */ + boolean hasRequiredHTTP2TLSVersion() { + return hasRequiredH2TLS; + } + // called when the facade is GC'ed. // Just wakes up the selector to cleanup... void facadeCleanup() { diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/HttpConnection.java b/src/java.net.http/share/classes/jdk/internal/net/http/HttpConnection.java index 115bc56f804..0c1388cec8a 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/HttpConnection.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/HttpConnection.java @@ -32,7 +32,6 @@ import java.net.http.HttpResponse; import java.nio.ByteBuffer; import java.nio.channels.NetworkChannel; import java.nio.channels.SocketChannel; -import java.util.Arrays; import java.util.Comparator; import java.util.IdentityHashMap; import java.util.List; @@ -43,8 +42,6 @@ import java.util.concurrent.ConcurrentLinkedDeque; import java.util.concurrent.Flow; import java.util.concurrent.atomic.AtomicLong; import java.util.function.BiPredicate; -import java.util.function.Predicate; -import java.net.http.HttpClient; import java.net.http.HttpClient.Version; import java.net.http.HttpHeaders; @@ -285,23 +282,6 @@ abstract class HttpConnection implements Closeable { */ abstract HttpPublisher publisher(); - // HTTP/2 MUST use TLS version 1.2 or higher for HTTP/2 over TLS - private static final Predicate testRequiredHTTP2TLSVersion = proto -> - proto.equals("TLSv1.2") || proto.equals("TLSv1.3"); - - /** - * Returns true if the given client's SSL parameter protocols contains at - * least one TLS version that HTTP/2 requires. - */ - private static final boolean hasRequiredHTTP2TLSVersion(HttpClient client) { - String[] protos = client.sslParameters().getProtocols(); - if (protos != null) { - return Arrays.stream(protos).filter(testRequiredHTTP2TLSVersion).findAny().isPresent(); - } else { - return false; - } - } - /** * Factory for retrieving HttpConnections. A connection can be retrieved * from the connection pool, or a new one created if none available. @@ -359,7 +339,7 @@ abstract class HttpConnection implements Closeable { } else { assert !request.isHttp3Only(version); // should have failed before String[] alpn = null; - if (version == HTTP_2 && hasRequiredHTTP2TLSVersion(client)) { + if (version == HTTP_2 && client.hasRequiredHTTP2TLSVersion()) { // We only come here after we have checked the HTTP/2 connection pool. // We will not negotiate HTTP/2 if we don't have the appropriate TLS version alpn = new String[] { Alpns.H2, Alpns.HTTP_1_1 }; diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/HttpQuicConnection.java b/src/java.net.http/share/classes/jdk/internal/net/http/HttpQuicConnection.java index 0a22256f6c6..36f191fbd67 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/HttpQuicConnection.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/HttpQuicConnection.java @@ -31,11 +31,9 @@ import java.net.InetSocketAddress; import java.net.SocketAddress; import java.net.SocketOption; import java.net.URI; -import java.net.http.HttpClient; import java.net.http.HttpConnectTimeoutException; import java.nio.channels.NetworkChannel; import java.time.Duration; -import java.util.Arrays; import java.util.List; import java.util.Objects; import java.util.Optional; @@ -43,7 +41,6 @@ import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; import java.util.function.Function; -import java.util.function.Predicate; import javax.net.ssl.SNIServerName; import javax.net.ssl.SSLParameters; @@ -81,9 +78,6 @@ abstract class HttpQuicConnection extends HttpConnection { // the alt-service which was advertised, from some origin, for this connection co-ordinates. // can be null, which indicates this wasn't created because of an alt-service private final AltService sourceAltService; - // HTTP/2 MUST use TLS version 1.3 or higher for HTTP/3 over TLS - private static final Predicate testRequiredHTTP3TLSVersion = proto -> - proto.equals("TLSv1.3"); HttpQuicConnection(Origin originServer, InetSocketAddress address, HttpClientImpl client, @@ -178,19 +172,6 @@ abstract class HttpQuicConnection extends HttpConnection { return quicConnection; } - /** - * Returns true if the given client's SSL parameter protocols contains at - * least one TLS version that HTTP/3 requires. - */ - private static boolean hasRequiredHTTP3TLSVersion(HttpClient client) { - String[] protos = client.sslParameters().getProtocols(); - if (protos != null) { - return Arrays.stream(protos).anyMatch(testRequiredHTTP3TLSVersion); - } else { - return false; - } - } - /** * Called when the HTTP/3 connection is established, either successfully or * unsuccessfully @@ -260,7 +241,7 @@ abstract class HttpQuicConnection extends HttpConnection { // to using HTTP/2 var debug = h3client.debug(); var where = "HttpQuicConnection.getHttpQuicConnection"; - if (proxy != null || !hasRequiredHTTP3TLSVersion(client)) { + if (proxy != null || !client.hasRequiredHTTP3TLSVersion()) { if (debug.on()) debug.log("%s: proxy required or SSL version mismatch", where); return null; diff --git a/test/jdk/java/net/httpclient/TlsContextTest.java b/test/jdk/java/net/httpclient/TlsContextTest.java index f24007f6d90..86b067f66f8 100644 --- a/test/jdk/java/net/httpclient/TlsContextTest.java +++ b/test/jdk/java/net/httpclient/TlsContextTest.java @@ -31,6 +31,8 @@ import java.net.http.HttpResponse; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLParameters; + import jdk.httpclient.test.lib.common.HttpServerAdapters; import jdk.httpclient.test.lib.http2.Http2TestServer; import jdk.test.lib.net.SimpleSSLContext; @@ -49,7 +51,7 @@ import jdk.test.lib.security.SecurityUtils; /* * @test - * @bug 8239594 + * @bug 8239594 8371887 * @summary This test verifies that the TLS version handshake respects ssl context * @library /test/lib /test/jdk/java/net/httpclient/lib * @build jdk.test.lib.net.SimpleSSLContext TlsContextTest @@ -101,9 +103,25 @@ public class TlsContextTest implements HttpServerAdapters { * Tests various scenarios between client and server tls handshake with valid http */ @Test(dataProvider = "scenarios") - public void testVersionProtocols(SSLContext context, + public void testVersionProtocolsNoParams(SSLContext context, Version version, String expectedProtocol) throws Exception { + runTest(context, version, expectedProtocol, false); + } + + /** + * Tests various scenarios between client and server tls handshake with valid http, + * but with empty SSLParameters + */ + @Test(dataProvider = "scenarios") + public void testVersionProtocolsEmptyParams(SSLContext context, + Version version, + String expectedProtocol) throws Exception { + runTest(context, version, expectedProtocol, true); + } + + private void runTest(SSLContext context, Version version, String expectedProtocol, + boolean setEmptyParams) throws Exception { // for HTTP/3 we won't accept to set the version to HTTP/3 on the // client if we don't have TLSv1.3; We will set the version // on the request instead in that case. @@ -111,8 +129,11 @@ public class TlsContextTest implements HttpServerAdapters { : HttpClient.newBuilder().version(version); var reqBuilder = HttpRequest.newBuilder(new URI(https2URI)); + if (setEmptyParams) { + builder.sslParameters(new SSLParameters()); + } HttpClient client = builder.sslContext(context) - .build(); + .build(); if (version == HTTP_3) { // warmup to obtain AltService client.send(reqBuilder.version(HTTP_2).GET().build(), ofString()); diff --git a/test/jdk/java/net/httpclient/http2/TLSConnection.java b/test/jdk/java/net/httpclient/http2/TLSConnection.java index fd9cff38371..e4009219bca 100644 --- a/test/jdk/java/net/httpclient/http2/TLSConnection.java +++ b/test/jdk/java/net/httpclient/http2/TLSConnection.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, 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,7 +41,7 @@ import jdk.httpclient.test.lib.http2.Http2Handler; /* * @test - * @bug 8150769 8157107 + * @bug 8150769 8157107 8371887 * @library /test/jdk/java/net/httpclient/lib * @build jdk.httpclient.test.lib.http2.Http2TestServer * @summary Checks that SSL parameters can be set for HTTP/2 connection @@ -135,6 +135,12 @@ public class TLSConnection { success &= checkCipherSuite(handler.getSSLSession(), "TLS_RSA_WITH_AES_128_CBC_SHA"); + success &= expectSuccess( + "---\nTest #5: empty SSL parameters, " + + "expect successful connection", + () -> connect(uriString, new SSLParameters())); + success &= checkProtocol(handler.getSSLSession(), expectedTLSVersion(null)); + if (success) { System.out.println("Test passed"); } else { diff --git a/test/jdk/java/net/httpclient/http3/H3UnsupportedSSLParametersTest.java b/test/jdk/java/net/httpclient/http3/H3UnsupportedSSLParametersTest.java index 090dec2c189..790af245db8 100644 --- a/test/jdk/java/net/httpclient/http3/H3UnsupportedSSLParametersTest.java +++ b/test/jdk/java/net/httpclient/http3/H3UnsupportedSSLParametersTest.java @@ -34,6 +34,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue; /* * @test + * @bug 8371887 * @summary Tests that a HttpClient configured with SSLParameters that doesn't include TLSv1.3 * cannot be used for HTTP3 * @library /test/lib /test/jdk/java/net/httpclient/lib @@ -75,4 +76,18 @@ public class H3UnsupportedSSLParametersTest { .version(HttpClient.Version.HTTP_3).build(); assertNotNull(client, "HttpClient is null"); } + + /** + * Builds a HttpClient with SSLParameters without protocol versions + * and expects the build() to succeed and return a HttpClient instance + */ + @Test + public void testDefault() throws Exception { + final SSLParameters params = new SSLParameters(); + final HttpClient client = HttpServerAdapters.createClientBuilderForH3() + .proxy(HttpClient.Builder.NO_PROXY) + .sslParameters(params) + .version(HttpClient.Version.HTTP_3).build(); + assertNotNull(client, "HttpClient is null"); + } } From 4ac33956343bbfa3619ccb029ceed6c5a402f775 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20Sikstr=C3=B6m?= Date: Thu, 27 Nov 2025 09:38:59 +0000 Subject: [PATCH 037/706] 8372150: Parallel: Tighten requirements around heap sizes with NUMA and Large Pages Reviewed-by: ayang, stefank, aboldtch, stuefe --- .../share/gc/parallel/parallelArguments.cpp | 102 +++++++++++------- .../share/gc/parallel/parallelArguments.hpp | 10 +- .../share/gc/serial/serialArguments.cpp | 39 +++++++ .../share/gc/serial/serialArguments.hpp | 7 +- src/hotspot/share/gc/shared/gcArguments.cpp | 18 ---- src/hotspot/share/gc/shared/gcArguments.hpp | 4 +- src/hotspot/share/gc/shared/genArguments.cpp | 18 ---- src/hotspot/share/gc/shared/genArguments.hpp | 7 +- .../share/gc/shared/jvmFlagConstraintsGC.cpp | 2 +- src/hotspot/share/runtime/arguments.cpp | 5 +- .../gtest/gc/shared/test_collectorPolicy.cpp | 11 -- 11 files changed, 118 insertions(+), 105 deletions(-) diff --git a/src/hotspot/share/gc/parallel/parallelArguments.cpp b/src/hotspot/share/gc/parallel/parallelArguments.cpp index 629690a6258..be9673224f5 100644 --- a/src/hotspot/share/gc/parallel/parallelArguments.cpp +++ b/src/hotspot/share/gc/parallel/parallelArguments.cpp @@ -37,8 +37,45 @@ #include "utilities/defaultStream.hpp" #include "utilities/powerOfTwo.hpp" -size_t ParallelArguments::conservative_max_heap_alignment() { - return compute_heap_alignment(); +static size_t num_young_spaces() { + // When using NUMA, we create one MutableNUMASpace for each NUMA node + const size_t num_eden_spaces = UseNUMA ? os::numa_get_groups_num() : 1; + + // The young generation must have room for eden + two survivors + return num_eden_spaces + 2; +} + +static size_t num_old_spaces() { + return 1; +} + +void ParallelArguments::initialize_alignments() { + // Initialize card size before initializing alignments + CardTable::initialize_card_size(); + const size_t card_table_alignment = CardTable::ct_max_alignment_constraint(); + SpaceAlignment = ParallelScavengeHeap::default_space_alignment(); + + if (UseLargePages) { + const size_t total_spaces = num_young_spaces() + num_old_spaces(); + const size_t page_size = os::page_size_for_region_unaligned(MaxHeapSize, total_spaces); + ParallelScavengeHeap::set_desired_page_size(page_size); + + if (page_size == os::vm_page_size()) { + log_warning(gc, heap)("MaxHeapSize (%zu) must be large enough for %zu * page-size; Disabling UseLargePages for heap", + MaxHeapSize, total_spaces); + } + + if (page_size > SpaceAlignment) { + SpaceAlignment = page_size; + } + + HeapAlignment = lcm(page_size, card_table_alignment); + + } else { + assert(is_aligned(SpaceAlignment, os::vm_page_size()), ""); + ParallelScavengeHeap::set_desired_page_size(os::vm_page_size()); + HeapAlignment = card_table_alignment; + } } void ParallelArguments::initialize() { @@ -98,49 +135,36 @@ void ParallelArguments::initialize() { FullGCForwarding::initialize_flags(heap_reserved_size_bytes()); } -void ParallelArguments::initialize_alignments() { - // Initialize card size before initializing alignments - CardTable::initialize_card_size(); - SpaceAlignment = ParallelScavengeHeap::default_space_alignment(); - HeapAlignment = compute_heap_alignment(); -} +size_t ParallelArguments::conservative_max_heap_alignment() { + // The card marking array and the offset arrays for old generations are + // committed in os pages as well. Make sure they are entirely full (to + // avoid partial page problems), e.g. if 512 bytes heap corresponds to 1 + // byte entry and the os page size is 4096, the maximum heap size should + // be 512*4096 = 2MB aligned. -void ParallelArguments::initialize_heap_flags_and_sizes_one_pass() { - // Do basic sizing work - GenArguments::initialize_heap_flags_and_sizes(); -} + size_t alignment = CardTable::ct_max_alignment_constraint(); -void ParallelArguments::initialize_heap_flags_and_sizes() { - initialize_heap_flags_and_sizes_one_pass(); - - if (!UseLargePages) { - ParallelScavengeHeap::set_desired_page_size(os::vm_page_size()); - return; + if (UseLargePages) { + // In presence of large pages we have to make sure that our + // alignment is large page aware. + alignment = lcm(os::large_page_size(), alignment); } - // If using large-page, need to update SpaceAlignment so that spaces are page-size aligned. - const size_t min_pages = 4; // 1 for eden + 1 for each survivor + 1 for old - const size_t page_sz = os::page_size_for_region_aligned(MinHeapSize, min_pages); - ParallelScavengeHeap::set_desired_page_size(page_sz); - - if (page_sz == os::vm_page_size()) { - log_warning(gc, heap)("MinHeapSize (%zu) must be large enough for 4 * page-size; Disabling UseLargePages for heap", MinHeapSize); - return; - } - - // Space is largepage-aligned. - size_t new_alignment = page_sz; - if (new_alignment != SpaceAlignment) { - SpaceAlignment = new_alignment; - // Redo everything from the start - initialize_heap_flags_and_sizes_one_pass(); - } -} - -size_t ParallelArguments::heap_reserved_size_bytes() { - return MaxHeapSize; + return alignment; } CollectedHeap* ParallelArguments::create_heap() { return new ParallelScavengeHeap(); } + +size_t ParallelArguments::young_gen_size_lower_bound() { + return num_young_spaces() * SpaceAlignment; +} + +size_t ParallelArguments::old_gen_size_lower_bound() { + return num_old_spaces() * SpaceAlignment; +} + +size_t ParallelArguments::heap_reserved_size_bytes() { + return MaxHeapSize; +} diff --git a/src/hotspot/share/gc/parallel/parallelArguments.hpp b/src/hotspot/share/gc/parallel/parallelArguments.hpp index 159441be792..729fe43b879 100644 --- a/src/hotspot/share/gc/parallel/parallelArguments.hpp +++ b/src/hotspot/share/gc/parallel/parallelArguments.hpp @@ -1,5 +1,6 @@ /* * Copyright (c) 2017, Red Hat, Inc. and/or its affiliates. + * Copyright (c) 2025, 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,21 +26,16 @@ #ifndef SHARE_GC_PARALLEL_PARALLELARGUMENTS_HPP #define SHARE_GC_PARALLEL_PARALLELARGUMENTS_HPP -#include "gc/shared/gcArguments.hpp" #include "gc/shared/genArguments.hpp" -class CollectedHeap; - class ParallelArguments : public GenArguments { private: virtual void initialize_alignments(); - virtual void initialize_heap_flags_and_sizes(); - - void initialize_heap_flags_and_sizes_one_pass(); - virtual void initialize(); virtual size_t conservative_max_heap_alignment(); virtual CollectedHeap* create_heap(); + virtual size_t young_gen_size_lower_bound(); + virtual size_t old_gen_size_lower_bound(); public: static size_t heap_reserved_size_bytes(); diff --git a/src/hotspot/share/gc/serial/serialArguments.cpp b/src/hotspot/share/gc/serial/serialArguments.cpp index aed1c2353b4..efebec4fa38 100644 --- a/src/hotspot/share/gc/serial/serialArguments.cpp +++ b/src/hotspot/share/gc/serial/serialArguments.cpp @@ -1,5 +1,6 @@ /* * Copyright (c) 2017, Red Hat, Inc. and/or its affiliates. + * Copyright (c) 2025, 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,11 +28,49 @@ #include "gc/shared/fullGCForwarding.hpp" #include "gc/shared/gcArguments.hpp" +static size_t compute_heap_alignment() { + // The card marking array and the offset arrays for old generations are + // committed in os pages as well. Make sure they are entirely full (to + // avoid partial page problems), e.g. if 512 bytes heap corresponds to 1 + // byte entry and the os page size is 4096, the maximum heap size should + // be 512*4096 = 2MB aligned. + + size_t alignment = CardTable::ct_max_alignment_constraint(); + + if (UseLargePages) { + // In presence of large pages we have to make sure that our + // alignment is large page aware. + alignment = lcm(os::large_page_size(), alignment); + } + + return alignment; +} + +void SerialArguments::initialize_alignments() { + // Initialize card size before initializing alignments + CardTable::initialize_card_size(); + SpaceAlignment = (size_t)Generation::GenGrain; + HeapAlignment = compute_heap_alignment(); +} + void SerialArguments::initialize() { GCArguments::initialize(); FullGCForwarding::initialize_flags(MaxHeapSize); } +size_t SerialArguments::conservative_max_heap_alignment() { + return MAX2((size_t)Generation::GenGrain, compute_heap_alignment()); +} + CollectedHeap* SerialArguments::create_heap() { return new SerialHeap(); } + +size_t SerialArguments::young_gen_size_lower_bound() { + // The young generation must be aligned and have room for eden + two survivors + return 3 * SpaceAlignment; +} + +size_t SerialArguments::old_gen_size_lower_bound() { + return SpaceAlignment; +} diff --git a/src/hotspot/share/gc/serial/serialArguments.hpp b/src/hotspot/share/gc/serial/serialArguments.hpp index 90c3225ff8d..774168eb626 100644 --- a/src/hotspot/share/gc/serial/serialArguments.hpp +++ b/src/hotspot/share/gc/serial/serialArguments.hpp @@ -1,5 +1,6 @@ /* * Copyright (c) 2017, Red Hat, Inc. and/or its affiliates. + * Copyright (c) 2025, 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,12 +28,14 @@ #include "gc/shared/genArguments.hpp" -class CollectedHeap; - class SerialArguments : public GenArguments { private: + virtual void initialize_alignments(); virtual void initialize(); + virtual size_t conservative_max_heap_alignment(); virtual CollectedHeap* create_heap(); + virtual size_t young_gen_size_lower_bound(); + virtual size_t old_gen_size_lower_bound(); }; #endif // SHARE_GC_SERIAL_SERIALARGUMENTS_HPP diff --git a/src/hotspot/share/gc/shared/gcArguments.cpp b/src/hotspot/share/gc/shared/gcArguments.cpp index d45e6a9c7dd..424427c12b6 100644 --- a/src/hotspot/share/gc/shared/gcArguments.cpp +++ b/src/hotspot/share/gc/shared/gcArguments.cpp @@ -62,24 +62,6 @@ void GCArguments::initialize_heap_sizes() { initialize_size_info(); } -size_t GCArguments::compute_heap_alignment() { - // The card marking array and the offset arrays for old generations are - // committed in os pages as well. Make sure they are entirely full (to - // avoid partial page problems), e.g. if 512 bytes heap corresponds to 1 - // byte entry and the os page size is 4096, the maximum heap size should - // be 512*4096 = 2MB aligned. - - size_t alignment = CardTable::ct_max_alignment_constraint(); - - if (UseLargePages) { - // In presence of large pages we have to make sure that our - // alignment is large page aware. - alignment = lcm(os::large_page_size(), alignment); - } - - return alignment; -} - #ifdef ASSERT void GCArguments::assert_flags() { assert(InitialHeapSize <= MaxHeapSize, "Ergonomics decided on incompatible initial and maximum heap sizes"); diff --git a/src/hotspot/share/gc/shared/gcArguments.hpp b/src/hotspot/share/gc/shared/gcArguments.hpp index fff41e85d8c..d8a4901f887 100644 --- a/src/hotspot/share/gc/shared/gcArguments.hpp +++ b/src/hotspot/share/gc/shared/gcArguments.hpp @@ -45,6 +45,8 @@ protected: public: virtual void initialize(); + + // Return the (conservative) maximum heap alignment virtual size_t conservative_max_heap_alignment() = 0; // Used by heap size heuristics to determine max @@ -59,8 +61,6 @@ public: } void initialize_heap_sizes(); - - static size_t compute_heap_alignment(); }; #endif // SHARE_GC_SHARED_GCARGUMENTS_HPP diff --git a/src/hotspot/share/gc/shared/genArguments.cpp b/src/hotspot/share/gc/shared/genArguments.cpp index 9618c515b7d..5d5003f8d9f 100644 --- a/src/hotspot/share/gc/shared/genArguments.cpp +++ b/src/hotspot/share/gc/shared/genArguments.cpp @@ -42,17 +42,6 @@ size_t MaxOldSize = 0; // See more in JDK-8346005 size_t OldSize = ScaleForWordSize(4*M); -size_t GenArguments::conservative_max_heap_alignment() { return (size_t)Generation::GenGrain; } - -static size_t young_gen_size_lower_bound() { - // The young generation must be aligned and have room for eden + two survivors - return 3 * SpaceAlignment; -} - -static size_t old_gen_size_lower_bound() { - return SpaceAlignment; -} - size_t GenArguments::scale_by_NewRatio_aligned(size_t base_size, size_t alignment) { return align_down_bounded(base_size / (NewRatio + 1), alignment); } @@ -64,13 +53,6 @@ static size_t bound_minus_alignment(size_t desired_size, return MIN2(desired_size, max_minus); } -void GenArguments::initialize_alignments() { - // Initialize card size before initializing alignments - CardTable::initialize_card_size(); - SpaceAlignment = (size_t)Generation::GenGrain; - HeapAlignment = compute_heap_alignment(); -} - void GenArguments::initialize_heap_flags_and_sizes() { GCArguments::initialize_heap_flags_and_sizes(); diff --git a/src/hotspot/share/gc/shared/genArguments.hpp b/src/hotspot/share/gc/shared/genArguments.hpp index 80133bd1ec1..0ff9568575d 100644 --- a/src/hotspot/share/gc/shared/genArguments.hpp +++ b/src/hotspot/share/gc/shared/genArguments.hpp @@ -38,17 +38,16 @@ extern size_t OldSize; class GenArguments : public GCArguments { friend class TestGenCollectorPolicy; // Testing private: - virtual void initialize_alignments(); virtual void initialize_size_info(); - // Return the (conservative) maximum heap alignment - virtual size_t conservative_max_heap_alignment(); - DEBUG_ONLY(void assert_flags();) DEBUG_ONLY(void assert_size_info();) static size_t scale_by_NewRatio_aligned(size_t base_size, size_t alignment); + virtual size_t young_gen_size_lower_bound() = 0; + virtual size_t old_gen_size_lower_bound() = 0; + protected: virtual void initialize_heap_flags_and_sizes(); }; diff --git a/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.cpp b/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.cpp index 1ed3701fdab..cc446adba66 100644 --- a/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.cpp +++ b/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.cpp @@ -250,7 +250,7 @@ static JVMFlag::Error MaxSizeForHeapAlignment(const char* name, size_t value, bo } else #endif { - heap_alignment = GCArguments::compute_heap_alignment(); + heap_alignment = Arguments::conservative_max_heap_alignment(); } return MaxSizeForAlignment(name, value, heap_alignment, verbose); diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index ff1de899bdd..01fee949e33 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -1478,10 +1478,9 @@ void Arguments::set_conservative_max_heap_alignment() { // the alignments imposed by several sources: any requirements from the heap // itself and the maximum page size we may run the VM with. size_t heap_alignment = GCConfig::arguments()->conservative_max_heap_alignment(); - _conservative_max_heap_alignment = MAX4(heap_alignment, + _conservative_max_heap_alignment = MAX3(heap_alignment, os::vm_allocation_granularity(), - os::max_page_size(), - GCArguments::compute_heap_alignment()); + os::max_page_size()); assert(is_power_of_2(_conservative_max_heap_alignment), "Expected to be a power-of-2"); } diff --git a/test/hotspot/gtest/gc/shared/test_collectorPolicy.cpp b/test/hotspot/gtest/gc/shared/test_collectorPolicy.cpp index b5e9c6de6a0..55c03f188cc 100644 --- a/test/hotspot/gtest/gc/shared/test_collectorPolicy.cpp +++ b/test/hotspot/gtest/gc/shared/test_collectorPolicy.cpp @@ -140,17 +140,6 @@ class TestGenCollectorPolicy { ASSERT_EQ(param, NewSize); } }; - - class SetMaxNewSizeCmd : public BinaryExecutor { - public: - SetMaxNewSizeCmd(size_t param1, size_t param2) : BinaryExecutor(param1, param2) { } - void execute() { - size_t heap_alignment = GCArguments::compute_heap_alignment(); - size_t new_size_value = align_up(MaxHeapSize, heap_alignment) - - param1 + param2; - FLAG_SET_CMDLINE(MaxNewSize, new_size_value); - } - }; }; From d350158e060c01acf49759dcbdd1f4d72530111b Mon Sep 17 00:00:00 2001 From: Viktor Klang Date: Thu, 27 Nov 2025 09:42:46 +0000 Subject: [PATCH 038/706] 8371740: LinkedTransferQueue.poll() returns null even though queue is not empty Co-authored-by: Doug Lea Co-authored-by: Dr Heinz M. Kabutz Reviewed-by: alanb --- .../util/concurrent/LinkedTransferQueue.java | 16 ++-- .../concurrent/BlockingQueue/MissedPoll.java | 78 +++++++++++++++++++ 2 files changed, 87 insertions(+), 7 deletions(-) create mode 100644 test/jdk/java/util/concurrent/BlockingQueue/MissedPoll.java diff --git a/src/java.base/share/classes/java/util/concurrent/LinkedTransferQueue.java b/src/java.base/share/classes/java/util/concurrent/LinkedTransferQueue.java index 118d648c7a2..787d8d5fecd 100644 --- a/src/java.base/share/classes/java/util/concurrent/LinkedTransferQueue.java +++ b/src/java.base/share/classes/java/util/concurrent/LinkedTransferQueue.java @@ -588,13 +588,15 @@ public class LinkedTransferQueue extends AbstractQueue do { m = p.item; q = p.next; - if (p.isData != haveData && haveData != (m != null) && - p.cmpExItem(m, e) == m) { - Thread w = p.waiter; // matched complementary node - if (p != h && h == cmpExHead(h, (q == null) ? p : q)) - h.next = h; // advance head; self-link old - LockSupport.unpark(w); - return m; + if (p.isData != haveData && haveData != (m != null)) { + if (p.cmpExItem(m, e) == m) { + Thread w = p.waiter; // matched complementary node + if (p != h && h == cmpExHead(h, (q == null) ? p : q)) + h.next = h; // advance head; self-link old + LockSupport.unpark(w); + return m; + } + continue restart; } else if (q == null) { if (ns == 0L) // try to append unless immediate break restart; diff --git a/test/jdk/java/util/concurrent/BlockingQueue/MissedPoll.java b/test/jdk/java/util/concurrent/BlockingQueue/MissedPoll.java new file mode 100644 index 00000000000..9eb39634ce6 --- /dev/null +++ b/test/jdk/java/util/concurrent/BlockingQueue/MissedPoll.java @@ -0,0 +1,78 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8371740 + * @summary Checks for poll() (or peek) returning null when an element must exist. + */ +import java.util.*; +import java.util.concurrent.*; + +public class MissedPoll { + public static void main(String... args) throws Throwable { + test(new LinkedTransferQueue<>()); + test(new LinkedBlockingQueue<>()); + test(new LinkedBlockingDeque<>()); + test(new ArrayBlockingQueue<>(10)); + } + + private static void test(BlockingQueue q) + throws ExecutionException, InterruptedException { + System.out.println(q.getClass()); + try (var pool = Executors.newCachedThreadPool()) { + var futures = new ArrayList>(); + var phaser = new Phaser(4) { + @Override + protected boolean onAdvance(int phase, int registeredParties) { + q.clear(); + return super.onAdvance(phase, registeredParties); + } + }; + for (var i = 0; i < 4; i++) { + futures.add(pool.submit(() -> { + int errors = 0; + for (int k = 0; k < 10; k++) { + for (int j = 0; j < 1000; j++) { + q.offer(j); + if (q.peek() == null) + ++errors; + if (q.poll() == null) + ++errors; + } + phaser.arriveAndAwaitAdvance(); + } + return errors; + })); + } + for (var future : futures) { + Integer res; + if ((res = future.get()) != 0) + throw new AssertionError("Expected 0 but got " + res); + } + } + if (!q.isEmpty()) + throw new AssertionError("Queue is not empty: " + q); + } +} From 150def42dd7f22d949b4d788bfe5986f236b9b37 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Thu, 27 Nov 2025 12:42:42 +0000 Subject: [PATCH 039/706] 8369911: Test sun/java2d/marlin/ClipShapeTest.java#CubicDoDash, #Cubic and #Poly fail intermittent Reviewed-by: mdoerr, rriggs, serb --- test/jdk/sun/java2d/marlin/ClipShapeTest.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/test/jdk/sun/java2d/marlin/ClipShapeTest.java b/test/jdk/sun/java2d/marlin/ClipShapeTest.java index 3bdbd416e63..e77fca6924d 100644 --- a/test/jdk/sun/java2d/marlin/ClipShapeTest.java +++ b/test/jdk/sun/java2d/marlin/ClipShapeTest.java @@ -154,13 +154,12 @@ public final class ClipShapeTest { static final AtomicBoolean isMarlin = new AtomicBoolean(); static final AtomicBoolean isClipRuntime = new AtomicBoolean(); + static final Logger log = Logger.getLogger("sun.java2d.marlin"); + static { Locale.setDefault(Locale.US); // FIRST: Get Marlin runtime state from its log: - - // initialize j.u.l Looger: - final Logger log = Logger.getLogger("sun.java2d.marlin"); log.addHandler(new Handler() { @Override public void publish(LogRecord record) { From 5f5bf1971ca622b053c4eae146298090d6944473 Mon Sep 17 00:00:00 2001 From: Ramkumar Sunderbabu Date: Thu, 27 Nov 2025 13:00:36 +0000 Subject: [PATCH 040/706] 8319540: GC: Make TestSelectDefaultGC use createTestJavaProcessBuilder Reviewed-by: lkorinth, stefank --- test/hotspot/jtreg/gc/arguments/TestSelectDefaultGC.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/hotspot/jtreg/gc/arguments/TestSelectDefaultGC.java b/test/hotspot/jtreg/gc/arguments/TestSelectDefaultGC.java index af3f77a8a76..a5e144bcd15 100644 --- a/test/hotspot/jtreg/gc/arguments/TestSelectDefaultGC.java +++ b/test/hotspot/jtreg/gc/arguments/TestSelectDefaultGC.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, 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 @@ -44,7 +44,7 @@ public class TestSelectDefaultGC { public static void testDefaultGC(boolean actAsServer) throws Exception { // Start VM without specifying GC - OutputAnalyzer output = GCArguments.executeLimitedTestJava( + OutputAnalyzer output = GCArguments.executeTestJava( "-XX:" + (actAsServer ? "+" : "-") + "AlwaysActAsServerClassMachine", "-XX:" + (actAsServer ? "-" : "+") + "NeverActAsServerClassMachine", "-XX:+PrintFlagsFinal", From 561c544d85ecdbfa7895e434e98aed8df250a305 Mon Sep 17 00:00:00 2001 From: Mikhail Yankelevich Date: Thu, 27 Nov 2025 13:22:40 +0000 Subject: [PATCH 041/706] 8367096: jdk/open/test/jdk/sun/security/pkcs11/ rsa, ec, config, secmod and sslecc tests are skipping but showing as pass Reviewed-by: rhalade --- .../pkcs11/Config/ReadConfInUTF16Env.java | 6 +++--- test/jdk/sun/security/pkcs11/PKCS11Test.java | 2 +- .../security/pkcs11/Secmod/AddPrivateKey.java | 6 ++---- .../pkcs11/Secmod/AddTrustedCert.java | 5 +---- .../sun/security/pkcs11/Secmod/Crypto.java | 7 ++----- .../security/pkcs11/Secmod/GetPrivateKey.java | 7 ++----- .../pkcs11/Secmod/JksSetPrivateKey.java | 7 ++----- .../security/pkcs11/Secmod/LoadKeystore.java | 7 ++----- .../pkcs11/Secmod/TestNssDbSqlite.java | 20 +++++-------------- .../security/pkcs11/Secmod/TrustAnchors.java | 7 ++----- test/jdk/sun/security/pkcs11/SecmodTest.java | 5 ++--- .../security/pkcs11/ec/ReadCertificates.java | 4 ++-- .../sun/security/pkcs11/ec/ReadPKCS12.java | 4 ++-- .../security/pkcs11/ec/TestKeyFactory.java | 7 ++++--- test/jdk/sun/security/pkcs11/rsa/KeyWrap.java | 10 +++++----- .../pkcs11/sslecc/ClientJSSEServerJSSE.java | 4 ++-- 16 files changed, 39 insertions(+), 69 deletions(-) diff --git a/test/jdk/sun/security/pkcs11/Config/ReadConfInUTF16Env.java b/test/jdk/sun/security/pkcs11/Config/ReadConfInUTF16Env.java index eacc0337cb6..23f5fc3d6a1 100644 --- a/test/jdk/sun/security/pkcs11/Config/ReadConfInUTF16Env.java +++ b/test/jdk/sun/security/pkcs11/Config/ReadConfInUTF16Env.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, 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 jdk.test.lib.process.ProcessTools; +import jtreg.SkippedException; import org.testng.annotations.Test; import java.security.Provider; @@ -47,8 +48,7 @@ public class ReadConfInUTF16Env { public static void main(String[] args) throws Exception { Provider p = Security.getProvider("SunPKCS11"); if (p == null) { - System.out.println("Skipping test - no PKCS11 provider available"); - return; + throw new SkippedException("No PKCS11 provider available"); } System.out.println(p.getName()); } diff --git a/test/jdk/sun/security/pkcs11/PKCS11Test.java b/test/jdk/sun/security/pkcs11/PKCS11Test.java index 0e8d2d61d53..3b09f845f8e 100644 --- a/test/jdk/sun/security/pkcs11/PKCS11Test.java +++ b/test/jdk/sun/security/pkcs11/PKCS11Test.java @@ -828,7 +828,7 @@ public abstract class PKCS11Test { private void premain(Provider p) throws Exception { if (skipTest(p)) { - return; + throw new SkippedException("See logs for details"); } long start = System.currentTimeMillis(); diff --git a/test/jdk/sun/security/pkcs11/Secmod/AddPrivateKey.java b/test/jdk/sun/security/pkcs11/Secmod/AddPrivateKey.java index 29950d762e0..34a813ab858 100644 --- a/test/jdk/sun/security/pkcs11/Secmod/AddPrivateKey.java +++ b/test/jdk/sun/security/pkcs11/Secmod/AddPrivateKey.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2025, 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 @@ -62,9 +62,7 @@ public class AddPrivateKey extends SecmodTest { private static final byte[] DATA = generateData(DATA_LENGTH); public static void main(String[] args) throws Exception { - if (initSecmod() == false) { - return; - } + initSecmod(); String configName = BASE + SEP + "nss.cfg"; Provider p = getSunPKCS11(configName); diff --git a/test/jdk/sun/security/pkcs11/Secmod/AddTrustedCert.java b/test/jdk/sun/security/pkcs11/Secmod/AddTrustedCert.java index 7b4a5075da8..aaa38fe1c71 100644 --- a/test/jdk/sun/security/pkcs11/Secmod/AddTrustedCert.java +++ b/test/jdk/sun/security/pkcs11/Secmod/AddTrustedCert.java @@ -31,7 +31,6 @@ * @run main/othervm AddTrustedCert */ -import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.security.KeyStore; @@ -47,9 +46,7 @@ import java.util.TreeSet; public class AddTrustedCert extends SecmodTest { public static void main(String[] args) throws Exception { - if (initSecmod() == false) { - return; - } + initSecmod(); X509Certificate cert; try (InputStream in = new FileInputStream(BASE + SEP + "anchor.cer")) { diff --git a/test/jdk/sun/security/pkcs11/Secmod/Crypto.java b/test/jdk/sun/security/pkcs11/Secmod/Crypto.java index 1b4c0883e80..e9e9bd73321 100644 --- a/test/jdk/sun/security/pkcs11/Secmod/Crypto.java +++ b/test/jdk/sun/security/pkcs11/Secmod/Crypto.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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,7 +31,6 @@ * @run main/othervm Crypto */ -import java.io.File; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.Provider; @@ -40,9 +39,7 @@ import java.security.Signature; public class Crypto extends SecmodTest { public static void main(String[] args) throws Exception { - if (initSecmod() == false) { - return; - } + initSecmod(); String configName = BASE + SEP + "nsscrypto.cfg"; Provider p = getSunPKCS11(configName); diff --git a/test/jdk/sun/security/pkcs11/Secmod/GetPrivateKey.java b/test/jdk/sun/security/pkcs11/Secmod/GetPrivateKey.java index e89cafb920c..8d613ee63d2 100644 --- a/test/jdk/sun/security/pkcs11/Secmod/GetPrivateKey.java +++ b/test/jdk/sun/security/pkcs11/Secmod/GetPrivateKey.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ * @run main/othervm GetPrivateKey */ -import java.io.File; import java.security.KeyStore; import java.security.PrivateKey; import java.security.Provider; @@ -46,9 +45,7 @@ import java.util.TreeSet; public class GetPrivateKey extends SecmodTest { public static void main(String[] args) throws Exception { - if (initSecmod() == false) { - return; - } + initSecmod(); String configName = BASE + SEP + "nss.cfg"; Provider p = getSunPKCS11(configName); diff --git a/test/jdk/sun/security/pkcs11/Secmod/JksSetPrivateKey.java b/test/jdk/sun/security/pkcs11/Secmod/JksSetPrivateKey.java index d6c084c882d..8549a338a58 100644 --- a/test/jdk/sun/security/pkcs11/Secmod/JksSetPrivateKey.java +++ b/test/jdk/sun/security/pkcs11/Secmod/JksSetPrivateKey.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2025, 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,7 +31,6 @@ * @run main/othervm JksSetPrivateKey */ -import java.io.File; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.PrivateKey; @@ -45,9 +44,7 @@ import java.util.TreeSet; public class JksSetPrivateKey extends SecmodTest { public static void main(String[] args) throws Exception { - if (initSecmod() == false) { - return; - } + initSecmod(); String configName = BASE + SEP + "nss.cfg"; Provider p = getSunPKCS11(configName); diff --git a/test/jdk/sun/security/pkcs11/Secmod/LoadKeystore.java b/test/jdk/sun/security/pkcs11/Secmod/LoadKeystore.java index 55c473ce90e..d657d805ca0 100644 --- a/test/jdk/sun/security/pkcs11/Secmod/LoadKeystore.java +++ b/test/jdk/sun/security/pkcs11/Secmod/LoadKeystore.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, 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,7 +30,6 @@ * @run main/othervm LoadKeystore */ -import java.io.File; import java.io.IOException; import java.security.KeyStore; import java.security.KeyStoreException; @@ -42,9 +41,7 @@ import java.util.Collections; public class LoadKeystore extends SecmodTest { public static void main(String[] args) throws Exception { - if (!initSecmod()) { - return; - } + initSecmod(); String configName = BASE + SEP + "nss.cfg"; Provider p = getSunPKCS11(configName); diff --git a/test/jdk/sun/security/pkcs11/Secmod/TestNssDbSqlite.java b/test/jdk/sun/security/pkcs11/Secmod/TestNssDbSqlite.java index 7b22a4abfc6..57309749e93 100644 --- a/test/jdk/sun/security/pkcs11/Secmod/TestNssDbSqlite.java +++ b/test/jdk/sun/security/pkcs11/Secmod/TestNssDbSqlite.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2018, Red Hat, Inc. and/or its affiliates. + * Copyright (c) 2017, 2025, Red Hat, Inc. and/or its affiliates. * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -46,6 +46,7 @@ import java.security.KeyStore; import java.security.Provider; import java.security.Signature; +import jtreg.SkippedException; import sun.security.rsa.SunRsaSign; import sun.security.jca.ProviderList; import sun.security.jca.Providers; @@ -66,9 +67,7 @@ public final class TestNssDbSqlite extends SecmodTest { public static void main(String[] args) throws Exception { - if (!initialize()) { - return; - } + initializeProvider(); if (enableDebug) { System.out.println("SunPKCS11 provider: " + @@ -110,16 +109,9 @@ public final class TestNssDbSqlite extends SecmodTest { } } - private static boolean initialize() throws Exception { - return initializeProvider(); - } - - private static boolean initializeProvider() throws Exception { + private static void initializeProvider() throws Exception { useSqlite(true); - if (!initSecmod()) { - System.out.println("Cannot init security module database, skipping"); - return false; - } + initSecmod(); sunPKCS11NSSProvider = getSunPKCS11(BASE + SEP + "nss-sqlite.cfg"); sunJCEProvider = new com.sun.crypto.provider.SunJCE(); @@ -135,7 +127,5 @@ public final class TestNssDbSqlite extends SecmodTest { gen.generate(2048); privateKey = gen.getPrivateKey(); certificate = gen.getSelfCertificate(new X500Name("CN=Me"), 365); - - return true; } } diff --git a/test/jdk/sun/security/pkcs11/Secmod/TrustAnchors.java b/test/jdk/sun/security/pkcs11/Secmod/TrustAnchors.java index efe34478a9e..14977fde340 100644 --- a/test/jdk/sun/security/pkcs11/Secmod/TrustAnchors.java +++ b/test/jdk/sun/security/pkcs11/Secmod/TrustAnchors.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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,7 +31,6 @@ * @run main/othervm TrustAnchors */ -import java.io.File; import java.security.KeyStore; import java.security.Provider; import java.security.Security; @@ -43,9 +42,7 @@ import java.util.TreeSet; public class TrustAnchors extends SecmodTest { public static void main(String[] args) throws Exception { - if (initSecmod() == false) { - return; - } + initSecmod(); // our secmod.db file says nssckbi.*so*, so NSS does not find the // *DLL* on Windows nor the *DYLIB* on Mac OSX. diff --git a/test/jdk/sun/security/pkcs11/SecmodTest.java b/test/jdk/sun/security/pkcs11/SecmodTest.java index 8201548bf9d..1979066e26a 100644 --- a/test/jdk/sun/security/pkcs11/SecmodTest.java +++ b/test/jdk/sun/security/pkcs11/SecmodTest.java @@ -42,7 +42,7 @@ public class SecmodTest extends PKCS11Test { useSqlite = b; } - static boolean initSecmod() throws Exception { + static void initSecmod() throws Exception { useNSS(); LIBPATH = getNSSLibDir(); // load all the libraries except libnss3 into memory @@ -60,7 +60,7 @@ public class SecmodTest extends PKCS11Test { System.setProperty("pkcs11test.nss.db", DBDIR); } File dbdirFile = new File(DBDIR); - if (dbdirFile.exists() == false) { + if (!dbdirFile.exists()) { dbdirFile.mkdir(); } @@ -73,7 +73,6 @@ public class SecmodTest extends PKCS11Test { copyFile("key3.db", BASE, DBDIR); copyFile("cert8.db", BASE, DBDIR); } - return true; } private static void copyFile(String name, String srcDir, String dstDir) throws IOException { diff --git a/test/jdk/sun/security/pkcs11/ec/ReadCertificates.java b/test/jdk/sun/security/pkcs11/ec/ReadCertificates.java index e2bfa3dc048..4ff17356eb6 100644 --- a/test/jdk/sun/security/pkcs11/ec/ReadCertificates.java +++ b/test/jdk/sun/security/pkcs11/ec/ReadCertificates.java @@ -55,6 +55,7 @@ import java.util.List; import java.util.Map; import javax.security.auth.x500.X500Principal; import jdk.test.lib.security.Providers; +import jtreg.SkippedException; public class ReadCertificates extends PKCS11Test { @@ -78,8 +79,7 @@ public class ReadCertificates extends PKCS11Test { @Override public void main(Provider p) throws Exception { if (p.getService("Signature", "SHA1withECDSA") == null) { - System.out.println("Provider does not support ECDSA, skipping..."); - return; + throw new SkippedException("Provider does not support ECDSA"); } /* diff --git a/test/jdk/sun/security/pkcs11/ec/ReadPKCS12.java b/test/jdk/sun/security/pkcs11/ec/ReadPKCS12.java index 15a5b14ec40..eea360b64fe 100644 --- a/test/jdk/sun/security/pkcs11/ec/ReadPKCS12.java +++ b/test/jdk/sun/security/pkcs11/ec/ReadPKCS12.java @@ -54,6 +54,7 @@ import java.util.List; import java.util.Map; import java.util.Random; import jdk.test.lib.security.Providers; +import jtreg.SkippedException; public class ReadPKCS12 extends PKCS11Test { @@ -66,8 +67,7 @@ public class ReadPKCS12 extends PKCS11Test { @Override public void main(Provider p) throws Exception { if (p.getService("Signature", "SHA1withECDSA") == null) { - System.out.println("Provider does not support ECDSA, skipping..."); - return; + throw new SkippedException("Provider does not support ECDSA"); } /* diff --git a/test/jdk/sun/security/pkcs11/ec/TestKeyFactory.java b/test/jdk/sun/security/pkcs11/ec/TestKeyFactory.java index d23c302f38f..94453dd649d 100644 --- a/test/jdk/sun/security/pkcs11/ec/TestKeyFactory.java +++ b/test/jdk/sun/security/pkcs11/ec/TestKeyFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2025, 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,8 @@ * @run main/othervm TestKeyFactory */ +import jtreg.SkippedException; + import java.security.Key; import java.security.KeyFactory; import java.security.KeyPair; @@ -126,8 +128,7 @@ public class TestKeyFactory extends PKCS11Test { @Override public void main(Provider p) throws Exception { if (p.getService("KeyFactory", "EC") == null) { - System.out.println("Provider does not support EC, skipping"); - return; + throw new SkippedException("Provider does not support EC, skipping"); } int[] keyLengths = {256, 521}; KeyFactory kf = KeyFactory.getInstance("EC", p); diff --git a/test/jdk/sun/security/pkcs11/rsa/KeyWrap.java b/test/jdk/sun/security/pkcs11/rsa/KeyWrap.java index 4fd4082f523..8d71b5e26ca 100644 --- a/test/jdk/sun/security/pkcs11/rsa/KeyWrap.java +++ b/test/jdk/sun/security/pkcs11/rsa/KeyWrap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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,6 +32,8 @@ * @run main/othervm KeyWrap */ +import jtreg.SkippedException; + import java.security.GeneralSecurityException; import java.security.InvalidKeyException; import java.security.Key; @@ -54,8 +56,7 @@ public class KeyWrap extends PKCS11Test { try { Cipher.getInstance("RSA/ECB/PKCS1Padding", p); } catch (GeneralSecurityException e) { - System.out.println("Not supported by provider, skipping"); - return; + throw new SkippedException("Not supported by provider, skipping"); } KeyPair kp; try { @@ -74,8 +75,7 @@ public class KeyWrap extends PKCS11Test { kp = new KeyPair(pub, priv); } catch (NoSuchAlgorithmException | InvalidKeyException ee) { ee.printStackTrace(); - System.out.println("Provider does not support RSA, skipping"); - return; + throw new SkippedException("Provider does not support RSA, skipping"); } } System.out.println(kp); diff --git a/test/jdk/sun/security/pkcs11/sslecc/ClientJSSEServerJSSE.java b/test/jdk/sun/security/pkcs11/sslecc/ClientJSSEServerJSSE.java index c125464659b..2630d9e310b 100644 --- a/test/jdk/sun/security/pkcs11/sslecc/ClientJSSEServerJSSE.java +++ b/test/jdk/sun/security/pkcs11/sslecc/ClientJSSEServerJSSE.java @@ -40,6 +40,7 @@ import java.security.Provider; import java.security.Security; import jdk.test.lib.security.Providers; +import jtreg.SkippedException; public class ClientJSSEServerJSSE extends PKCS11Test { @@ -58,8 +59,7 @@ public class ClientJSSEServerJSSE extends PKCS11Test { @Override public void main(Provider p) throws Exception { if (p.getService("KeyFactory", "EC") == null) { - System.out.println("Provider does not support EC, skipping"); - return; + throw new SkippedException("Provider does not support EC, skipping"); } Providers.setAt(p, 1); CipherTest.main(new JSSEFactory(), cmdArgs); From da8e41a368bd98a7a35f5706302ecb9475b58363 Mon Sep 17 00:00:00 2001 From: Mikhail Yankelevich Date: Thu, 27 Nov 2025 13:23:14 +0000 Subject: [PATCH 042/706] 8365623: test/jdk/sun/security/pkcs11/tls/ tests skipped without skip exception Reviewed-by: syan, rhalade --- test/jdk/sun/security/pkcs11/tls/TestKeyMaterial.java | 7 +++---- .../security/pkcs11/tls/TestKeyMaterialChaCha20.java | 11 +++++------ .../jdk/sun/security/pkcs11/tls/TestMasterSecret.java | 7 ++++--- test/jdk/sun/security/pkcs11/tls/TestPRF.java | 7 ++++--- test/jdk/sun/security/pkcs11/tls/TestPremaster.java | 10 +++++----- .../jdk/sun/security/pkcs11/tls/fips/FipsModeTLS.java | 10 +++++----- 6 files changed, 26 insertions(+), 26 deletions(-) diff --git a/test/jdk/sun/security/pkcs11/tls/TestKeyMaterial.java b/test/jdk/sun/security/pkcs11/tls/TestKeyMaterial.java index 977ae5338bd..682c09bab41 100644 --- a/test/jdk/sun/security/pkcs11/tls/TestKeyMaterial.java +++ b/test/jdk/sun/security/pkcs11/tls/TestKeyMaterial.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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,7 +35,6 @@ import java.io.BufferedReader; import java.nio.file.Files; import java.nio.file.Paths; -import java.security.InvalidAlgorithmParameterException; import java.security.Provider; import java.security.ProviderException; import java.util.Arrays; @@ -45,6 +44,7 @@ import javax.crypto.SecretKey; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; +import jtreg.SkippedException; import sun.security.internal.spec.TlsKeyMaterialParameterSpec; import sun.security.internal.spec.TlsKeyMaterialSpec; @@ -60,8 +60,7 @@ public class TestKeyMaterial extends PKCS11Test { @Override public void main(Provider provider) throws Exception { if (provider.getService("KeyGenerator", "SunTlsKeyMaterial") == null) { - System.out.println("Provider does not support algorithm, skipping"); - return; + throw new SkippedException("Provider does not support algorithm, skipping"); } try (BufferedReader reader = Files.newBufferedReader( diff --git a/test/jdk/sun/security/pkcs11/tls/TestKeyMaterialChaCha20.java b/test/jdk/sun/security/pkcs11/tls/TestKeyMaterialChaCha20.java index 51471fca65a..b784a3127c6 100644 --- a/test/jdk/sun/security/pkcs11/tls/TestKeyMaterialChaCha20.java +++ b/test/jdk/sun/security/pkcs11/tls/TestKeyMaterialChaCha20.java @@ -35,6 +35,8 @@ import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; import java.security.Provider; import java.security.NoSuchAlgorithmException; + +import jtreg.SkippedException; import sun.security.internal.spec.TlsRsaPremasterSecretParameterSpec; import sun.security.internal.spec.TlsMasterSecretParameterSpec; import sun.security.internal.spec.TlsKeyMaterialParameterSpec; @@ -52,20 +54,17 @@ public class TestKeyMaterialChaCha20 extends PKCS11Test { try { kg1 = KeyGenerator.getInstance("SunTlsRsaPremasterSecret", provider); } catch (Exception e) { - System.out.println("Skipping, SunTlsRsaPremasterSecret KeyGenerator not supported"); - return; + throw new SkippedException("Skipping, SunTlsRsaPremasterSecret KeyGenerator not supported"); } try { kg2 = KeyGenerator.getInstance("SunTls12MasterSecret", provider); } catch (Exception e) { - System.out.println("Skipping, SunTls12MasterSecret KeyGenerator not supported"); - return; + throw new SkippedException("Skipping, SunTls12MasterSecret KeyGenerator not supported"); } try { kg3 = KeyGenerator.getInstance("SunTls12KeyMaterial", provider); } catch (Exception e) { - System.out.println("Skipping, SunTls12KeyMaterial KeyGenerator not supported"); - return; + throw new SkippedException("Skipping, SunTls12KeyMaterial KeyGenerator not supported"); } kg1.init(new TlsRsaPremasterSecretParameterSpec(0x0303, 0x0303)); diff --git a/test/jdk/sun/security/pkcs11/tls/TestMasterSecret.java b/test/jdk/sun/security/pkcs11/tls/TestMasterSecret.java index 52e2327cfc9..f969aece532 100644 --- a/test/jdk/sun/security/pkcs11/tls/TestMasterSecret.java +++ b/test/jdk/sun/security/pkcs11/tls/TestMasterSecret.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -42,6 +42,8 @@ import java.util.Arrays; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; + +import jtreg.SkippedException; import sun.security.internal.interfaces.TlsMasterSecret; import sun.security.internal.spec.TlsMasterSecretParameterSpec; @@ -56,8 +58,7 @@ public class TestMasterSecret extends PKCS11Test { @Override public void main(Provider provider) throws Exception { if (provider.getService("KeyGenerator", "SunTlsMasterSecret") == null) { - System.out.println("Not supported by provider, skipping"); - return; + throw new SkippedException("Not supported by provider, skipping"); } try (BufferedReader reader = Files.newBufferedReader( diff --git a/test/jdk/sun/security/pkcs11/tls/TestPRF.java b/test/jdk/sun/security/pkcs11/tls/TestPRF.java index ada1716c98b..662383095a9 100644 --- a/test/jdk/sun/security/pkcs11/tls/TestPRF.java +++ b/test/jdk/sun/security/pkcs11/tls/TestPRF.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -40,6 +40,8 @@ import java.util.Arrays; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; + +import jtreg.SkippedException; import sun.security.internal.spec.TlsPrfParameterSpec; public class TestPRF extends PKCS11Test { @@ -53,8 +55,7 @@ public class TestPRF extends PKCS11Test { @Override public void main(Provider provider) throws Exception { if (provider.getService("KeyGenerator", "SunTlsPrf") == null) { - System.out.println("Provider does not support algorithm, skipping"); - return; + throw new SkippedException("Provider does not support algorithm, skipping"); } try (BufferedReader reader = Files.newBufferedReader( diff --git a/test/jdk/sun/security/pkcs11/tls/TestPremaster.java b/test/jdk/sun/security/pkcs11/tls/TestPremaster.java index 9ee1dddb8e5..d34330fa073 100644 --- a/test/jdk/sun/security/pkcs11/tls/TestPremaster.java +++ b/test/jdk/sun/security/pkcs11/tls/TestPremaster.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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,8 @@ import java.security.Provider; import java.security.InvalidAlgorithmParameterException; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; + +import jtreg.SkippedException; import sun.security.internal.spec.TlsRsaPremasterSecretParameterSpec; public class TestPremaster extends PKCS11Test { @@ -48,8 +50,7 @@ public class TestPremaster extends PKCS11Test { public void main(Provider provider) throws Exception { if (provider.getService( "KeyGenerator", "SunTlsRsaPremasterSecret") == null) { - System.out.println("Not supported by provider, skipping"); - return; + throw new SkippedException("Not supported by provider, skipping"); } KeyGenerator kg; kg = KeyGenerator.getInstance("SunTlsRsaPremasterSecret", provider); @@ -87,8 +88,7 @@ public class TestPremaster extends PKCS11Test { } catch (InvalidAlgorithmParameterException iape) { // S12 removed support for SSL v3.0 if (clientVersion == 0x300 || serverVersion == 0x300) { - System.out.println("Skip testing SSLv3 due to no support"); - return; + throw new SkippedException("Skip testing SSLv3 due to no support"); } // unexpected, pass it up throw iape; diff --git a/test/jdk/sun/security/pkcs11/tls/fips/FipsModeTLS.java b/test/jdk/sun/security/pkcs11/tls/fips/FipsModeTLS.java index c227e99d12b..d0b1407422a 100644 --- a/test/jdk/sun/security/pkcs11/tls/fips/FipsModeTLS.java +++ b/test/jdk/sun/security/pkcs11/tls/fips/FipsModeTLS.java @@ -71,6 +71,7 @@ import javax.net.ssl.SSLSession; import javax.net.ssl.TrustManagerFactory; import jdk.test.lib.security.SecurityUtils; +import jtreg.SkippedException; import sun.security.internal.spec.TlsMasterSecretParameterSpec; import sun.security.internal.spec.TlsPrfParameterSpec; import sun.security.internal.spec.TlsRsaPremasterSecretParameterSpec; @@ -94,12 +95,11 @@ public final class FipsModeTLS extends SecmodTest { try { initialize(); } catch (Exception e) { - System.out.println("Test skipped: failure during" + - " initialization"); if (enableDebug) { System.out.println(e); } - return; + throw new SkippedException("Test skipped: failure during" + + " initialization"); } if (shouldRun()) { @@ -112,8 +112,8 @@ public final class FipsModeTLS extends SecmodTest { System.out.println("Test PASS - OK"); } else { - System.out.println("Test skipped: TLS 1.2 mechanisms" + - " not supported by current SunPKCS11 back-end"); + throw new SkippedException("Test skipped: TLS 1.2 mechanisms" + + " not supported by current SunPKCS11 back-end"); } } From 6901c05c9d23cde41e2af510e7d610af66e40770 Mon Sep 17 00:00:00 2001 From: Alan Bateman Date: Thu, 27 Nov 2025 14:17:13 +0000 Subject: [PATCH 043/706] 8371815: API docs for 2-arg StructuredTaskScope.open should say timeout may expire before or while waiting in join Reviewed-by: vklang --- .../classes/java/util/concurrent/StructuredTaskScope.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 941d6bd55cb..01bf1158bf6 100644 --- a/src/java.base/share/classes/java/util/concurrent/StructuredTaskScope.java +++ b/src/java.base/share/classes/java/util/concurrent/StructuredTaskScope.java @@ -914,8 +914,8 @@ public sealed interface StructuredTaskScope * forking subtasks will create an unnamed virtual thread for each subtask. * *

    If a {@linkplain Configuration#withTimeout(Duration) timeout} is set then it - * starts when the scope is opened. If the timeout expires before the scope has - * {@linkplain #join() joined} then the scope is {@linkplain ##Cancellation cancelled} + * starts when the scope is opened. If the timeout expires before or while waiting in + * {@link #join()} then the scope is {@linkplain ##Cancellation cancelled} * and the {@code Joiner}'s {@link Joiner#onTimeout() onTimeout()} method is invoked * to optionally throw {@link TimeoutException TimeoutException}. * From 683ef14bcec0e6c4825067229826ed4a53cd3d19 Mon Sep 17 00:00:00 2001 From: Jonas Norlinder Date: Thu, 27 Nov 2025 14:59:07 +0000 Subject: [PATCH 044/706] 8372625: [Linux] Remove unnecessary logic for supports_fast_thread_cpu_time Reviewed-by: sjohanss, dholmes --- src/hotspot/os/linux/os_linux.cpp | 72 +++++-------------- src/hotspot/os/linux/os_linux.hpp | 17 +---- src/hotspot/share/runtime/cpuTimeCounters.cpp | 3 - 3 files changed, 17 insertions(+), 75 deletions(-) diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index efeeec6f484..a1d957eb77d 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -159,9 +159,7 @@ physical_memory_size_type os::Linux::_physical_memory = 0; address os::Linux::_initial_thread_stack_bottom = nullptr; uintptr_t os::Linux::_initial_thread_stack_size = 0; -int (*os::Linux::_pthread_getcpuclockid)(pthread_t, clockid_t *) = nullptr; pthread_t os::Linux::_main_thread; -bool os::Linux::_supports_fast_thread_cpu_time = false; const char * os::Linux::_libc_version = nullptr; const char * os::Linux::_libpthread_version = nullptr; @@ -1475,29 +1473,6 @@ void os::Linux::capture_initial_stack(size_t max_size) { //////////////////////////////////////////////////////////////////////////////// // time support -void os::Linux::fast_thread_clock_init() { - clockid_t clockid; - struct timespec tp; - int (*pthread_getcpuclockid_func)(pthread_t, clockid_t *) = - (int(*)(pthread_t, clockid_t *)) dlsym(RTLD_DEFAULT, "pthread_getcpuclockid"); - - // Switch to using fast clocks for thread cpu time if - // the clock_getres() returns 0 error code. - // Note, that some kernels may support the current thread - // clock (CLOCK_THREAD_CPUTIME_ID) but not the clocks - // returned by the pthread_getcpuclockid(). - // If the fast POSIX clocks are supported then the clock_getres() - // must return at least tp.tv_sec == 0 which means a resolution - // better than 1 sec. This is extra check for reliability. - - if (pthread_getcpuclockid_func && - pthread_getcpuclockid_func(_main_thread, &clockid) == 0 && - clock_getres(clockid, &tp) == 0 && tp.tv_sec == 0) { - _supports_fast_thread_cpu_time = true; - _pthread_getcpuclockid = pthread_getcpuclockid_func; - } -} - // thread_id is kernel thread id (similar to Solaris LWP id) intx os::current_thread_id() { return os::Linux::gettid(); } int os::current_process_id() { @@ -4328,7 +4303,7 @@ OSReturn os::get_native_priority(const Thread* const thread, // For reference, please, see IEEE Std 1003.1-2004: // http://www.unix.org/single_unix_specification -jlong os::Linux::fast_thread_cpu_time(clockid_t clockid) { +jlong os::Linux::total_thread_cpu_time(clockid_t clockid) { struct timespec tp; int status = clock_gettime(clockid, &tp); assert(status == 0, "clock_gettime error: %s", os::strerror(errno)); @@ -4556,8 +4531,6 @@ jint os::init_2(void) { os::Posix::init_2(); - Linux::fast_thread_clock_init(); - if (PosixSignals::init() == JNI_ERR) { return JNI_ERR; } @@ -4985,14 +4958,14 @@ int os::open(const char *path, int oflag, int mode) { return fd; } -static jlong slow_thread_cpu_time(Thread *thread, bool user_sys_cpu_time); +static jlong user_thread_cpu_time(Thread *thread); -static jlong fast_cpu_time(Thread *thread) { +static jlong total_thread_cpu_time(Thread *thread) { clockid_t clockid; - int rc = os::Linux::pthread_getcpuclockid(thread->osthread()->pthread_id(), + int rc = pthread_getcpuclockid(thread->osthread()->pthread_id(), &clockid); if (rc == 0) { - return os::Linux::fast_thread_cpu_time(clockid); + return os::Linux::total_thread_cpu_time(clockid); } else { // It's possible to encounter a terminated native thread that failed // to detach itself from the VM - which should result in ESRCH. @@ -5009,41 +4982,31 @@ static jlong fast_cpu_time(Thread *thread) { // the fast estimate available on the platform. jlong os::current_thread_cpu_time() { - if (os::Linux::supports_fast_thread_cpu_time()) { - return os::Linux::fast_thread_cpu_time(CLOCK_THREAD_CPUTIME_ID); - } else { - // return user + sys since the cost is the same - return slow_thread_cpu_time(Thread::current(), true /* user + sys */); - } + return os::Linux::total_thread_cpu_time(CLOCK_THREAD_CPUTIME_ID); } jlong os::thread_cpu_time(Thread* thread) { - // consistent with what current_thread_cpu_time() returns - if (os::Linux::supports_fast_thread_cpu_time()) { - return fast_cpu_time(thread); - } else { - return slow_thread_cpu_time(thread, true /* user + sys */); - } + return total_thread_cpu_time(thread); } jlong os::current_thread_cpu_time(bool user_sys_cpu_time) { - if (user_sys_cpu_time && os::Linux::supports_fast_thread_cpu_time()) { - return os::Linux::fast_thread_cpu_time(CLOCK_THREAD_CPUTIME_ID); + if (user_sys_cpu_time) { + return os::Linux::total_thread_cpu_time(CLOCK_THREAD_CPUTIME_ID); } else { - return slow_thread_cpu_time(Thread::current(), user_sys_cpu_time); + return user_thread_cpu_time(Thread::current()); } } jlong os::thread_cpu_time(Thread *thread, bool user_sys_cpu_time) { - if (user_sys_cpu_time && os::Linux::supports_fast_thread_cpu_time()) { - return fast_cpu_time(thread); + if (user_sys_cpu_time) { + return total_thread_cpu_time(thread); } else { - return slow_thread_cpu_time(thread, user_sys_cpu_time); + return user_thread_cpu_time(thread); } } // -1 on error. -static jlong slow_thread_cpu_time(Thread *thread, bool user_sys_cpu_time) { +static jlong user_thread_cpu_time(Thread *thread) { pid_t tid = thread->osthread()->thread_id(); char *s; char stat[2048]; @@ -5080,11 +5043,8 @@ static jlong slow_thread_cpu_time(Thread *thread, bool user_sys_cpu_time) { &ldummy, &ldummy, &ldummy, &ldummy, &ldummy, &user_time, &sys_time); if (count != 13) return -1; - if (user_sys_cpu_time) { - return ((jlong)sys_time + (jlong)user_time) * (1000000000 / os::Posix::clock_tics_per_second()); - } else { - return (jlong)user_time * (1000000000 / os::Posix::clock_tics_per_second()); - } + + return (jlong)user_time * (1000000000 / os::Posix::clock_tics_per_second()); } void os::current_thread_cpu_time_info(jvmtiTimerInfo *info_ptr) { diff --git a/src/hotspot/os/linux/os_linux.hpp b/src/hotspot/os/linux/os_linux.hpp index 9c0b6723b38..dd07cb600b9 100644 --- a/src/hotspot/os/linux/os_linux.hpp +++ b/src/hotspot/os/linux/os_linux.hpp @@ -32,16 +32,12 @@ class os::Linux { friend class os; - static int (*_pthread_getcpuclockid)(pthread_t, clockid_t *); - static address _initial_thread_stack_bottom; static uintptr_t _initial_thread_stack_size; static const char *_libc_version; static const char *_libpthread_version; - static bool _supports_fast_thread_cpu_time; - static GrowableArray* _cpu_to_node; static GrowableArray* _nindex_to_node; @@ -146,18 +142,7 @@ class os::Linux { static bool manually_expand_stack(JavaThread * t, address addr); static void expand_stack_to(address bottom); - // fast POSIX clocks support - static void fast_thread_clock_init(void); - - static int pthread_getcpuclockid(pthread_t tid, clockid_t *clock_id) { - return _pthread_getcpuclockid ? _pthread_getcpuclockid(tid, clock_id) : -1; - } - - static bool supports_fast_thread_cpu_time() { - return _supports_fast_thread_cpu_time; - } - - static jlong fast_thread_cpu_time(clockid_t clockid); + static jlong total_thread_cpu_time(clockid_t clockid); static jlong sendfile(int out_fd, int in_fd, jlong* offset, jlong count); diff --git a/src/hotspot/share/runtime/cpuTimeCounters.cpp b/src/hotspot/share/runtime/cpuTimeCounters.cpp index e5364550b6c..e174407089c 100644 --- a/src/hotspot/share/runtime/cpuTimeCounters.cpp +++ b/src/hotspot/share/runtime/cpuTimeCounters.cpp @@ -118,8 +118,5 @@ ThreadTotalCPUTimeClosure::~ThreadTotalCPUTimeClosure() { } void ThreadTotalCPUTimeClosure::do_thread(Thread* thread) { - // The default code path (fast_thread_cpu_time()) asserts that - // pthread_getcpuclockid() and clock_gettime() must return 0. Thus caller - // must ensure the thread exists and has not terminated. _total += os::thread_cpu_time(thread); } From b2f97131d643ad7ebde137617999f1689a204975 Mon Sep 17 00:00:00 2001 From: Christoph Langer Date: Thu, 27 Nov 2025 15:43:53 +0000 Subject: [PATCH 045/706] 8317838: java/nio/channels/Channels/SocketChannelStreams.java running into timeout (aix) Reviewed-by: alanb, mdoerr --- test/jdk/ProblemList.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 9452b3a1b9f..9904bd88626 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -586,7 +586,6 @@ java/net/MulticastSocket/Test.java 7145658,8308807 # jdk_nio -java/nio/channels/Channels/SocketChannelStreams.java 8317838 aix-ppc64 java/nio/channels/AsyncCloseAndInterrupt.java 8368290 macosx-26.0.1 java/nio/channels/DatagramChannel/AdaptorMulticasting.java 8308807,8144003 aix-ppc64,macosx-all From 8a0672c819e09a16c30fbdf58dc2b81f50958da4 Mon Sep 17 00:00:00 2001 From: Daniel Fuchs Date: Thu, 27 Nov 2025 17:56:04 +0000 Subject: [PATCH 046/706] 8372198: Avoid closing PlainHttpConnection while holding a lock Reviewed-by: djelinski, jpai, vyazici --- .../jdk/internal/net/http/ConnectionPool.java | 36 +- .../jdk/internal/net/http/HttpClientImpl.java | 8 + .../net/http/PlainHttpConnection.java | 20 +- .../httpclient/PlainConnectionLockTest.java | 383 ++++++++++++++++++ 4 files changed, 422 insertions(+), 25 deletions(-) create mode 100644 test/jdk/java/net/httpclient/PlainConnectionLockTest.java diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/ConnectionPool.java b/src/java.net.http/share/classes/jdk/internal/net/http/ConnectionPool.java index 1d8cb013295..e1725aa92d5 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/ConnectionPool.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/ConnectionPool.java @@ -205,32 +205,38 @@ final class ConnectionPool { // it's possible that cleanup may have been called. HttpConnection toClose = null; + boolean stopping = false; stateLock.lock(); try { if (cleanup.isDone()) { return; - } else if (stopped) { - conn.close(); - return; - } - if (MAX_POOL_SIZE > 0 && expiryList.size() >= MAX_POOL_SIZE) { - toClose = expiryList.removeOldest(); - if (toClose != null) removeFromPool(toClose); - } - if (conn instanceof PlainHttpConnection) { - putConnection(conn, plainPool); + } else if (stopping = stopped) { + toClose = conn; } else { - assert conn.isSecure(); - putConnection(conn, sslPool); + if (MAX_POOL_SIZE > 0 && expiryList.size() >= MAX_POOL_SIZE) { + toClose = expiryList.removeOldest(); + if (toClose != null) removeFromPool(toClose); + } + if (conn instanceof PlainHttpConnection) { + putConnection(conn, plainPool); + } else { + assert conn.isSecure(); + putConnection(conn, sslPool); + } + expiryList.add(conn, now, keepAlive); } - expiryList.add(conn, now, keepAlive); } finally { stateLock.unlock(); } if (toClose != null) { if (debug.on()) { - debug.log("Maximum pool size reached: removing oldest connection %s", - toClose.dbgString()); + if (stopping) { + debug.log("Stopping: close connection %s", + toClose.dbgString()); + } else { + debug.log("Maximum pool size reached: removing oldest connection %s", + toClose.dbgString()); + } } close(toClose); } diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/HttpClientImpl.java b/src/java.net.http/share/classes/jdk/internal/net/http/HttpClientImpl.java index 54bad66d4fa..d02930f4f31 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/HttpClientImpl.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/HttpClientImpl.java @@ -1359,6 +1359,13 @@ final class HttpClientImpl extends HttpClient implements Trackable { // Only called by the selector manager thread private void shutdown() { + // first stop the client to avoid seeing exceptions + // about "selector manager closed" + Log.logTrace("{0}: stopping", owner.dbgTag); + try { + owner.stop(); + } catch (Throwable ignored) { + } try { lock.lock(); try { @@ -1371,6 +1378,7 @@ final class HttpClientImpl extends HttpClient implements Trackable { } } catch (IOException ignored) { } finally { + // cleanup anything that might have been left behind owner.stop(); } } diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/PlainHttpConnection.java b/src/java.net.http/share/classes/jdk/internal/net/http/PlainHttpConnection.java index e705aae72a1..45d242df671 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/PlainHttpConnection.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/PlainHttpConnection.java @@ -311,20 +311,20 @@ class PlainHttpConnection extends HttpConnection { var connectTimerEvent = this.connectTimerEvent; if (connectTimerEvent != null) client().cancelTimer(connectTimerEvent); - if (Log.channel()) { - Log.logChannel("Closing channel: " + chan); - } - try { - tube.signalClosed(errorRef.get()); - chan.close(); - } finally { - client().connectionClosed(this); - } + } finally { + stateLock.unlock(); + } + if (Log.channel()) { + Log.logChannel("Closing channel: " + chan); + } + try { + tube.signalClosed(errorRef.get()); + chan.close(); } catch (IOException e) { debug.log("Closing resulted in " + e); Log.logTrace("Closing resulted in " + e); } finally { - stateLock.unlock(); + client().connectionClosed(this); } } diff --git a/test/jdk/java/net/httpclient/PlainConnectionLockTest.java b/test/jdk/java/net/httpclient/PlainConnectionLockTest.java new file mode 100644 index 00000000000..3205f87111a --- /dev/null +++ b/test/jdk/java/net/httpclient/PlainConnectionLockTest.java @@ -0,0 +1,383 @@ +/* + * Copyright (c) 2025, 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.io.IOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.net.http.HttpResponse.BodyHandlers; +import java.time.Duration; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.concurrent.CancellationException; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; +import javax.net.ssl.SSLContext; + +import com.sun.net.httpserver.HttpServer; +import com.sun.net.httpserver.HttpsServer; +import jdk.httpclient.test.lib.common.HttpServerAdapters; +import jdk.httpclient.test.lib.common.TestServerConfigurator; +import jdk.test.lib.net.SimpleSSLContext; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Assertions; + +import static java.net.http.HttpClient.Builder.NO_PROXY; +import static java.net.http.HttpClient.Version.HTTP_1_1; + +/* + * @test id=default + * @bug 8372198 + * @requires os.family != "windows" + * @summary Attempt to check that no deadlock occurs when + * connections are closed by the ConnectionPool. + * @library /test/lib /test/jdk/java/net/httpclient/lib + * @build jdk.test.lib.net.SimpleSSLContext + * jdk.httpclient.test.lib.common.HttpServerAdapters + * @run junit/othervm + * -Djdk.httpclient.HttpClient.log=errors + * -Djdk.httpclient.connectionPoolSize=1 + * ${test.main.class} + */ +/* + * @test id=windows + * @bug 8372198 + * @requires os.family == "windows" + * @summary Attempt to check that no deadlock occurs when + * connections are closed by the ConnectionPool. + * @library /test/lib /test/jdk/java/net/httpclient/lib + * @build jdk.test.lib.net.SimpleSSLContext + * jdk.httpclient.test.lib.common.HttpServerAdapters + * @comment A special jtreg id for windows allows for experimentation + * with different configuration - for instance, specifying + * -Djdk.internal.httpclient.tcp.selector.useVirtualThreads= + * on the run command line, or specifying a different request count + * with -DrequestCount=. + * On windows, it seems important to set the backlog for the HTTP/1.1 + * server to at least the number of concurrent request. This is done + * in the beforeTest() method. + * If the test fails waiting for avalaible permits, due to system limitations, + * even with the backlog correctly configure, adding a margin to the backlog + * or reducing the requestCount could be envisaged. + * @run junit/othervm + * -Djdk.httpclient.HttpClient.log=errors + * -Djdk.httpclient.connectionPoolSize=1 + * ${test.main.class} + */ + +// -Djava.security.debug=all +class PlainConnectionLockTest implements HttpServerAdapters { + + private SSLContext sslContext; + private HttpTestServer http1Server; + private HttpTestServer https1Server; + private String http1URI; + private String https1URI; + private ExecutorService serverExecutor; + private Semaphore responseSemaphore; + private Semaphore requestSemaphore; + private boolean successfulCompletion; + private static final int MANY = Integer.getInteger("requestCount", 100); + + static { + HttpServerAdapters.enableServerLogging(); + } + + private boolean blockResponse(Semaphore request, Semaphore response) { + try { + request.release(); + response.acquire(); + return true; + } catch (InterruptedException x) { + Thread.currentThread().interrupt(); // Restore the interrupt + return false; + } + } + + + @BeforeEach + synchronized void beforeTest() throws Exception { + requestSemaphore = new Semaphore(0); + responseSemaphore = new Semaphore(0); + successfulCompletion = false; + sslContext = new SimpleSSLContext().get(); + if (sslContext == null) { + throw new AssertionError("Unexpected null sslContext"); + } + serverExecutor = Executors.newThreadPerTaskExecutor( + Thread.ofVirtual().name("Http1Server", 0).factory()); + + // On Windows, sending 100 concurrent requests may + // fail if the server's connection backlog is less than 100. + // The default backlog is 50. Just make sure the backlog is + // big enough. + int backlog = Math.max(MANY, 50); + + // create a https server for HTTP/1.1 + var loopback = InetAddress.getLoopbackAddress(); + var wrappedHttps1Server = HttpsServer.create(new InetSocketAddress(loopback, 0), backlog); + wrappedHttps1Server.setHttpsConfigurator(new TestServerConfigurator(loopback, sslContext)); + https1Server = HttpTestServer.of(wrappedHttps1Server, serverExecutor); + https1Server.addHandler((exchange) -> { + if (blockResponse(requestSemaphore, responseSemaphore)) { + exchange.sendResponseHeaders(200, 0); + } else { + exchange.sendResponseHeaders(500, 0); + } + }, "/PlainConnectionLockTest/"); + https1Server.start(); + System.out.println("HTTPS Server started at " + https1Server.getAddress()); + https1URI = "https://" + https1Server.serverAuthority() + "/PlainConnectionLockTest/https1"; + + // create a plain http server for HTTP/1.1 + var wrappedHttp1Server = HttpServer.create(new InetSocketAddress(loopback, 0), backlog); + http1Server = HttpTestServer.of(wrappedHttp1Server, serverExecutor); + http1Server.addHandler((exchange) -> { + if (blockResponse(requestSemaphore, responseSemaphore)) { + exchange.sendResponseHeaders(200, 0); + } else { + exchange.sendResponseHeaders(500, 0); + } + }, "/PlainConnectionLockTest/"); + http1Server.start(); + System.out.println("HTTP Server started at " + http1Server.getAddress()); + http1URI = "http://" + http1Server.serverAuthority() + "/PlainConnectionLockTest/http1"; + } + + @AfterEach + synchronized void afterTest() throws Exception { + if (http1Server != null) { + System.out.println("Stopping HTTP server " + http1Server.getAddress()); + http1Server.stop(); + } + if (https1Server != null) { + System.out.println("Stopping HTTPS server " + https1Server.getAddress()); + https1Server.stop(); + } + if (serverExecutor != null) { + System.out.println("Closing server executor"); + if (successfulCompletion) { + serverExecutor.close(); + } else { + // server handlers may be wedged. + serverExecutor.shutdownNow(); + } + } + requestSemaphore = null; + responseSemaphore = null; + serverExecutor = null; + http1Server = null; + https1Server = null; + http1URI = null; + https1URI = null; + System.out.println("done\n"); + } + + @Test + void sendManyHttpRequestsNoShutdown() throws Exception { + try { + sendManyRequests(http1URI, MANY, false); + } catch (Throwable t) { + t.printStackTrace(System.out); + throw t; + } + } + + @Test + void sendManyHttpRequestsShutdownNow() throws Exception { + try { + sendManyRequests(http1URI, MANY, true); + } catch (Throwable t) { + t.printStackTrace(System.out); + throw t; + } + } + + @Test + void sendManyHttpsRequestsNoShutdown() throws Exception { + try { + sendManyRequests(https1URI, MANY, false); + } catch (Throwable t) { + t.printStackTrace(System.out); + throw t; + } + } + + @Test + void sendManyHttpsRequestsShutdownNow() throws Exception { + try { + sendManyRequests(https1URI, MANY, true); + } catch (Throwable t) { + t.printStackTrace(System.out); + throw t; + } + } + + private static void throwCause(CompletionException x) throws Exception { + var cause = x.getCause(); + if (cause instanceof Exception ex) throw ex; + if (cause instanceof Error err) throw err; + throw x; + } + + static final long start = System.nanoTime(); + public static String now() { + long now = System.nanoTime() - start; + long secs = now / 1000_000_000; + long mill = (now % 1000_000_000) / 1000_000; + long nan = now % 1000_000; + return String.format("[%d s, %d ms, %d ns] ", secs, mill, nan); + } + + static Throwable getCause(Throwable exception) { + if (exception instanceof IOException) return exception; + if (exception instanceof CancellationException) return exception; + if (exception instanceof CompletionException) return getCause(exception.getCause()); + if (exception instanceof ExecutionException) return getCause(exception.getCause()); + return exception; + } + + private synchronized void sendManyRequests(final String requestURI, final int many, boolean shutdown) throws Exception { + System.out.println("\n%sSending %s requests to %s, shutdown=%s\n".formatted(now(), many, requestURI, shutdown)); + System.err.println("\n%sSending %s requests to %s, shutdown=%s\n".formatted(now(), many, requestURI, shutdown)); + assert many > 0; + try (final HttpClient client = HttpClient.newBuilder() + .proxy(NO_PROXY) + .sslContext(sslContext).build()) { + List>> futures = new ArrayList<>(); + final HttpRequest.Builder reqBuilder = HttpRequest.newBuilder().version(HTTP_1_1); + for (int i = 0; i < many; i++) { + // GET + final URI reqURI = new URI(requestURI + "?i=" + i); + final HttpRequest req = reqBuilder.copy().uri(reqURI).GET().build(); + System.out.println(now() + "Issuing request: " + req); + var cf = client.sendAsync(req, BodyHandlers.ofString()); + futures.add(cf); + } + System.out.printf("\n%sWaiting for %s requests to be handled on the server%n", now(), many); + + int count = 0; + // wait for all exchanges to be handled + while (!requestSemaphore.tryAcquire(many, 5, TimeUnit.SECONDS)) { + count++; + System.out.printf("%sFailed to obtain %s permits after %ss - only %s available%n", + now(), many, (count * 5), requestSemaphore.availablePermits()); + for (var cf : futures) { + if (cf.isDone() || cf.isCancelled()) { + System.out.printf("%sFound some completed cf: %s%n", now(), cf); + if (cf.isCancelled()) { + System.out.printf("%scf is cancelled: %s%n", now(), cf); + client.shutdownNow(); // make sure HttpCient::close won't block waiting for server + var error = new AssertionError(now() + "A request cf was cancelled" + cf); + System.out.printf("%s throwing: %s%n", now(), error); + throw error; + } + if (cf.isCompletedExceptionally()) { + System.out.printf("%scf is completed exceptionally: %s%n", now(), cf); + var exception = getCause(cf.exceptionNow()); + System.out.printf("%sexception is: %s%n", now(), exception); + client.shutdownNow(); // make sure HttpCient::close won't block waiting for server + exception.printStackTrace(System.out); + var error = new AssertionError(now() + "A request failed prematurely", exception); + System.out.printf("%s throwing: %s%n", now(), error); + throw error; + } + System.out.printf("%scf is completed prematurely: %s%n", now(), cf); + client.shutdownNow(); // make sure HttpCient::close won't block waiting for server + var error = new AssertionError(now() + "A request succeeded prematurely: " + cf.join()); + System.out.printf("%s throwing: %s%n", now(), error); + throw error; + } + } + System.out.printf("%sCouldn't acquire %s permits, only %s available - keep on waiting%n", + now(), many, requestSemaphore.availablePermits()); + } + + System.out.println(now() + "All requests reached the server: releasing one response"); + // allow one request to proceed + responseSemaphore.release(); + try { + // wait for the first response. + System.out.println(now() + "Waiting for the first response"); + CompletableFuture.anyOf(futures.toArray(new CompletableFuture[0])).join(); + System.out.println(now() + "Got first response: " + futures.stream().filter(CompletableFuture::isDone) + .findFirst().map(CompletableFuture::join)); + if (shutdown) { + System.out.println(now() + "Calling HttpClient::shutdownNow"); + client.shutdownNow(); + client.awaitTermination(Duration.ofSeconds(1)); + } + } finally { + System.out.printf("%s Releasing %s remaining responses%n", now(), many - 1); + // now release the others. + responseSemaphore.release(many - 1); + } + + // wait for all responses + System.out.printf("%sWaiting for all %s responses to complete%n", now(), many); + CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).exceptionally(t -> null).join(); + + // check + System.out.printf("%sAll %s responses completed. Checking...%n%n", now(), many); + Set conns = new HashSet<>(); + int exceptionCount = 0; + int success = 0; + for (var respCF : futures) { + try { + var resp = respCF.join(); + Assertions.assertEquals(200, resp.statusCode(), + now() + "unexpected response code for GET request: " + resp); + Assertions.assertTrue(conns.add(resp.connectionLabel().get()), + now() + "unexepected reuse of connection: " + + resp.connectionLabel().get() + " found in " + conns); + success++; + } catch (CompletionException x) { + if (shutdown) exceptionCount++; + else throwCause(x); + } + } + if (shutdown) { + if (success == 0) { + throw new AssertionError(("%s%s: shutdownNow=%s: Expected at least one response, " + + "got success=%s, exceptions=%s").formatted(now(), requestURI, shutdown, success, exceptionCount)); + } + } + System.out.println("%sSuccess: %s: shutdownNow:%s, success=%s, exceptions:%s\n" + .formatted(now(), requestURI, shutdown, success, exceptionCount)); + successfulCompletion = true; + } + } +} From f1d90b8b25b78b15dc6529a5a6e45633eb250286 Mon Sep 17 00:00:00 2001 From: James Yuzawa Date: Thu, 27 Nov 2025 20:26:16 +0000 Subject: [PATCH 047/706] 8372134: ThreadLocalRandom no longer overrides nextGaussian Reviewed-by: alanb, rgiulietti, vklang --- .../util/concurrent/ThreadLocalRandom.java | 26 ++++++++++++------- .../java/util/random/RandomGenerator.java | 3 +-- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/src/java.base/share/classes/java/util/concurrent/ThreadLocalRandom.java b/src/java.base/share/classes/java/util/concurrent/ThreadLocalRandom.java index 3713d616a3a..deed7f018c3 100644 --- a/src/java.base/share/classes/java/util/concurrent/ThreadLocalRandom.java +++ b/src/java.base/share/classes/java/util/concurrent/ThreadLocalRandom.java @@ -128,11 +128,6 @@ public final class ThreadLocalRandom extends Random { * Implementations of non-core methods are mostly the same as in * SplittableRandom, that were in part derived from a previous * version of this class. - * - * This implementation of ThreadLocalRandom overrides the - * definition of the nextGaussian() method in the class Random, - * and instead uses the ziggurat-based algorithm that is the - * default for the RandomGenerator interface. */ private static int mix32(long z) { @@ -499,6 +494,23 @@ public final class ThreadLocalRandom extends Random { return super.nextLong(origin, bound); } + /** + * Returns a {@code double} value pseudorandomly chosen from a Gaussian + * (normal) distribution whose mean is 0 and whose standard deviation is 1. + * + * @return a {@code double} value pseudorandomly chosen from a + * Gaussian distribution + * + * @implNote This implementation invokes the default implementation of + * {@link java.util.random.RandomGenerator#nextGaussian()}, + * and so it uses McFarland's fast modified ziggurat algorithm + * rather than the polar method described in the superclass. + */ + @Override + public double nextGaussian() { + return RandomSupport.computeNextGaussian(this); + } + /** * {@inheritDoc} */ @@ -510,7 +522,6 @@ public final class ThreadLocalRandom extends Random { /** * {@inheritDoc} * @throws IllegalArgumentException {@inheritDoc} - * @implNote {@inheritDoc} * * @since 17 */ @@ -522,7 +533,6 @@ public final class ThreadLocalRandom extends Random { /** * {@inheritDoc} * @throws IllegalArgumentException {@inheritDoc} - * @implNote {@inheritDoc} * * @since 17 */ @@ -542,7 +552,6 @@ public final class ThreadLocalRandom extends Random { /** * {@inheritDoc} * @throws IllegalArgumentException {@inheritDoc} - * @implNote {@inheritDoc} */ @Override public double nextDouble(double bound) { @@ -552,7 +561,6 @@ public final class ThreadLocalRandom extends Random { /** * {@inheritDoc} * @throws IllegalArgumentException {@inheritDoc} - * @implNote {@inheritDoc} */ @Override public double nextDouble(double origin, double bound) { diff --git a/src/java.base/share/classes/java/util/random/RandomGenerator.java b/src/java.base/share/classes/java/util/random/RandomGenerator.java index e019e073a2d..2195774e591 100644 --- a/src/java.base/share/classes/java/util/random/RandomGenerator.java +++ b/src/java.base/share/classes/java/util/random/RandomGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, 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 @@ -917,7 +917,6 @@ public interface RandomGenerator { * a discrete distribution also plays a role. */ default double nextGaussian() { - // See Knuth, TAOCP, Vol. 2, 3rd edition, Section 3.4.1 Algorithm C. return RandomSupport.computeNextGaussian(this); } From 195b36f90b789b64f4a0fc867c620935d609a455 Mon Sep 17 00:00:00 2001 From: David Holmes Date: Thu, 27 Nov 2025 23:05:51 +0000 Subject: [PATCH 048/706] 8372702: sun/security/pkcs11/tls/fips/FipsModeTLS.java does not compile after JDK-8367096 Reviewed-by: djelinski --- test/jdk/sun/security/pkcs11/tls/fips/FipsModeTLS.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/test/jdk/sun/security/pkcs11/tls/fips/FipsModeTLS.java b/test/jdk/sun/security/pkcs11/tls/fips/FipsModeTLS.java index d0b1407422a..8799f2305bf 100644 --- a/test/jdk/sun/security/pkcs11/tls/fips/FipsModeTLS.java +++ b/test/jdk/sun/security/pkcs11/tls/fips/FipsModeTLS.java @@ -456,9 +456,8 @@ public final class FipsModeTLS extends SecmodTest { // 2. SUN (to handle X.509 certificates) // 3. SunJSSE (for a TLS engine) - if (initSecmod() == false) { - return; - } + initSecmod(); + String configName = BASE + SEP + "nss.cfg"; sunPKCS11NSSProvider = getSunPKCS11(configName); System.out.println("SunPKCS11 provider: " + sunPKCS11NSSProvider); From 0c6d1b9c8bfd7f4e39a6621c7a8f7bdcd044a05f Mon Sep 17 00:00:00 2001 From: Sergey Bylokhov Date: Fri, 28 Nov 2025 06:39:03 +0000 Subject: [PATCH 049/706] 8371759: Add missing @Override annotations in com.sun.imageio package Reviewed-by: tr, jdv, azvegint --- .../plugins/bmp/BMPImageReaderSpi.java | 6 ++- .../plugins/bmp/BMPImageWriterSpi.java | 6 ++- .../sun/imageio/plugins/bmp/BMPMetadata.java | 11 +++++- .../plugins/bmp/BMPMetadataFormat.java | 3 +- .../bmp/BMPMetadataFormatResources.java | 3 +- .../plugins/common/BogusColorSpace.java | 6 ++- .../plugins/common/InputStreamAdapter.java | 4 +- .../plugins/common/SimpleCMYKColorSpace.java | 8 +++- .../plugins/common/SimpleRenderedImage.java | 22 ++++++++++- .../common/SingleTileRenderedImage.java | 3 +- .../common/StandardMetadataFormat.java | 3 +- .../StandardMetadataFormatResources.java | 3 +- .../plugins/common/SubImageInputStream.java | 6 ++- .../imageio/plugins/gif/GIFImageMetadata.java | 14 ++++++- .../plugins/gif/GIFImageMetadataFormat.java | 3 +- .../gif/GIFImageMetadataFormatResources.java | 3 +- .../plugins/gif/GIFImageReaderSpi.java | 5 ++- .../plugins/gif/GIFImageWriterSpi.java | 5 ++- .../sun/imageio/plugins/gif/GIFMetadata.java | 3 +- .../plugins/gif/GIFStreamMetadata.java | 15 ++++++- .../plugins/gif/GIFStreamMetadataFormat.java | 3 +- .../gif/GIFStreamMetadataFormatResources.java | 3 +- .../plugins/gif/GIFWritableImageMetadata.java | 7 +++- .../gif/GIFWritableStreamMetadata.java | 8 +++- .../plugins/jpeg/AdobeMarkerSegment.java | 5 ++- .../plugins/jpeg/COMMarkerSegment.java | 5 ++- .../plugins/jpeg/DHTMarkerSegment.java | 7 +++- .../plugins/jpeg/DQTMarkerSegment.java | 7 +++- .../plugins/jpeg/DRIMarkerSegment.java | 5 ++- .../plugins/jpeg/JFIFMarkerSegment.java | 39 +++++++++++++++++++ .../plugins/jpeg/JPEGImageMetadataFormat.java | 3 +- .../JPEGImageMetadataFormatResources.java | 3 +- .../jpeg/JPEGImageReaderResources.java | 3 +- .../plugins/jpeg/JPEGImageReaderSpi.java | 5 ++- .../jpeg/JPEGImageWriterResources.java | 3 +- .../plugins/jpeg/JPEGImageWriterSpi.java | 6 ++- .../imageio/plugins/jpeg/JPEGMetadata.java | 11 ++++++ .../plugins/jpeg/JPEGMetadataFormat.java | 3 +- .../JPEGStreamMetadataFormatResources.java | 3 +- .../imageio/plugins/jpeg/MarkerSegment.java | 1 + .../plugins/jpeg/SOFMarkerSegment.java | 7 +++- .../plugins/jpeg/SOSMarkerSegment.java | 7 +++- .../plugins/png/PNGImageReaderSpi.java | 5 ++- .../plugins/png/PNGImageWriterSpi.java | 5 ++- .../sun/imageio/plugins/png/PNGMetadata.java | 14 ++++++- .../plugins/png/PNGMetadataFormat.java | 3 +- .../png/PNGMetadataFormatResources.java | 3 +- .../plugins/tiff/TIFFBaseJPEGCompressor.java | 3 +- .../tiff/TIFFCIELabColorConverter.java | 4 +- .../plugins/tiff/TIFFDeflateDecompressor.java | 3 +- .../imageio/plugins/tiff/TIFFDeflater.java | 3 +- .../plugins/tiff/TIFFExifJPEGCompressor.java | 3 +- .../plugins/tiff/TIFFFaxCompressor.java | 3 +- .../plugins/tiff/TIFFFaxDecompressor.java | 4 +- .../imageio/plugins/tiff/TIFFFieldNode.java | 13 ++++++- .../plugins/tiff/TIFFImageMetadata.java | 13 ++++++- .../plugins/tiff/TIFFImageMetadataFormat.java | 3 +- .../TIFFImageMetadataFormatResources.java | 3 +- .../plugins/tiff/TIFFImageReaderSpi.java | 6 ++- .../plugins/tiff/TIFFImageWriterSpi.java | 6 ++- .../plugins/tiff/TIFFJPEGCompressor.java | 4 +- .../plugins/tiff/TIFFJPEGDecompressor.java | 4 +- .../plugins/tiff/TIFFLSBCompressor.java | 3 +- .../plugins/tiff/TIFFLSBDecompressor.java | 3 +- .../plugins/tiff/TIFFLZWCompressor.java | 4 +- .../plugins/tiff/TIFFLZWDecompressor.java | 3 +- .../plugins/tiff/TIFFMetadataFormat.java | 27 ++++++++++++- .../plugins/tiff/TIFFNullCompressor.java | 3 +- .../plugins/tiff/TIFFNullDecompressor.java | 5 ++- .../plugins/tiff/TIFFOldJPEGDecompressor.java | 3 +- .../plugins/tiff/TIFFPackBitsCompressor.java | 3 +- .../tiff/TIFFPackBitsDecompressor.java | 3 +- .../plugins/tiff/TIFFRLECompressor.java | 3 +- .../plugins/tiff/TIFFRenderedImage.java | 23 ++++++++++- .../plugins/tiff/TIFFStreamMetadata.java | 6 ++- .../tiff/TIFFStreamMetadataFormat.java | 3 +- .../TIFFStreamMetadataFormatResources.java | 3 +- .../plugins/tiff/TIFFT4Compressor.java | 4 +- .../plugins/tiff/TIFFT6Compressor.java | 3 +- .../plugins/tiff/TIFFYCbCrColorConverter.java | 4 +- .../plugins/tiff/TIFFYCbCrDecompressor.java | 36 ++++++++++++++++- .../plugins/wbmp/WBMPImageReaderSpi.java | 6 ++- .../plugins/wbmp/WBMPImageWriterSpi.java | 6 ++- .../imageio/plugins/wbmp/WBMPMetadata.java | 9 ++++- .../plugins/wbmp/WBMPMetadataFormat.java | 3 +- .../imageio/spi/FileImageInputStreamSpi.java | 4 +- .../imageio/spi/FileImageOutputStreamSpi.java | 4 +- .../spi/InputStreamImageInputStreamSpi.java | 6 ++- .../spi/OutputStreamImageOutputStreamSpi.java | 6 ++- .../imageio/spi/RAFImageInputStreamSpi.java | 4 +- .../imageio/spi/RAFImageOutputStreamSpi.java | 4 +- .../stream/CloseableDisposerRecord.java | 3 +- .../com/sun/imageio/stream/StreamCloser.java | 3 +- 93 files changed, 491 insertions(+), 90 deletions(-) diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPImageReaderSpi.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPImageReaderSpi.java index a3098bd9684..63cc1464460 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPImageReaderSpi.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPImageReaderSpi.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, 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 @@ -61,6 +61,7 @@ public class BMPImageReaderSpi extends ImageReaderSpi { null, null); } + @Override public void onRegistration(ServiceRegistry registry, Class category) { if (registered) { @@ -69,10 +70,12 @@ public class BMPImageReaderSpi extends ImageReaderSpi { registered = true; } + @Override public String getDescription(Locale locale) { return "Standard BMP Image Reader"; } + @Override public boolean canDecodeInput(Object source) throws IOException { if (!(source instanceof ImageInputStream)) { return false; @@ -87,6 +90,7 @@ public class BMPImageReaderSpi extends ImageReaderSpi { return full && (b[0] == 0x42) && (b[1] == 0x4d); } + @Override public ImageReader createReaderInstance(Object extension) throws IIOException { return new BMPImageReader(this); diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPImageWriterSpi.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPImageWriterSpi.java index ae6a7f65a3b..736a1c2194e 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPImageWriterSpi.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPImageWriterSpi.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, 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 @@ -66,10 +66,12 @@ public class BMPImageWriterSpi extends ImageWriterSpi { null, null); } + @Override public String getDescription(Locale locale) { return "Standard BMP Image Writer"; } + @Override public void onRegistration(ServiceRegistry registry, Class category) { if (registered) { @@ -79,6 +81,7 @@ public class BMPImageWriterSpi extends ImageWriterSpi { registered = true; } + @Override public boolean canEncodeImage(ImageTypeSpecifier type) { int dataType= type.getSampleModel().getDataType(); if (dataType < DataBuffer.TYPE_BYTE || dataType > DataBuffer.TYPE_INT) @@ -99,6 +102,7 @@ public class BMPImageWriterSpi extends ImageWriterSpi { return true; } + @Override public ImageWriter createWriterInstance(Object extension) throws IIOException { return new BMPImageWriter(this); diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPMetadata.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPMetadata.java index 5e5a4a52d35..48d3bb12f1c 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPMetadata.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPMetadata.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, 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 @@ -94,10 +94,12 @@ public class BMPMetadata extends IIOMetadata implements BMPConstants { null, null); } + @Override public boolean isReadOnly() { return true; } + @Override public Node getAsTree(String formatName) { if (formatName.equals(nativeMetadataFormatName)) { return getNativeTree(); @@ -177,6 +179,7 @@ public class BMPMetadata extends IIOMetadata implements BMPConstants { } // Standard tree node methods + @Override protected IIOMetadataNode getStandardChromaNode() { if ((palette != null) && (paletteSize > 0)) { @@ -202,6 +205,7 @@ public class BMPMetadata extends IIOMetadata implements BMPConstants { return null; } + @Override protected IIOMetadataNode getStandardCompressionNode() { IIOMetadataNode node = new IIOMetadataNode("Compression"); @@ -212,6 +216,7 @@ public class BMPMetadata extends IIOMetadata implements BMPConstants { return node; } + @Override protected IIOMetadataNode getStandardDataNode() { IIOMetadataNode node = new IIOMetadataNode("Data"); @@ -230,6 +235,7 @@ public class BMPMetadata extends IIOMetadata implements BMPConstants { return node; } + @Override protected IIOMetadataNode getStandardDimensionNode() { if (yPixelsPerMeter > 0.0F && xPixelsPerMeter > 0.0F) { IIOMetadataNode node = new IIOMetadataNode("Dimension"); @@ -251,14 +257,17 @@ public class BMPMetadata extends IIOMetadata implements BMPConstants { return null; } + @Override public void setFromTree(String formatName, Node root) { throw new IllegalStateException(I18N.getString("BMPMetadata1")); } + @Override public void mergeTree(String formatName, Node root) { throw new IllegalStateException(I18N.getString("BMPMetadata1")); } + @Override public void reset() { throw new IllegalStateException(I18N.getString("BMPMetadata1")); } diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPMetadataFormat.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPMetadataFormat.java index b9ea0ee0fe3..277169a34e0 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPMetadataFormat.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPMetadataFormat.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, 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 @@ -194,6 +194,7 @@ public class BMPMetadataFormat extends IIOMetadataFormatImpl { DATATYPE_STRING, true, null); } + @Override public boolean canNodeAppear(String elementName, ImageTypeSpecifier imageType) { return true; diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPMetadataFormatResources.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPMetadataFormatResources.java index 1f2f444acd7..4d6c4fe49ec 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPMetadataFormatResources.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPMetadataFormatResources.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, 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,6 +33,7 @@ public class BMPMetadataFormatResources extends ListResourceBundle { public BMPMetadataFormatResources() {} + @Override protected Object[][] getContents() { return new Object[][] { diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/common/BogusColorSpace.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/common/BogusColorSpace.java index 5a064f4f4c5..107ee313b70 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/common/BogusColorSpace.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/common/BogusColorSpace.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, 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 @@ -79,6 +79,7 @@ public class BogusColorSpace extends ColorSpace { // specified behavior of the methods vis-a-vis exceptions. // + @Override public float[] toRGB(float[] colorvalue) { if(colorvalue.length < getNumComponents()) { throw new ArrayIndexOutOfBoundsException @@ -93,6 +94,7 @@ public class BogusColorSpace extends ColorSpace { return rgbvalue; } + @Override public float[] fromRGB(float[] rgbvalue) { if(rgbvalue.length < 3) { throw new ArrayIndexOutOfBoundsException @@ -107,6 +109,7 @@ public class BogusColorSpace extends ColorSpace { return colorvalue; } + @Override public float[] toCIEXYZ(float[] colorvalue) { if(colorvalue.length < getNumComponents()) { throw new ArrayIndexOutOfBoundsException @@ -121,6 +124,7 @@ public class BogusColorSpace extends ColorSpace { return xyzvalue; } + @Override public float[] fromCIEXYZ(float[] xyzvalue) { if(xyzvalue.length < 3) { throw new ArrayIndexOutOfBoundsException diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/common/InputStreamAdapter.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/common/InputStreamAdapter.java index 1b63a54d8ff..b11ffeb6287 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/common/InputStreamAdapter.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/common/InputStreamAdapter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, 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,10 +39,12 @@ public class InputStreamAdapter extends InputStream { this.stream = stream; } + @Override public int read() throws IOException { return stream.read(); } + @Override public int read(byte[] b, int off, int len) throws IOException { return stream.read(b, off, len); } diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/common/SimpleCMYKColorSpace.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/common/SimpleCMYKColorSpace.java index a5c283e6c9c..1662d09984d 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/common/SimpleCMYKColorSpace.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/common/SimpleCMYKColorSpace.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -58,14 +58,17 @@ public final class SimpleCMYKColorSpace extends ColorSpace { csRGB = ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB); } + @Override public boolean equals(Object o) { return o instanceof SimpleCMYKColorSpace; } + @Override public int hashCode() { return System.identityHashCode(theInstance); } + @Override public float[] toRGB(float[] colorvalue) { float C = colorvalue[0]; float M = colorvalue[1]; @@ -97,6 +100,7 @@ public final class SimpleCMYKColorSpace extends ColorSpace { return rgbvalue; } + @Override public float[] fromRGB(float[] rgbvalue) { // Convert from sRGB to linear RGB. for (int i = 0; i < 3; i++) { @@ -128,10 +132,12 @@ public final class SimpleCMYKColorSpace extends ColorSpace { return new float[] {C, M, Y, K}; } + @Override public float[] toCIEXYZ(float[] colorvalue) { return csRGB.toCIEXYZ(toRGB(colorvalue)); } + @Override public float[] fromCIEXYZ(float[] xyzvalue) { return fromRGB(csRGB.fromCIEXYZ(xyzvalue)); } diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/common/SimpleRenderedImage.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/common/SimpleRenderedImage.java index 1d8c850b4a9..f598aeb06a1 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/common/SimpleRenderedImage.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/common/SimpleRenderedImage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -74,6 +74,7 @@ public abstract class SimpleRenderedImage implements RenderedImage { protected Hashtable properties = new Hashtable(); /** Returns the X coordinate of the leftmost column of the image. */ + @Override public int getMinX() { return minX; } @@ -89,6 +90,7 @@ public abstract class SimpleRenderedImage implements RenderedImage { } /** Returns the X coordinate of the uppermost row of the image. */ + @Override public int getMinY() { return minY; } @@ -104,11 +106,13 @@ public abstract class SimpleRenderedImage implements RenderedImage { } /** Returns the width of the image. */ + @Override public int getWidth() { return width; } /** Returns the height of the image. */ + @Override public int getHeight() { return height; } @@ -119,11 +123,13 @@ public abstract class SimpleRenderedImage implements RenderedImage { } /** Returns the width of a tile. */ + @Override public int getTileWidth() { return tileWidth; } /** Returns the height of a tile. */ + @Override public int getTileHeight() { return tileHeight; } @@ -131,6 +137,7 @@ public abstract class SimpleRenderedImage implements RenderedImage { /** * Returns the X coordinate of the upper-left pixel of tile (0, 0). */ + @Override public int getTileGridXOffset() { return tileGridXOffset; } @@ -138,6 +145,7 @@ public abstract class SimpleRenderedImage implements RenderedImage { /** * Returns the Y coordinate of the upper-left pixel of tile (0, 0). */ + @Override public int getTileGridYOffset() { return tileGridYOffset; } @@ -147,6 +155,7 @@ public abstract class SimpleRenderedImage implements RenderedImage { * getMinTileX() is implemented in terms of getMinX() * and so does not need to be implemented by subclasses. */ + @Override public int getMinTileX() { return XToTileX(getMinX()); } @@ -166,6 +175,7 @@ public abstract class SimpleRenderedImage implements RenderedImage { * of getMinTileX() and getMaxTileX() and so does not need to be * implemented by subclasses. */ + @Override public int getNumXTiles() { return getMaxTileX() - getMinTileX() + 1; } @@ -175,6 +185,7 @@ public abstract class SimpleRenderedImage implements RenderedImage { * is implemented in terms of getMinY() and so does not need to be * implemented by subclasses. */ + @Override public int getMinTileY() { return YToTileY(getMinY()); } @@ -194,16 +205,19 @@ public abstract class SimpleRenderedImage implements RenderedImage { * of getMinTileY() and getMaxTileY() and so does not need to be * implemented by subclasses. */ + @Override public int getNumYTiles() { return getMaxTileY() - getMinTileY() + 1; } /** Returns the SampleModel of the image. */ + @Override public SampleModel getSampleModel() { return sampleModel; } /** Returns the ColorModel of the image. */ + @Override public ColorModel getColorModel() { return colorModel; } @@ -218,6 +232,7 @@ public abstract class SimpleRenderedImage implements RenderedImage { * Object, or the value * java.awt.Image.UndefinedProperty. */ + @Override public Object getProperty(String name) { name = name.toLowerCase(); Object value = properties.get(name); @@ -232,6 +247,7 @@ public abstract class SimpleRenderedImage implements RenderedImage { * @return an array of Strings representing valid * property names. */ + @Override public String[] getPropertyNames() { String[] names = null; @@ -379,6 +395,7 @@ public abstract class SimpleRenderedImage implements RenderedImage { return ty*tileHeight + tileGridYOffset; } + @Override public Vector getSources() { return null; } @@ -399,6 +416,7 @@ public abstract class SimpleRenderedImage implements RenderedImage { * * @return a Raster containing a copy of this image's data. */ + @Override public Raster getData() { Rectangle rect = new Rectangle(getMinX(), getMinY(), getWidth(), getHeight()); @@ -422,6 +440,7 @@ public abstract class SimpleRenderedImage implements RenderedImage { * * @param bounds the region of the RenderedImage to be returned. */ + @Override public Raster getData(Rectangle bounds) { // Get the image bounds. Rectangle imageBounds = getBounds(); @@ -511,6 +530,7 @@ public abstract class SimpleRenderedImage implements RenderedImage { * @return a reference to the supplied WritableRaster, or to a * new WritableRaster if the supplied one was null. */ + @Override public WritableRaster copyData(WritableRaster dest) { // Get the image bounds. Rectangle imageBounds = getBounds(); diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/common/SingleTileRenderedImage.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/common/SingleTileRenderedImage.java index 0cbdefa9127..315270e5916 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/common/SingleTileRenderedImage.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/common/SingleTileRenderedImage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -58,6 +58,7 @@ public class SingleTileRenderedImage extends SimpleRenderedImage { /** * Returns the image's Raster as tile (0, 0). */ + @Override public Raster getTile(int tileX, int tileY) { if (tileX != 0 || tileY != 0) { throw new IllegalArgumentException("tileX != 0 || tileY != 0"); diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/common/StandardMetadataFormat.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/common/StandardMetadataFormat.java index d880c507cba..05fa72f24ae 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/common/StandardMetadataFormat.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/common/StandardMetadataFormat.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, 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 @@ -492,6 +492,7 @@ public class StandardMetadataFormat extends IIOMetadataFormatImpl { null); } + @Override public boolean canNodeAppear(String elementName, ImageTypeSpecifier imageType) { return true; diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/common/StandardMetadataFormatResources.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/common/StandardMetadataFormatResources.java index 4a94450d003..20e81dd76fa 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/common/StandardMetadataFormatResources.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/common/StandardMetadataFormatResources.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, 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 @@ public class StandardMetadataFormatResources extends ListResourceBundle { public StandardMetadataFormatResources() {} + @Override protected Object[][] getContents() { return new Object[][] { diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/common/SubImageInputStream.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/common/SubImageInputStream.java index 5d6bd401dc6..487f678c1eb 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/common/SubImageInputStream.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/common/SubImageInputStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, 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,6 +43,7 @@ public final class SubImageInputStream extends ImageInputStreamImpl { this.startingLength = this.length = length; } + @Override public int read() throws IOException { if (length == 0) { // Local EOF return -1; @@ -52,6 +53,7 @@ public final class SubImageInputStream extends ImageInputStreamImpl { } } + @Override public int read(byte[] b, int off, int len) throws IOException { if (length == 0) { // Local EOF return -1; @@ -63,10 +65,12 @@ public final class SubImageInputStream extends ImageInputStreamImpl { return bytes; } + @Override public long length() { return startingLength; } + @Override public void seek(long pos) throws IOException { stream.seek(pos - startingPos); streamPos = pos; diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageMetadata.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageMetadata.java index 061f3b1eaf0..bf2768af4e1 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageMetadata.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageMetadata.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, 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 @@ -115,10 +115,12 @@ public class GIFImageMetadata extends GIFMetadata { null, null); } + @Override public boolean isReadOnly() { return true; } + @Override public Node getAsTree(String formatName) { if (formatName.equals(nativeMetadataFormatName)) { return getNativeTree(); @@ -252,6 +254,7 @@ public class GIFImageMetadata extends GIFMetadata { return root; } + @Override public IIOMetadataNode getStandardChromaNode() { IIOMetadataNode chroma_node = new IIOMetadataNode("Chroma"); IIOMetadataNode node = null; // scratch node @@ -294,6 +297,7 @@ public class GIFImageMetadata extends GIFMetadata { return chroma_node; } + @Override public IIOMetadataNode getStandardCompressionNode() { IIOMetadataNode compression_node = new IIOMetadataNode("Compression"); IIOMetadataNode node = null; // scratch node @@ -315,6 +319,7 @@ public class GIFImageMetadata extends GIFMetadata { return compression_node; } + @Override public IIOMetadataNode getStandardDataNode() { IIOMetadataNode data_node = new IIOMetadataNode("Data"); IIOMetadataNode node = null; // scratch node @@ -332,6 +337,7 @@ public class GIFImageMetadata extends GIFMetadata { return data_node; } + @Override public IIOMetadataNode getStandardDimensionNode() { IIOMetadataNode dimension_node = new IIOMetadataNode("Dimension"); IIOMetadataNode node = null; // scratch node @@ -365,6 +371,7 @@ public class GIFImageMetadata extends GIFMetadata { // Document not in image + @Override public IIOMetadataNode getStandardTextNode() { if (comments == null) { return null; @@ -391,6 +398,7 @@ public class GIFImageMetadata extends GIFMetadata { return text_node; } + @Override public IIOMetadataNode getStandardTransparencyNode() { if (!transparentColorFlag) { return null; @@ -414,22 +422,26 @@ public class GIFImageMetadata extends GIFMetadata { return transparency_node; } + @Override public void setFromTree(String formatName, Node root) throws IIOInvalidTreeException { throw new IllegalStateException("Metadata is read-only!"); } + @Override protected void mergeNativeTree(Node root) throws IIOInvalidTreeException { throw new IllegalStateException("Metadata is read-only!"); } + @Override protected void mergeStandardTree(Node root) throws IIOInvalidTreeException { throw new IllegalStateException("Metadata is read-only!"); } + @Override public void reset() { throw new IllegalStateException("Metadata is read-only!"); } diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageMetadataFormat.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageMetadataFormat.java index fa55d72bbda..5a6a85a2b57 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageMetadataFormat.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageMetadataFormat.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, 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,6 +157,7 @@ public class GIFImageMetadataFormat extends IIOMetadataFormatImpl { DATATYPE_STRING, true, null); } + @Override public boolean canNodeAppear(String elementName, ImageTypeSpecifier imageType) { return true; diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageMetadataFormatResources.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageMetadataFormatResources.java index aa9697a8ee9..f9a29cdebba 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageMetadataFormatResources.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageMetadataFormatResources.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, 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 @@ public class GIFImageMetadataFormatResources extends ListResourceBundle { public GIFImageMetadataFormatResources() {} + @Override protected Object[][] getContents() { return new Object[][] { diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageReaderSpi.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageReaderSpi.java index 96a5ba436aa..9484484abf8 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageReaderSpi.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageReaderSpi.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, 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 @@ -71,10 +71,12 @@ public class GIFImageReaderSpi extends ImageReaderSpi { ); } + @Override public String getDescription(Locale locale) { return "Standard GIF image reader"; } + @Override public boolean canDecodeInput(Object input) throws IOException { if (!(input instanceof ImageInputStream)) { return false; @@ -91,6 +93,7 @@ public class GIFImageReaderSpi extends ImageReaderSpi { (b[4] == '7' || b[4] == '9') && b[5] == 'a'; } + @Override public ImageReader createReaderInstance(Object extension) { return new GIFImageReader(this); } diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageWriterSpi.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageWriterSpi.java index 0f1b8aec102..6da6332eb50 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageWriterSpi.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageWriterSpi.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -73,6 +73,7 @@ public class GIFImageWriterSpi extends ImageWriterSpi { ); } + @Override public boolean canEncodeImage(ImageTypeSpecifier type) { if (type == null) { throw new IllegalArgumentException("type == null!"); @@ -94,10 +95,12 @@ public class GIFImageWriterSpi extends ImageWriterSpi { } } + @Override public String getDescription(Locale locale) { return "Standard GIF image writer"; } + @Override public ImageWriter createWriterInstance(Object extension) { return new GIFImageWriter(this); } diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFMetadata.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFMetadata.java index 5fb4dc007b7..dca232352d9 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFMetadata.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFMetadata.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -242,6 +242,7 @@ abstract class GIFMetadata extends IIOMetadata { extraMetadataFormatClassNames); } + @Override public void mergeTree(String formatName, Node root) throws IIOInvalidTreeException { if (formatName.equals(nativeMetadataFormatName)) { diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFStreamMetadata.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFStreamMetadata.java index 31c1305b58a..b34e96907ee 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFStreamMetadata.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFStreamMetadata.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, 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 @@ -77,10 +77,12 @@ public class GIFStreamMetadata extends GIFMetadata { } + @Override public boolean isReadOnly() { return true; } + @Override public Node getAsTree(String formatName) { if (formatName.equals(nativeMetadataFormatName)) { return getNativeTree(); @@ -149,6 +151,7 @@ public class GIFStreamMetadata extends GIFMetadata { return root; } + @Override public IIOMetadataNode getStandardChromaNode() { IIOMetadataNode chroma_node = new IIOMetadataNode("Chroma"); IIOMetadataNode node = null; // scratch node @@ -190,6 +193,7 @@ public class GIFStreamMetadata extends GIFMetadata { return chroma_node; } + @Override public IIOMetadataNode getStandardCompressionNode() { IIOMetadataNode compression_node = new IIOMetadataNode("Compression"); IIOMetadataNode node = null; // scratch node @@ -208,6 +212,7 @@ public class GIFStreamMetadata extends GIFMetadata { return compression_node; } + @Override public IIOMetadataNode getStandardDataNode() { IIOMetadataNode data_node = new IIOMetadataNode("Data"); IIOMetadataNode node = null; // scratch node @@ -230,6 +235,7 @@ public class GIFStreamMetadata extends GIFMetadata { return data_node; } + @Override public IIOMetadataNode getStandardDimensionNode() { IIOMetadataNode dimension_node = new IIOMetadataNode("Dimension"); IIOMetadataNode node = null; // scratch node @@ -270,6 +276,7 @@ public class GIFStreamMetadata extends GIFMetadata { return dimension_node; } + @Override public IIOMetadataNode getStandardDocumentNode() { IIOMetadataNode document_node = new IIOMetadataNode("Document"); IIOMetadataNode node = null; // scratch node @@ -285,32 +292,38 @@ public class GIFStreamMetadata extends GIFMetadata { return document_node; } + @Override public IIOMetadataNode getStandardTextNode() { // Not in stream return null; } + @Override public IIOMetadataNode getStandardTransparencyNode() { // Not in stream return null; } + @Override public void setFromTree(String formatName, Node root) throws IIOInvalidTreeException { throw new IllegalStateException("Metadata is read-only!"); } + @Override protected void mergeNativeTree(Node root) throws IIOInvalidTreeException { throw new IllegalStateException("Metadata is read-only!"); } + @Override protected void mergeStandardTree(Node root) throws IIOInvalidTreeException { throw new IllegalStateException("Metadata is read-only!"); } + @Override public void reset() { throw new IllegalStateException("Metadata is read-only!"); } diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFStreamMetadataFormat.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFStreamMetadataFormat.java index b598674ccb3..fcdb8b0d13e 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFStreamMetadataFormat.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFStreamMetadataFormat.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, 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 @@ -92,6 +92,7 @@ public class GIFStreamMetadataFormat extends IIOMetadataFormatImpl { "0", "255", true, true); } + @Override public boolean canNodeAppear(String elementName, ImageTypeSpecifier imageType) { return true; diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFStreamMetadataFormatResources.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFStreamMetadataFormatResources.java index 0404b2c88da..65e9f89c557 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFStreamMetadataFormatResources.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFStreamMetadataFormatResources.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, 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 @@ public class GIFStreamMetadataFormatResources extends ListResourceBundle { public GIFStreamMetadataFormatResources() {} + @Override protected Object[][] getContents() { return new Object[][] { diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFWritableImageMetadata.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFWritableImageMetadata.java index a3e8a769490..cec4f354ee0 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFWritableImageMetadata.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFWritableImageMetadata.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -49,10 +49,12 @@ class GIFWritableImageMetadata extends GIFImageMetadata { null, null); } + @Override public boolean isReadOnly() { return false; } + @Override public void reset() { // Fields from Image Descriptor imageLeftPosition = 0; @@ -96,6 +98,7 @@ class GIFWritableImageMetadata extends GIFImageMetadata { return data.getBytes(ISO_8859_1); } + @Override protected void mergeNativeTree(Node root) throws IIOInvalidTreeException { Node node = root; if (!node.getNodeName().equals(nativeMetadataFormatName)) { @@ -292,6 +295,7 @@ class GIFWritableImageMetadata extends GIFImageMetadata { } } + @Override protected void mergeStandardTree(Node root) throws IIOInvalidTreeException { Node node = root; @@ -389,6 +393,7 @@ class GIFWritableImageMetadata extends GIFImageMetadata { } } + @Override public void setFromTree(String formatName, Node root) throws IIOInvalidTreeException { diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFWritableStreamMetadata.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFWritableStreamMetadata.java index 8a9a6d865a8..d8863cb4a2d 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFWritableStreamMetadata.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFWritableStreamMetadata.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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,10 +55,12 @@ class GIFWritableStreamMetadata extends GIFStreamMetadata { reset(); } + @Override public boolean isReadOnly() { return false; } + @Override public void mergeTree(String formatName, Node root) throws IIOInvalidTreeException { if (formatName.equals(nativeMetadataFormatName)) { @@ -77,6 +79,7 @@ class GIFWritableStreamMetadata extends GIFStreamMetadata { } } + @Override public void reset() { version = null; @@ -90,6 +93,7 @@ class GIFWritableStreamMetadata extends GIFStreamMetadata { globalColorTable = null; } + @Override protected void mergeNativeTree(Node root) throws IIOInvalidTreeException { Node node = root; if (!node.getNodeName().equals(nativeMetadataFormatName)) { @@ -164,6 +168,7 @@ class GIFWritableStreamMetadata extends GIFStreamMetadata { } } + @Override protected void mergeStandardTree(Node root) throws IIOInvalidTreeException { Node node = root; @@ -258,6 +263,7 @@ class GIFWritableStreamMetadata extends GIFStreamMetadata { } } + @Override public void setFromTree(String formatName, Node root) throws IIOInvalidTreeException { diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/AdobeMarkerSegment.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/AdobeMarkerSegment.java index 551f4dc4d72..9b1fbd27fc4 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/AdobeMarkerSegment.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/AdobeMarkerSegment.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, 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 @@ -73,6 +73,7 @@ class AdobeMarkerSegment extends MarkerSegment { updateFromNativeNode(node, true); } + @Override IIOMetadataNode getNativeNode() { IIOMetadataNode node = new IIOMetadataNode("app14Adobe"); node.setAttribute("version", Integer.toString(version)); @@ -108,6 +109,7 @@ class AdobeMarkerSegment extends MarkerSegment { * Writes the data for this segment to the stream in * valid JPEG format. */ + @Override void write(ImageOutputStream ios) throws IOException { length = 14; writeTag(ios); @@ -124,6 +126,7 @@ class AdobeMarkerSegment extends MarkerSegment { (new AdobeMarkerSegment(transform)).write(ios); } + @Override void print () { printTag("Adobe APP14"); System.out.print("Version: "); diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/COMMarkerSegment.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/COMMarkerSegment.java index f28e7b35658..f45bded991a 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/COMMarkerSegment.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/COMMarkerSegment.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, 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 @@ -104,6 +104,7 @@ class COMMarkerSegment extends MarkerSegment { * as a user object and a string encoded using ISO-8895-1, as an * attribute. */ + @Override IIOMetadataNode getNativeNode() { IIOMetadataNode node = new IIOMetadataNode("com"); node.setAttribute("comment", getComment()); @@ -117,12 +118,14 @@ class COMMarkerSegment extends MarkerSegment { * Writes the data for this segment to the stream in * valid JPEG format, directly from the data array. */ + @Override void write(ImageOutputStream ios) throws IOException { length = 2 + data.length; writeTag(ios); ios.write(data); } + @Override void print() { printTag("COM"); System.out.println("<" + getComment() + ">"); diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/DHTMarkerSegment.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/DHTMarkerSegment.java index c14402522db..634a266354d 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/DHTMarkerSegment.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/DHTMarkerSegment.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, 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,6 +90,7 @@ class DHTMarkerSegment extends MarkerSegment { } } + @Override protected Object clone() { DHTMarkerSegment newGuy = (DHTMarkerSegment) super.clone(); newGuy.tables = new ArrayList<>(tables.size()); @@ -99,6 +100,7 @@ class DHTMarkerSegment extends MarkerSegment { return newGuy; } + @Override IIOMetadataNode getNativeNode() { IIOMetadataNode node = new IIOMetadataNode("dht"); for (int i= 0; i(tables.size()); @@ -92,6 +93,7 @@ class DQTMarkerSegment extends MarkerSegment { return newGuy; } + @Override IIOMetadataNode getNativeNode() { IIOMetadataNode node = new IIOMetadataNode("dqt"); for (int i= 0; i MAX_THUMB_WIDTH) @@ -949,6 +960,7 @@ class JFIFMarkerSegment extends MarkerSegment { writeThumbnailData(ios, data, writer); } + @Override void print() { System.out.print(name + " width: "); System.out.println(thumbWidth); @@ -978,10 +990,12 @@ class JFIFMarkerSegment extends MarkerSegment { super(thumb); } + @Override int getLength() { return (thumbWidth*thumbHeight*3); } + @Override BufferedImage getThumbnail(ImageInputStream iis, JPEGImageReader reader) throws IOException { @@ -1014,6 +1028,7 @@ class JFIFMarkerSegment extends MarkerSegment { null); } + @Override void write(ImageOutputStream ios, JPEGImageWriter writer) throws IOException { super.write(ios, writer); // width and height @@ -1050,10 +1065,12 @@ class JFIFMarkerSegment extends MarkerSegment { } } + @Override int getLength() { return (thumbWidth*thumbHeight + PALETTE_SIZE); } + @Override BufferedImage getThumbnail(ImageInputStream iis, JPEGImageReader reader) throws IOException { @@ -1091,6 +1108,7 @@ class JFIFMarkerSegment extends MarkerSegment { null); } + @Override void write(ImageOutputStream ios, JPEGImageWriter writer) throws IOException { super.write(ios, writer); // width and height @@ -1221,6 +1239,7 @@ class JFIFMarkerSegment extends MarkerSegment { } } + @Override int getWidth() { int retval = 0; SOFMarkerSegment sof = @@ -1232,6 +1251,7 @@ class JFIFMarkerSegment extends MarkerSegment { return retval; } + @Override int getHeight() { int retval = 0; SOFMarkerSegment sof = @@ -1249,21 +1269,31 @@ class JFIFMarkerSegment extends MarkerSegment { ThumbnailReadListener (JPEGImageReader reader) { this.reader = reader; } + @Override public void sequenceStarted(ImageReader source, int minIndex) {} + @Override public void sequenceComplete(ImageReader source) {} + @Override public void imageStarted(ImageReader source, int imageIndex) {} + @Override public void imageProgress(ImageReader source, float percentageDone) { reader.thumbnailProgress(percentageDone); } + @Override public void imageComplete(ImageReader source) {} + @Override public void thumbnailStarted(ImageReader source, int imageIndex, int thumbnailIndex) {} + @Override public void thumbnailProgress(ImageReader source, float percentageDone) {} + @Override public void thumbnailComplete(ImageReader source) {} + @Override public void readAborted(ImageReader source) {} } + @Override BufferedImage getThumbnail(ImageInputStream iis, JPEGImageReader reader) throws IOException { @@ -1279,6 +1309,7 @@ class JFIFMarkerSegment extends MarkerSegment { return ret; } + @Override protected Object clone() { JFIFThumbJPEG newGuy = (JFIFThumbJPEG) super.clone(); if (thumbMetadata != null) { @@ -1287,6 +1318,7 @@ class JFIFMarkerSegment extends MarkerSegment { return newGuy; } + @Override IIOMetadataNode getNativeNode() { IIOMetadataNode node = new IIOMetadataNode("JFIFthumbJPEG"); if (thumbMetadata != null) { @@ -1295,6 +1327,7 @@ class JFIFMarkerSegment extends MarkerSegment { return node; } + @Override int getLength() { if (data == null) { return 0; @@ -1303,6 +1336,7 @@ class JFIFMarkerSegment extends MarkerSegment { } } + @Override void write(ImageOutputStream ios, JPEGImageWriter writer) throws IOException { int progInterval = data.length / 20; // approx. every 5% @@ -1322,6 +1356,7 @@ class JFIFMarkerSegment extends MarkerSegment { } } + @Override void print () { System.out.println("JFIF thumbnail stored as JPEG"); } @@ -1445,6 +1480,7 @@ class JFIFMarkerSegment extends MarkerSegment { } } + @Override protected Object clone () { ICCMarkerSegment newGuy = (ICCMarkerSegment) super.clone(); if (profile != null) { @@ -1541,6 +1577,7 @@ class JFIFMarkerSegment extends MarkerSegment { return retval; } + @Override IIOMetadataNode getNativeNode() { IIOMetadataNode node = new IIOMetadataNode("app2ICC"); if (profile != null) { @@ -1553,10 +1590,12 @@ class JFIFMarkerSegment extends MarkerSegment { * No-op. Profiles are never written from metadata. * They are written from the ColorSpace of the image. */ + @Override void write(ImageOutputStream ios) throws IOException { // No-op } + @Override void print () { printTag("ICC Profile APP2"); } diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageMetadataFormat.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageMetadataFormat.java index 4c858a47ab1..20b94fb339b 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageMetadataFormat.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageMetadataFormat.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, 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 @@ -337,6 +337,7 @@ public class JPEGImageMetadataFormat extends JPEGMetadataFormat { tabids); } + @Override public boolean canNodeAppear(String elementName, ImageTypeSpecifier imageType) { // All images can have these diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageMetadataFormatResources.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageMetadataFormatResources.java index e242a355a17..3cbc0054c85 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageMetadataFormatResources.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageMetadataFormatResources.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, 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 @@ -122,6 +122,7 @@ public class JPEGImageMetadataFormatResources public JPEGImageMetadataFormatResources() {} + @Override protected Object[][] getContents() { // return a copy of the combined commonContents and imageContents; // in theory we want a deep clone of the combined arrays, diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReaderResources.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReaderResources.java index e4b09197aa7..be6fc32a761 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReaderResources.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReaderResources.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, 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 @@ public class JPEGImageReaderResources extends ListResourceBundle { public JPEGImageReaderResources() {} + @Override protected Object[][] getContents() { return new Object[][] { diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReaderSpi.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReaderSpi.java index 450dd89b6f4..ab942ea8de2 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReaderSpi.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReaderSpi.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, 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 @@ -59,10 +59,12 @@ public class JPEGImageReaderSpi extends ImageReaderSpi { ); } + @Override public String getDescription(Locale locale) { return "Standard JPEG Image Reader"; } + @Override public boolean canDecodeInput(Object source) throws IOException { if (!(source instanceof ImageInputStream)) { return false; @@ -80,6 +82,7 @@ public class JPEGImageReaderSpi extends ImageReaderSpi { return false; } + @Override public ImageReader createReaderInstance(Object extension) throws IIOException { return new JPEGImageReader(this); diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageWriterResources.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageWriterResources.java index 3db20b3d39d..3b2a149f6b4 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageWriterResources.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageWriterResources.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, 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 @@ public class JPEGImageWriterResources extends ListResourceBundle { public JPEGImageWriterResources() {} + @Override protected Object[][] getContents() { return new Object[][] { diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageWriterSpi.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageWriterSpi.java index bd6bcc8d784..d6f5abbbccb 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageWriterSpi.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageWriterSpi.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, 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 @@ -63,14 +63,17 @@ public class JPEGImageWriterSpi extends ImageWriterSpi { ); } + @Override public String getDescription(Locale locale) { return "Standard JPEG Image Writer"; } + @Override public boolean isFormatLossless() { return false; } + @Override public boolean canEncodeImage(ImageTypeSpecifier type) { SampleModel sampleModel = type.getSampleModel(); ColorModel cm = type.getColorModel(); @@ -95,6 +98,7 @@ public class JPEGImageWriterSpi extends ImageWriterSpi { return true; } + @Override public ImageWriter createWriterInstance(Object extension) throws IIOException { return new JPEGImageWriter(this); diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGMetadata.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGMetadata.java index c7ad982b35a..3081fd43404 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGMetadata.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGMetadata.java @@ -725,6 +725,7 @@ public class JPEGMetadata extends IIOMetadata implements Cloneable { // Implement Cloneable, but restrict access + @Override protected Object clone() { JPEGMetadata newGuy = null; try { @@ -755,6 +756,7 @@ public class JPEGMetadata extends IIOMetadata implements Cloneable { // Tree methods + @Override public Node getAsTree(String formatName) { if (formatName == null) { throw new IllegalArgumentException("null formatName!"); @@ -810,6 +812,7 @@ public class JPEGMetadata extends IIOMetadata implements Cloneable { // Standard tree node methods + @Override protected IIOMetadataNode getStandardChromaNode() { hasAlpha = false; // Unless we find otherwise @@ -950,6 +953,7 @@ public class JPEGMetadata extends IIOMetadata implements Cloneable { return chroma; } + @Override protected IIOMetadataNode getStandardCompressionNode() { IIOMetadataNode compression = new IIOMetadataNode("Compression"); @@ -980,6 +984,7 @@ public class JPEGMetadata extends IIOMetadata implements Cloneable { return compression; } + @Override protected IIOMetadataNode getStandardDimensionNode() { // If we have a JFIF marker segment, we know a little // otherwise all we know is the orientation, which is always normal @@ -1055,6 +1060,7 @@ public class JPEGMetadata extends IIOMetadata implements Cloneable { return doc; } + @Override protected IIOMetadataNode getStandardTextNode() { IIOMetadataNode text = null; // Add a text entry for each COM Marker Segment @@ -1073,6 +1079,7 @@ public class JPEGMetadata extends IIOMetadata implements Cloneable { return text; } + @Override protected IIOMetadataNode getStandardTransparencyNode() { IIOMetadataNode trans = null; if (hasAlpha == true) { @@ -1086,10 +1093,12 @@ public class JPEGMetadata extends IIOMetadata implements Cloneable { // Editing + @Override public boolean isReadOnly() { return false; } + @Override public void mergeTree(String formatName, Node root) throws IIOInvalidTreeException { if (formatName == null) { @@ -2160,6 +2169,7 @@ public class JPEGMetadata extends IIOMetadata implements Cloneable { } + @Override public void setFromTree(String formatName, Node root) throws IIOInvalidTreeException { if (formatName == null) { @@ -2404,6 +2414,7 @@ public class JPEGMetadata extends IIOMetadata implements Cloneable { //// End of writer support + @Override public void reset() { if (resetSequence != null) { // Otherwise no need to reset markerSequence = resetSequence; diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGMetadataFormat.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGMetadataFormat.java index 475cc36359e..53b30f333f0 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGMetadataFormat.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGMetadataFormat.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, 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,6 +123,7 @@ abstract class JPEGMetadataFormat extends IIOMetadataFormatImpl { addObjectValue("unknown", byte[].class, 1, MAX_JPEG_DATA_SIZE); } + @Override public boolean canNodeAppear(String elementName, ImageTypeSpecifier imageType) { // Just check if it appears in the format diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGStreamMetadataFormatResources.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGStreamMetadataFormatResources.java index ea6d2b70138..5e29101e83b 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGStreamMetadataFormatResources.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGStreamMetadataFormatResources.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, 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,6 +32,7 @@ public class JPEGStreamMetadataFormatResources public JPEGStreamMetadataFormatResources() {} + @Override protected Object[][] getContents() { // return a copy of commonContents; in theory we want a deep clone // of commonContents, but since it only contains (immutable) Strings, diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/MarkerSegment.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/MarkerSegment.java index f4ba27b0fcd..74bf598c4d5 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/MarkerSegment.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/MarkerSegment.java @@ -110,6 +110,7 @@ class MarkerSegment implements Cloneable { /** * Deep copy of data array. */ + @Override protected Object clone() { MarkerSegment newGuy = null; try { diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/SOFMarkerSegment.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/SOFMarkerSegment.java index e5b7e861924..fa7acba3325 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/SOFMarkerSegment.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/SOFMarkerSegment.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, 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 @@ -95,6 +95,7 @@ class SOFMarkerSegment extends MarkerSegment { updateFromNativeNode(node, true); } + @Override protected Object clone() { SOFMarkerSegment newGuy = (SOFMarkerSegment) super.clone(); if (componentSpecs != null) { @@ -107,6 +108,7 @@ class SOFMarkerSegment extends MarkerSegment { return newGuy; } + @Override IIOMetadataNode getNativeNode() { IIOMetadataNode node = new IIOMetadataNode("sof"); node.setAttribute("process", Integer.toString(tag-JPEG.SOF0)); @@ -154,10 +156,12 @@ class SOFMarkerSegment extends MarkerSegment { * Writes the data for this segment to the stream in * valid JPEG format. */ + @Override void write(ImageOutputStream ios) throws IOException { // We don't write SOF segments; the IJG library does. } + @Override void print () { printTag("SOF"); System.out.print("Sample precision: "); @@ -231,6 +235,7 @@ class SOFMarkerSegment extends MarkerSegment { 0, 3, true); } + @Override protected Object clone() { try { return super.clone(); diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/SOSMarkerSegment.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/SOSMarkerSegment.java index f40acdd0375..a34fc43486a 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/SOSMarkerSegment.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/SOSMarkerSegment.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, 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 @@ -89,6 +89,7 @@ class SOSMarkerSegment extends MarkerSegment { updateFromNativeNode(node, true); } + @Override protected Object clone () { SOSMarkerSegment newGuy = (SOSMarkerSegment) super.clone(); if (componentSpecs != null) { @@ -101,6 +102,7 @@ class SOSMarkerSegment extends MarkerSegment { return newGuy; } + @Override IIOMetadataNode getNativeNode() { IIOMetadataNode node = new IIOMetadataNode("sos"); node.setAttribute("numScanComponents", @@ -152,10 +154,12 @@ class SOSMarkerSegment extends MarkerSegment { * Writes the data for this segment to the stream in * valid JPEG format. */ + @Override void write(ImageOutputStream ios) throws IOException { // We don't write SOS segments; the IJG library does. } + @Override void print () { printTag("SOS"); System.out.print("Start spectral selection: "); @@ -208,6 +212,7 @@ class SOSMarkerSegment extends MarkerSegment { 0, 3, true); } + @Override protected Object clone() { try { return super.clone(); diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGImageReaderSpi.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGImageReaderSpi.java index 60105e30f8a..bf0576ecb74 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGImageReaderSpi.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGImageReaderSpi.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, 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 @@ -70,10 +70,12 @@ public class PNGImageReaderSpi extends ImageReaderSpi { ); } + @Override public String getDescription(Locale locale) { return "Standard PNG image reader"; } + @Override public boolean canDecodeInput(Object input) throws IOException { if (!(input instanceof ImageInputStream)) { return false; @@ -96,6 +98,7 @@ public class PNGImageReaderSpi extends ImageReaderSpi { b[7] == (byte)10); } + @Override public ImageReader createReaderInstance(Object extension) { return new PNGImageReader(this); } diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGImageWriterSpi.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGImageWriterSpi.java index 44080a05a16..3ce07aa4ba5 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGImageWriterSpi.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGImageWriterSpi.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, 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 @@ -74,6 +74,7 @@ public class PNGImageWriterSpi extends ImageWriterSpi { ); } + @Override public boolean canEncodeImage(ImageTypeSpecifier type) { SampleModel sampleModel = type.getSampleModel(); ColorModel colorModel = type.getColorModel(); @@ -116,10 +117,12 @@ public class PNGImageWriterSpi extends ImageWriterSpi { return true; } + @Override public String getDescription(Locale locale) { return "Standard PNG image writer"; } + @Override public ImageWriter createWriterInstance(Object extension) { return new PNGImageWriter(this); } diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGMetadata.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGMetadata.java index 03d00f7ae8e..730294c9f01 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGMetadata.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGMetadata.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, 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 @@ -463,6 +463,7 @@ public class PNGMetadata extends IIOMetadata implements Cloneable { IHDR_present = true; } + @Override public boolean isReadOnly() { return false; } @@ -480,6 +481,7 @@ public class PNGMetadata extends IIOMetadata implements Cloneable { } // Deep clone + @Override public Object clone() { PNGMetadata metadata; try { @@ -495,6 +497,7 @@ public class PNGMetadata extends IIOMetadata implements Cloneable { return metadata; } + @Override public Node getAsTree(String formatName) { if (formatName.equals(nativeMetadataFormatName)) { return getNativeTree(); @@ -847,6 +850,7 @@ public class PNGMetadata extends IIOMetadata implements Cloneable { return numChannels; } + @Override public IIOMetadataNode getStandardChromaNode() { IIOMetadataNode chroma_node = new IIOMetadataNode("Chroma"); IIOMetadataNode node = null; // scratch node @@ -919,6 +923,7 @@ public class PNGMetadata extends IIOMetadata implements Cloneable { return chroma_node; } + @Override public IIOMetadataNode getStandardCompressionNode() { IIOMetadataNode compression_node = new IIOMetadataNode("Compression"); IIOMetadataNode node = null; // scratch node @@ -952,6 +957,7 @@ public class PNGMetadata extends IIOMetadata implements Cloneable { return sb.toString(); } + @Override public IIOMetadataNode getStandardDataNode() { IIOMetadataNode data_node = new IIOMetadataNode("Data"); IIOMetadataNode node = null; // scratch node @@ -998,6 +1004,7 @@ public class PNGMetadata extends IIOMetadata implements Cloneable { return data_node; } + @Override public IIOMetadataNode getStandardDimensionNode() { IIOMetadataNode dimension_node = new IIOMetadataNode("Dimension"); IIOMetadataNode node = null; // scratch node @@ -1027,6 +1034,7 @@ public class PNGMetadata extends IIOMetadata implements Cloneable { return dimension_node; } + @Override public IIOMetadataNode getStandardDocumentNode() { IIOMetadataNode document_node = null; @@ -1067,6 +1075,7 @@ public class PNGMetadata extends IIOMetadata implements Cloneable { return document_node; } + @Override public IIOMetadataNode getStandardTextNode() { int numEntries = tEXt_keyword.size() + iTXt_keyword.size() + zTXt_keyword.size(); @@ -1114,6 +1123,7 @@ public class PNGMetadata extends IIOMetadata implements Cloneable { return text_node; } + @Override public IIOMetadataNode getStandardTransparencyNode() { IIOMetadataNode transparency_node = new IIOMetadataNode("Transparency"); @@ -1285,6 +1295,7 @@ public class PNGMetadata extends IIOMetadata implements Cloneable { return getAttribute(node, name, null, true); } + @Override public void mergeTree(String formatName, Node root) throws IIOInvalidTreeException { if (formatName.equals(nativeMetadataFormatName)) { @@ -2267,6 +2278,7 @@ public class PNGMetadata extends IIOMetadata implements Cloneable { } // Reset all instance variables to their initial state + @Override public void reset() { IHDR_present = false; PLTE_present = false; diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGMetadataFormat.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGMetadataFormat.java index b7d96dc3f2b..1518d097903 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGMetadataFormat.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGMetadataFormat.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, 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 @@ -486,6 +486,7 @@ public class PNGMetadataFormat extends IIOMetadataFormatImpl { addObjectValue("UnknownChunk", byte.class, 0, Integer.MAX_VALUE); } + @Override public boolean canNodeAppear(String elementName, ImageTypeSpecifier imageType) { return true; diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGMetadataFormatResources.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGMetadataFormatResources.java index d99946bd890..818a2364e23 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGMetadataFormatResources.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGMetadataFormatResources.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, 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 @@ public class PNGMetadataFormatResources extends ListResourceBundle { public PNGMetadataFormatResources() {} + @Override protected Object[][] getContents() { return new Object[][] { diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFBaseJPEGCompressor.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFBaseJPEGCompressor.java index d5adb4e8d35..31806941e35 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFBaseJPEGCompressor.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFBaseJPEGCompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -335,6 +335,7 @@ public abstract class TIFFBaseJPEGCompressor extends TIFFCompressor { return JPEGImageMetadata; } + @Override public final int encode(byte[] b, int off, int width, int height, int[] bitsPerSample, diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFCIELabColorConverter.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFCIELabColorConverter.java index bc20c57da69..dbddc94516e 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFCIELabColorConverter.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFCIELabColorConverter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -56,6 +56,7 @@ public class TIFFCIELabColorConverter extends TIFFColorConverter { } } + @Override public void fromRGB(float r, float g, float b, float[] result) { float X = 0.412453f*r + 0.357580f*g + 0.180423f*b; float Y = 0.212671f*r + 0.715160f*g + 0.072169f*b; @@ -100,6 +101,7 @@ public class TIFFCIELabColorConverter extends TIFFColorConverter { result[2] = clamp2(bStar); } + @Override public void toRGB(float x0, float x1, float x2, float[] rgb) { float LStar = x0*100.0f/255.0f; float aStar = (x1 > 128.0f) ? (x1 - 256.0f) : x1; diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFDeflateDecompressor.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFDeflateDecompressor.java index 1ce7d56c1c7..5ade4bacfb4 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFDeflateDecompressor.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFDeflateDecompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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,6 +48,7 @@ public class TIFFDeflateDecompressor extends TIFFDecompressor { this.predictor = predictor; } + @Override public synchronized void decodeRaw(byte[] b, int dstOffset, int bitsPerPixel, diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFDeflater.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFDeflater.java index 0fde32a229f..3a5a10245df 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFDeflater.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFDeflater.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -58,6 +58,7 @@ public class TIFFDeflater extends TIFFCompressor { this.deflater = new Deflater(deflateLevel); } + @Override public int encode(byte[] b, int off, int width, int height, int[] bitsPerSample, diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFExifJPEGCompressor.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFExifJPEGCompressor.java index 3541ce110db..992cba6cbe5 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFExifJPEGCompressor.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFExifJPEGCompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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,6 +39,7 @@ public class TIFFExifJPEGCompressor extends TIFFBaseJPEGCompressor { param); } + @Override public void setMetadata(IIOMetadata metadata) { // Set the metadata. super.setMetadata(metadata); diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFFaxCompressor.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFFaxCompressor.java index 5c126acab53..2af59c682c4 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFFaxCompressor.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFFaxCompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -242,6 +242,7 @@ abstract class TIFFFaxCompressor extends TIFFCompressor { * * @see #getMetadata() */ + @Override public void setMetadata(IIOMetadata metadata) { super.setMetadata(metadata); diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFFaxDecompressor.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFFaxDecompressor.java index a1947dc6b72..64839c033da 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFFaxDecompressor.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFFaxDecompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -591,6 +591,7 @@ class TIFFFaxDecompressor extends TIFFDecompressor { * Invokes the superclass method and then sets instance variables on * the basis of the metadata set on this decompressor. */ + @Override public void beginDecoding() { super.beginDecoding(); @@ -627,6 +628,7 @@ class TIFFFaxDecompressor extends TIFFDecompressor { } } + @Override public void decodeRaw(byte[] b, int dstOffset, int pixelBitStride, // will always be 1 int scanlineStride) throws IOException { diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFFieldNode.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFFieldNode.java index 6f23fbad4f2..e8878d93315 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFFieldNode.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFFieldNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -162,6 +162,7 @@ public class TIFFFieldNode extends IIOMetadataNode { // Need to override this method to avoid a stack overflow exception // which will occur if super.appendChild is called from initialize(). + @Override public Node appendChild(Node newChild) { if (newChild == null) { throw new NullPointerException("newChild == null!"); @@ -172,53 +173,63 @@ public class TIFFFieldNode extends IIOMetadataNode { // Override all methods which refer to child nodes. + @Override public boolean hasChildNodes() { initialize(); return super.hasChildNodes(); } + @Override public int getLength() { initialize(); return super.getLength(); } + @Override public Node getFirstChild() { initialize(); return super.getFirstChild(); } + @Override public Node getLastChild() { initialize(); return super.getLastChild(); } + @Override public Node getPreviousSibling() { initialize(); return super.getPreviousSibling(); } + @Override public Node getNextSibling() { initialize(); return super.getNextSibling(); } + @Override public Node insertBefore(Node newChild, Node refChild) { initialize(); return super.insertBefore(newChild, refChild); } + @Override public Node replaceChild(Node newChild, Node oldChild) { initialize(); return super.replaceChild(newChild, oldChild); } + @Override public Node removeChild(Node oldChild) { initialize(); return super.removeChild(oldChild); } + @Override public Node cloneNode(boolean deep) { initialize(); return super.cloneNode(deep); diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageMetadata.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageMetadata.java index 82ae068d7e4..a3cf39505e6 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageMetadata.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageMetadata.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -93,6 +93,7 @@ public class TIFFImageMetadata extends IIOMetadata { rootIFD.addTIFFField(field); } + @Override public boolean isReadOnly() { return false; } @@ -149,6 +150,7 @@ public class TIFFImageMetadata extends IIOMetadata { return IFDRoot; } + @Override public Node getAsTree(String formatName) { if (formatName.equals(nativeMetadataFormatName)) { return getNativeTree(); @@ -181,6 +183,7 @@ public class TIFFImageMetadata extends IIOMetadata { "Lab", // ICCLab }; + @Override public IIOMetadataNode getStandardChromaNode() { IIOMetadataNode chroma_node = new IIOMetadataNode("Chroma"); IIOMetadataNode node = null; // scratch node @@ -278,6 +281,7 @@ public class TIFFImageMetadata extends IIOMetadata { return chroma_node; } + @Override public IIOMetadataNode getStandardCompressionNode() { IIOMetadataNode compression_node = new IIOMetadataNode("Compression"); IIOMetadataNode node = null; // scratch node @@ -336,6 +340,7 @@ public class TIFFImageMetadata extends IIOMetadata { return sb.toString(); } + @Override public IIOMetadataNode getStandardDataNode() { IIOMetadataNode data_node = new IIOMetadataNode("Data"); IIOMetadataNode node = null; // scratch node @@ -476,6 +481,7 @@ public class TIFFImageMetadata extends IIOMetadata { "Rotate90", }; + @Override public IIOMetadataNode getStandardDimensionNode() { IIOMetadataNode dimension_node = new IIOMetadataNode("Dimension"); IIOMetadataNode node = null; // scratch node @@ -604,6 +610,7 @@ public class TIFFImageMetadata extends IIOMetadata { return dimension_node; } + @Override public IIOMetadataNode getStandardDocumentNode() { IIOMetadataNode document_node = new IIOMetadataNode("Document"); IIOMetadataNode node = null; // scratch node @@ -669,6 +676,7 @@ public class TIFFImageMetadata extends IIOMetadata { return document_node; } + @Override public IIOMetadataNode getStandardTextNode() { IIOMetadataNode text_node = null; IIOMetadataNode node = null; // scratch node @@ -705,6 +713,7 @@ public class TIFFImageMetadata extends IIOMetadata { return text_node; } + @Override public IIOMetadataNode getStandardTransparencyNode() { IIOMetadataNode transparency_node = new IIOMetadataNode("Transparency"); @@ -1579,6 +1588,7 @@ public class TIFFImageMetadata extends IIOMetadata { } } + @Override public void mergeTree(String formatName, Node root) throws IIOInvalidTreeException{ if (formatName.equals(nativeMetadataFormatName)) { @@ -1597,6 +1607,7 @@ public class TIFFImageMetadata extends IIOMetadata { } } + @Override public void reset() { rootIFD = new TIFFIFD(tagSets); } diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageMetadataFormat.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageMetadataFormat.java index 59c425ec517..edfa3a5be9c 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageMetadataFormat.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageMetadataFormat.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ public class TIFFImageMetadataFormat extends TIFFMetadataFormat { static { } + @Override public boolean canNodeAppear(String elementName, ImageTypeSpecifier imageType) { return false; diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageMetadataFormatResources.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageMetadataFormatResources.java index 070836e8854..59e68d0dfe2 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageMetadataFormatResources.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageMetadataFormatResources.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -96,6 +96,7 @@ public class TIFFImageMetadataFormatResources extends ListResourceBundle { public TIFFImageMetadataFormatResources() { } + @Override public Object[][] getContents() { return contents.clone(); } diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageReaderSpi.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageReaderSpi.java index 2332e4be2d1..ef21e0b2042 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageReaderSpi.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageReaderSpi.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -56,10 +56,12 @@ public class TIFFImageReaderSpi extends ImageReaderSpi { ); } + @Override public String getDescription(Locale locale) { return "Standard TIFF image reader"; } + @Override public boolean canDecodeInput(Object input) throws IOException { if (!(input instanceof ImageInputStream)) { return false; @@ -78,10 +80,12 @@ public class TIFFImageReaderSpi extends ImageReaderSpi { b[2] == (byte)0x00 && b[3] == (byte)0x2a)); } + @Override public ImageReader createReaderInstance(Object extension) { return new TIFFImageReader(this); } + @Override public void onRegistration(ServiceRegistry registry, Class category) { if (registered) { diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageWriterSpi.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageWriterSpi.java index 0b93cbedc0b..a742db6f6bb 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageWriterSpi.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageWriterSpi.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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,22 @@ public class TIFFImageWriterSpi extends ImageWriterSpi { ); } + @Override public boolean canEncodeImage(ImageTypeSpecifier type) { return true; } + @Override public String getDescription(Locale locale) { return "Standard TIFF image writer"; } + @Override public ImageWriter createWriterInstance(Object extension) { return new TIFFImageWriter(this); } + @Override public void onRegistration(ServiceRegistry registry, Class category) { if (registered) { diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFJPEGCompressor.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFJPEGCompressor.java index f524f34e32e..e73ccb2b282 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFJPEGCompressor.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFJPEGCompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -54,6 +54,7 @@ public class TIFFJPEGCompressor extends TIFFBaseJPEGCompressor { private static class JPEGSPIFilter implements ServiceRegistry.Filter { JPEGSPIFilter() {} + @Override public boolean filter(Object provider) { ImageReaderSpi readerSPI = (ImageReaderSpi)provider; @@ -112,6 +113,7 @@ public class TIFFJPEGCompressor extends TIFFBaseJPEGCompressor { * * @see #getMetadata() */ + @Override public void setMetadata(IIOMetadata metadata) { super.setMetadata(metadata); diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFJPEGDecompressor.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFJPEGDecompressor.java index 3c2ce905958..7353ccea56f 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFJPEGDecompressor.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFJPEGDecompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -54,6 +54,7 @@ public class TIFFJPEGDecompressor extends TIFFDecompressor { public TIFFJPEGDecompressor() {} + @Override public void beginDecoding() { // Initialize the JPEG reader if needed. if(this.JPEGReader == null) { @@ -90,6 +91,7 @@ public class TIFFJPEGDecompressor extends TIFFDecompressor { } } + @Override public void decodeRaw(byte[] b, int dstOffset, int bitsPerPixel, diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFLSBCompressor.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFLSBCompressor.java index b7bceb89ae4..5052ffedbff 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFLSBCompressor.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFLSBCompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ public class TIFFLSBCompressor extends TIFFCompressor { super("", BaselineTIFFTagSet.COMPRESSION_NONE, true); } + @Override public int encode(byte[] b, int off, int width, int height, int[] bitsPerSample, diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFLSBDecompressor.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFLSBDecompressor.java index d871b6a3e86..6724b779334 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFLSBDecompressor.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFLSBDecompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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,6 +35,7 @@ public class TIFFLSBDecompressor extends TIFFDecompressor { public TIFFLSBDecompressor() {} + @Override public void decodeRaw(byte[] b, int dstOffset, int bitsPerPixel, diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFLZWCompressor.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFLZWCompressor.java index 4b2b945acb7..6780d65053f 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFLZWCompressor.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFLZWCompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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,10 +41,12 @@ public class TIFFLZWCompressor extends TIFFCompressor { this.predictor = predictorValue; } + @Override public void setStream(ImageOutputStream stream) { super.setStream(stream); } + @Override public int encode(byte[] b, int off, int width, int height, int[] bitsPerSample, diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFLZWDecompressor.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFLZWDecompressor.java index fc682589ce2..dcf5b2a7f71 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFLZWDecompressor.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFLZWDecompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -76,6 +76,7 @@ class TIFFLZWDecompressor extends TIFFDecompressor { flipBits = fillOrder == BaselineTIFFTagSet.FILL_ORDER_RIGHT_TO_LEFT; } + @Override public void decodeRaw(byte[] b, int dstOffset, int bitsPerPixel, diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFMetadataFormat.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFMetadataFormat.java index 1091cab9bb2..92d15bfdcb4 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFMetadataFormat.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFMetadataFormat.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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,6 +39,7 @@ public abstract class TIFFMetadataFormat implements IIOMetadataFormat { protected String resourceBaseName; protected String rootName; + @Override public String getRootName() { return rootName; } @@ -85,16 +86,19 @@ public abstract class TIFFMetadataFormat implements IIOMetadataFormat { return info; } + @Override public int getElementMinChildren(String elementName) { TIFFElementInfo info = getElementInfo(elementName); return info.minChildren; } + @Override public int getElementMaxChildren(String elementName) { TIFFElementInfo info = getElementInfo(elementName); return info.maxChildren; } + @Override public String getElementDescription(String elementName, Locale locale) { if (!elementInfoMap.containsKey(elementName)) { throw new IllegalArgumentException("No such element: " + @@ -103,64 +107,77 @@ public abstract class TIFFMetadataFormat implements IIOMetadataFormat { return getResource(elementName, locale); } + @Override public int getChildPolicy(String elementName) { TIFFElementInfo info = getElementInfo(elementName); return info.childPolicy; } + @Override public String[] getChildNames(String elementName) { TIFFElementInfo info = getElementInfo(elementName); return info.childNames; } + @Override public String[] getAttributeNames(String elementName) { TIFFElementInfo info = getElementInfo(elementName); return info.attributeNames; } + @Override public int getAttributeValueType(String elementName, String attrName) { TIFFAttrInfo info = getAttrInfo(elementName, attrName); return info.valueType; } + @Override public int getAttributeDataType(String elementName, String attrName) { TIFFAttrInfo info = getAttrInfo(elementName, attrName); return info.dataType; } + @Override public boolean isAttributeRequired(String elementName, String attrName) { TIFFAttrInfo info = getAttrInfo(elementName, attrName); return info.isRequired; } + @Override public String getAttributeDefaultValue(String elementName, String attrName) { return null; } + @Override public String[] getAttributeEnumerations(String elementName, String attrName) { throw new IllegalArgumentException("The attribute is not an enumeration."); } + @Override public String getAttributeMinValue(String elementName, String attrName) { throw new IllegalArgumentException("The attribute is not a range."); } + @Override public String getAttributeMaxValue(String elementName, String attrName) { throw new IllegalArgumentException("The attribute is not a range."); } + @Override public int getAttributeListMinLength(String elementName, String attrName) { TIFFAttrInfo info = getAttrInfo(elementName, attrName); return info.listMinLength; } + @Override public int getAttributeListMaxLength(String elementName, String attrName) { TIFFAttrInfo info = getAttrInfo(elementName, attrName); return info.listMaxLength; } + @Override public String getAttributeDescription(String elementName, String attrName, Locale locale) { String key = elementName + "/" + attrName; @@ -170,11 +187,13 @@ public abstract class TIFFMetadataFormat implements IIOMetadataFormat { return getResource(key, locale); } + @Override public int getObjectValueType(String elementName) { TIFFElementInfo info = getElementInfo(elementName); return info.objectValueType; } + @Override public Class getObjectClass(String elementName) { TIFFElementInfo info = getElementInfo(elementName); if (info.objectValueType == VALUE_NONE) { @@ -184,6 +203,7 @@ public abstract class TIFFMetadataFormat implements IIOMetadataFormat { return info.objectClass; } + @Override public Object getObjectDefaultValue(String elementName) { TIFFElementInfo info = getElementInfo(elementName); if (info.objectValueType == VALUE_NONE) { @@ -193,6 +213,7 @@ public abstract class TIFFMetadataFormat implements IIOMetadataFormat { return info.objectDefaultValue; } + @Override public Object[] getObjectEnumerations(String elementName) { TIFFElementInfo info = getElementInfo(elementName); if (info.objectValueType == VALUE_NONE) { @@ -202,6 +223,7 @@ public abstract class TIFFMetadataFormat implements IIOMetadataFormat { return info.objectEnumerations; } + @Override public Comparable getObjectMinValue(String elementName) { TIFFElementInfo info = getElementInfo(elementName); if (info.objectValueType == VALUE_NONE) { @@ -211,6 +233,7 @@ public abstract class TIFFMetadataFormat implements IIOMetadataFormat { return info.objectMinValue; } + @Override public Comparable getObjectMaxValue(String elementName) { TIFFElementInfo info = getElementInfo(elementName); if (info.objectValueType == VALUE_NONE) { @@ -220,6 +243,7 @@ public abstract class TIFFMetadataFormat implements IIOMetadataFormat { return info.objectMaxValue; } + @Override public int getObjectArrayMinLength(String elementName) { TIFFElementInfo info = getElementInfo(elementName); if (info.objectValueType == VALUE_NONE) { @@ -229,6 +253,7 @@ public abstract class TIFFMetadataFormat implements IIOMetadataFormat { return info.objectArrayMinLength; } + @Override public int getObjectArrayMaxLength(String elementName) { TIFFElementInfo info = getElementInfo(elementName); if (info.objectValueType == VALUE_NONE) { diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFNullCompressor.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFNullCompressor.java index fc366f791f7..8f6428035d9 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFNullCompressor.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFNullCompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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,6 +33,7 @@ public class TIFFNullCompressor extends TIFFCompressor { super("", BaselineTIFFTagSet.COMPRESSION_NONE, true); } + @Override public int encode(byte[] b, int off, int width, int height, int[] bitsPerSample, diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFNullDecompressor.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFNullDecompressor.java index 9b5a746eec1..b73580ef823 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFNullDecompressor.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFNullDecompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -56,6 +56,7 @@ public class TIFFNullDecompressor extends TIFFDecompressor { // change beginDecoding() and decode() to use the active region values // when random access is easy and the entire region values otherwise. // + @Override public void beginDecoding() { // Determine number of bits per pixel. int bitsPerPixel = 0; @@ -89,6 +90,7 @@ public class TIFFNullDecompressor extends TIFFDecompressor { super.beginDecoding(); } + @Override public void decode() throws IOException { super.decode(); @@ -105,6 +107,7 @@ public class TIFFNullDecompressor extends TIFFDecompressor { } } + @Override public void decodeRaw(byte[] b, int dstOffset, int bitsPerPixel, diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFOldJPEGDecompressor.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFOldJPEGDecompressor.java index 2935ca5caf8..77594ea8086 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFOldJPEGDecompressor.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFOldJPEGDecompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -545,6 +545,7 @@ public class TIFFOldJPEGDecompressor extends TIFFJPEGDecompressor { // The strategy for cases 4-5 is to concatenate a tables stream created // in initialize() with the entropy coded data in each strip or tile. // + @Override public void decodeRaw(byte[] b, int dstOffset, int bitsPerPixel, diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFPackBitsCompressor.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFPackBitsCompressor.java index 119e4ad4906..b2341f12ed7 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFPackBitsCompressor.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFPackBitsCompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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,6 +86,7 @@ public class TIFFPackBitsCompressor extends TIFFCompressor { return outOffset; } + @Override public int encode(byte[] b, int off, int width, int height, int[] bitsPerSample, diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFPackBitsDecompressor.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFPackBitsDecompressor.java index 0a5dfe8308e..61026f57fed 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFPackBitsDecompressor.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFPackBitsDecompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ public class TIFFPackBitsDecompressor extends TIFFDecompressor { return dstIndex - dstOffset; } + @Override public void decodeRaw(byte[] b, int dstOffset, int bitsPerPixel, diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFRLECompressor.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFRLECompressor.java index 0bf59da81da..1e0270c6ecc 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFRLECompressor.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFRLECompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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,6 +87,7 @@ public class TIFFRLECompressor extends TIFFFaxCompressor { return outIndex; } + @Override public int encode(byte[] b, int off, int width, int height, int[] bitsPerSample, diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFRenderedImage.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFRenderedImage.java index 77e0c9a109c..dadabac3d68 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFRenderedImage.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFRenderedImage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -130,74 +130,92 @@ public class TIFFRenderedImage implements RenderedImage { return newParam; } + @Override public Vector getSources() { return null; } + @Override public Object getProperty(String name) { return java.awt.Image.UndefinedProperty; } + @Override public String[] getPropertyNames() { return null; } + @Override public ColorModel getColorModel() { return its.getColorModel(); } + @Override public SampleModel getSampleModel() { return its.getSampleModel(); } + @Override public int getWidth() { return width; } + @Override public int getHeight() { return height; } + @Override public int getMinX() { return 0; } + @Override public int getMinY() { return 0; } + @Override public int getNumXTiles() { return (width + tileWidth - 1)/tileWidth; } + @Override public int getNumYTiles() { return (height + tileHeight - 1)/tileHeight; } + @Override public int getMinTileX() { return 0; } + @Override public int getMinTileY() { return 0; } + @Override public int getTileWidth() { return tileWidth; } + @Override public int getTileHeight() { return tileHeight; } + @Override public int getTileGridXOffset() { return 0; } + @Override public int getTileGridYOffset() { return 0; } + @Override public Raster getTile(int tileX, int tileY) { Rectangle tileRect = new Rectangle(tileX*tileWidth, tileY*tileHeight, @@ -206,10 +224,12 @@ public class TIFFRenderedImage implements RenderedImage { return getData(tileRect); } + @Override public Raster getData() { return read(new Rectangle(0, 0, getWidth(), getHeight())); } + @Override public Raster getData(Rectangle rect) { return read(rect); } @@ -236,6 +256,7 @@ public class TIFFRenderedImage implements RenderedImage { } } + @Override public WritableRaster copyData(WritableRaster raster) { if (raster == null) { return read(new Rectangle(0, 0, getWidth(), getHeight())); diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFStreamMetadata.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFStreamMetadata.java index 96592cc62fb..ac9398fd6e9 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFStreamMetadata.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFStreamMetadata.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -54,6 +54,7 @@ public class TIFFStreamMetadata extends IIOMetadata { null, null); } + @Override public boolean isReadOnly() { return false; } @@ -64,6 +65,7 @@ public class TIFFStreamMetadata extends IIOMetadata { throw new IIOInvalidTreeException(reason, node); } + @Override public Node getAsTree(String formatName) { IIOMetadataNode root = new IIOMetadataNode(nativeMetadataFormatName); @@ -103,6 +105,7 @@ public class TIFFStreamMetadata extends IIOMetadata { } } + @Override public void mergeTree(String formatName, Node root) throws IIOInvalidTreeException { if (formatName.equals(nativeMetadataFormatName)) { @@ -115,6 +118,7 @@ public class TIFFStreamMetadata extends IIOMetadata { } } + @Override public void reset() { this.byteOrder = ByteOrder.BIG_ENDIAN; } diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFStreamMetadataFormat.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFStreamMetadataFormat.java index bf35133811e..50a3d32e239 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFStreamMetadataFormat.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFStreamMetadataFormat.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ public class TIFFStreamMetadataFormat extends TIFFMetadataFormat { private static TIFFStreamMetadataFormat theInstance = null; + @Override public boolean canNodeAppear(String elementName, ImageTypeSpecifier imageType) { return false; diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFStreamMetadataFormatResources.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFStreamMetadataFormatResources.java index 1e0ea272200..75977c15a41 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFStreamMetadataFormatResources.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFStreamMetadataFormatResources.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ public class TIFFStreamMetadataFormatResources extends ListResourceBundle { public TIFFStreamMetadataFormatResources() { } + @Override public Object[][] getContents() { return contents.clone(); } diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFT4Compressor.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFT4Compressor.java index 55088e34dfe..99d45ce4866 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFT4Compressor.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFT4Compressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -52,6 +52,7 @@ public class TIFFT4Compressor extends TIFFFaxCompressor { * * @see #getMetadata() */ + @Override public void setMetadata(IIOMetadata metadata) { super.setMetadata(metadata); @@ -214,6 +215,7 @@ public class TIFFT4Compressor extends TIFFFaxCompressor { return outIndex; } + @Override public int encode(byte[] b, int off, int width, int height, int[] bitsPerSample, diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFT6Compressor.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFT6Compressor.java index 517c23bde54..7e2625d87e2 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFT6Compressor.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFT6Compressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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,6 +146,7 @@ public class TIFFT6Compressor extends TIFFFaxCompressor { return outIndex; } + @Override public int encode(byte[] b, int off, int width, int height, int[] bitsPerSample, diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFYCbCrColorConverter.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFYCbCrColorConverter.java index a006a3a1e38..b5dae8a9298 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFYCbCrColorConverter.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFYCbCrColorConverter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -80,6 +80,7 @@ public class TIFFYCbCrColorConverter extends TIFFColorConverter { / CodingRange) + ReferenceBlack; */ + @Override public void fromRGB(float r, float g, float b, float[] result) { // Convert RGB to full-range YCbCr. float Y = (lumaRed*r + lumaGreen*g + lumaBlue*b); @@ -95,6 +96,7 @@ public class TIFFYCbCrColorConverter extends TIFFColorConverter { referenceBlackCr; } + @Override public void toRGB(float x0, float x1, float x2, float[] rgb) { // Convert YCbCr code to full-range YCbCr. float Y = (x0 - referenceBlackY)*CODING_RANGE_Y/ diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFYCbCrDecompressor.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFYCbCrDecompressor.java index 0f10904cab4..c0623885d34 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFYCbCrDecompressor.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFYCbCrDecompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -95,6 +95,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { // "Chained" decompressor methods. // + @Override public void setReader(ImageReader reader) { if(decompressor != null) { decompressor.setReader(reader); @@ -102,6 +103,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setReader(reader); } + @Override public void setMetadata(IIOMetadata metadata) { if(decompressor != null) { decompressor.setMetadata(metadata); @@ -109,6 +111,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setMetadata(metadata); } + @Override public void setPhotometricInterpretation(int photometricInterpretation) { if(decompressor != null) { decompressor.setPhotometricInterpretation(photometricInterpretation); @@ -116,6 +119,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setPhotometricInterpretation(photometricInterpretation); } + @Override public void setCompression(int compression) { if(decompressor != null) { decompressor.setCompression(compression); @@ -123,6 +127,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setCompression(compression); } + @Override public void setPlanar(boolean planar) { if(decompressor != null) { decompressor.setPlanar(planar); @@ -130,6 +135,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setPlanar(planar); } + @Override public void setSamplesPerPixel(int samplesPerPixel) { if(decompressor != null) { decompressor.setSamplesPerPixel(samplesPerPixel); @@ -137,6 +143,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setSamplesPerPixel(samplesPerPixel); } + @Override public void setBitsPerSample(int[] bitsPerSample) { if(decompressor != null) { decompressor.setBitsPerSample(bitsPerSample); @@ -144,6 +151,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setBitsPerSample(bitsPerSample); } + @Override public void setSampleFormat(int[] sampleFormat) { if(decompressor != null) { decompressor.setSampleFormat(sampleFormat); @@ -151,6 +159,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setSampleFormat(sampleFormat); } + @Override public void setExtraSamples(int[] extraSamples) { if(decompressor != null) { decompressor.setExtraSamples(extraSamples); @@ -158,6 +167,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setExtraSamples(extraSamples); } + @Override public void setColorMap(char[] colorMap) { if(decompressor != null) { decompressor.setColorMap(colorMap); @@ -165,6 +175,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setColorMap(colorMap); } + @Override public void setStream(ImageInputStream stream) { if(decompressor != null) { decompressor.setStream(stream); @@ -173,6 +184,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { } } + @Override public void setOffset(long offset) { if(decompressor != null) { decompressor.setOffset(offset); @@ -180,6 +192,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setOffset(offset); } + @Override public void setByteCount(int byteCount) throws IOException { if(decompressor != null) { decompressor.setByteCount(byteCount); @@ -187,6 +200,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setByteCount(byteCount); } + @Override public void setSrcMinX(int srcMinX) { if(decompressor != null) { decompressor.setSrcMinX(srcMinX); @@ -194,6 +208,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setSrcMinX(srcMinX); } + @Override public void setSrcMinY(int srcMinY) { if(decompressor != null) { decompressor.setSrcMinY(srcMinY); @@ -201,6 +216,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setSrcMinY(srcMinY); } + @Override public void setSrcWidth(int srcWidth) { if(decompressor != null) { decompressor.setSrcWidth(srcWidth); @@ -208,6 +224,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setSrcWidth(srcWidth); } + @Override public void setSrcHeight(int srcHeight) { if(decompressor != null) { decompressor.setSrcHeight(srcHeight); @@ -215,6 +232,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setSrcHeight(srcHeight); } + @Override public void setSourceXOffset(int sourceXOffset) { if(decompressor != null) { decompressor.setSourceXOffset(sourceXOffset); @@ -222,6 +240,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setSourceXOffset(sourceXOffset); } + @Override public void setDstXOffset(int dstXOffset) { if(decompressor != null) { decompressor.setDstXOffset(dstXOffset); @@ -229,6 +248,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setDstXOffset(dstXOffset); } + @Override public void setSourceYOffset(int sourceYOffset) { if(decompressor != null) { decompressor.setSourceYOffset(sourceYOffset); @@ -236,6 +256,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setSourceYOffset(sourceYOffset); } + @Override public void setDstYOffset(int dstYOffset) { if(decompressor != null) { decompressor.setDstYOffset(dstYOffset); @@ -260,6 +281,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { } */ + @Override public void setSourceBands(int[] sourceBands) { if(decompressor != null) { decompressor.setSourceBands(sourceBands); @@ -267,6 +289,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setSourceBands(sourceBands); } + @Override public void setDestinationBands(int[] destinationBands) { if(decompressor != null) { decompressor.setDestinationBands(destinationBands); @@ -274,6 +297,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setDestinationBands(destinationBands); } + @Override public void setImage(BufferedImage image) { if(decompressor != null) { ColorModel cm = image.getColorModel(); @@ -287,6 +311,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setImage(image); } + @Override public void setDstMinX(int dstMinX) { if(decompressor != null) { decompressor.setDstMinX(dstMinX); @@ -294,6 +319,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setDstMinX(dstMinX); } + @Override public void setDstMinY(int dstMinY) { if(decompressor != null) { decompressor.setDstMinY(dstMinY); @@ -301,6 +327,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setDstMinY(dstMinY); } + @Override public void setDstWidth(int dstWidth) { if(decompressor != null) { decompressor.setDstWidth(dstWidth); @@ -308,6 +335,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setDstWidth(dstWidth); } + @Override public void setDstHeight(int dstHeight) { if(decompressor != null) { decompressor.setDstHeight(dstHeight); @@ -315,6 +343,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setDstHeight(dstHeight); } + @Override public void setActiveSrcMinX(int activeSrcMinX) { if(decompressor != null) { decompressor.setActiveSrcMinX(activeSrcMinX); @@ -322,6 +351,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setActiveSrcMinX(activeSrcMinX); } + @Override public void setActiveSrcMinY(int activeSrcMinY) { if(decompressor != null) { decompressor.setActiveSrcMinY(activeSrcMinY); @@ -329,6 +359,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setActiveSrcMinY(activeSrcMinY); } + @Override public void setActiveSrcWidth(int activeSrcWidth) { if(decompressor != null) { decompressor.setActiveSrcWidth(activeSrcWidth); @@ -336,6 +367,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setActiveSrcWidth(activeSrcWidth); } + @Override public void setActiveSrcHeight(int activeSrcHeight) { if(decompressor != null) { decompressor.setActiveSrcHeight(activeSrcHeight); @@ -353,6 +385,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { } } + @Override public void beginDecoding() { if(decompressor != null) { decompressor.beginDecoding(); @@ -445,6 +478,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { } } + @Override public void decodeRaw(byte[] buf, int dstOffset, int bitsPerPixel, diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/wbmp/WBMPImageReaderSpi.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/wbmp/WBMPImageReaderSpi.java index acff45d5b72..9cd967140c9 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/wbmp/WBMPImageReaderSpi.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/wbmp/WBMPImageReaderSpi.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, 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 @@ -63,6 +63,7 @@ public class WBMPImageReaderSpi extends ImageReaderSpi { null, null); } + @Override public void onRegistration(ServiceRegistry registry, Class category) { if (registered) { @@ -71,10 +72,12 @@ public class WBMPImageReaderSpi extends ImageReaderSpi { registered = true; } + @Override public String getDescription(Locale locale) { return "Standard WBMP Image Reader"; } + @Override public boolean canDecodeInput(Object source) throws IOException { if (!(source instanceof ImageInputStream)) { return false; @@ -149,6 +152,7 @@ public class WBMPImageReaderSpi extends ImageReaderSpi { return result; } + @Override public ImageReader createReaderInstance(Object extension) throws IIOException { return new WBMPImageReader(this); diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/wbmp/WBMPImageWriterSpi.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/wbmp/WBMPImageWriterSpi.java index be2f2d96a38..d6d723c0110 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/wbmp/WBMPImageWriterSpi.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/wbmp/WBMPImageWriterSpi.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, 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 @@ -63,10 +63,12 @@ public class WBMPImageWriterSpi extends ImageWriterSpi { null, null, null, null); } + @Override public String getDescription(Locale locale) { return "Standard WBMP Image Writer"; } + @Override public void onRegistration(ServiceRegistry registry, Class category) { if (registered) { @@ -76,6 +78,7 @@ public class WBMPImageWriterSpi extends ImageWriterSpi { registered = true; } + @Override public boolean canEncodeImage(ImageTypeSpecifier type) { SampleModel sm = type.getSampleModel(); if (!(sm instanceof MultiPixelPackedSampleModel)) @@ -86,6 +89,7 @@ public class WBMPImageWriterSpi extends ImageWriterSpi { return true; } + @Override public ImageWriter createWriterInstance(Object extension) throws IIOException { return new WBMPImageWriter(this); diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/wbmp/WBMPMetadata.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/wbmp/WBMPMetadata.java index 3a13bcca94f..f3a63ff7b13 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/wbmp/WBMPMetadata.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/wbmp/WBMPMetadata.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, 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 @@ -50,10 +50,12 @@ public class WBMPMetadata extends IIOMetadata { null, null); } + @Override public boolean isReadOnly() { return true; } + @Override public Node getAsTree(String formatName) { if (formatName.equals(nativeMetadataFormatName)) { return getNativeTree(); @@ -76,14 +78,17 @@ public class WBMPMetadata extends IIOMetadata { return root; } + @Override public void setFromTree(String formatName, Node root) { throw new IllegalStateException(I18N.getString("WBMPMetadata1")); } + @Override public void mergeTree(String formatName, Node root) { throw new IllegalStateException(I18N.getString("WBMPMetadata1")); } + @Override public void reset() { throw new IllegalStateException(I18N.getString("WBMPMetadata1")); } @@ -101,6 +106,7 @@ public class WBMPMetadata extends IIOMetadata { } + @Override protected IIOMetadataNode getStandardChromaNode() { IIOMetadataNode node = new IIOMetadataNode("Chroma"); @@ -112,6 +118,7 @@ public class WBMPMetadata extends IIOMetadata { } + @Override protected IIOMetadataNode getStandardDimensionNode() { IIOMetadataNode dimension_node = new IIOMetadataNode("Dimension"); IIOMetadataNode node = null; // scratch node diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/wbmp/WBMPMetadataFormat.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/wbmp/WBMPMetadataFormat.java index 49bce89164a..0aabaa132a3 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/wbmp/WBMPMetadataFormat.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/wbmp/WBMPMetadataFormat.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, 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 @@ -56,6 +56,7 @@ public class WBMPMetadataFormat extends IIOMetadataFormatImpl { + @Override public boolean canNodeAppear(String elementName, ImageTypeSpecifier imageType) { return true; diff --git a/src/java.desktop/share/classes/com/sun/imageio/spi/FileImageInputStreamSpi.java b/src/java.desktop/share/classes/com/sun/imageio/spi/FileImageInputStreamSpi.java index 81070ff1cb6..3b52fb2b0f0 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/spi/FileImageInputStreamSpi.java +++ b/src/java.desktop/share/classes/com/sun/imageio/spi/FileImageInputStreamSpi.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, 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,10 +43,12 @@ public class FileImageInputStreamSpi extends ImageInputStreamSpi { super(vendorName, version, inputClass); } + @Override public String getDescription(Locale locale) { return "Service provider that instantiates a FileImageInputStream from a File"; } + @Override public ImageInputStream createInputStreamInstance(Object input, boolean useCache, File cacheDir) { diff --git a/src/java.desktop/share/classes/com/sun/imageio/spi/FileImageOutputStreamSpi.java b/src/java.desktop/share/classes/com/sun/imageio/spi/FileImageOutputStreamSpi.java index 1ca08005fa1..aa906197d37 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/spi/FileImageOutputStreamSpi.java +++ b/src/java.desktop/share/classes/com/sun/imageio/spi/FileImageOutputStreamSpi.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, 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,10 +43,12 @@ public class FileImageOutputStreamSpi extends ImageOutputStreamSpi { super(vendorName, version, outputClass); } + @Override public String getDescription(Locale locale) { return "Service provider that instantiates a FileImageOutputStream from a File"; } + @Override public ImageOutputStream createOutputStreamInstance(Object output, boolean useCache, File cacheDir) { diff --git a/src/java.desktop/share/classes/com/sun/imageio/spi/InputStreamImageInputStreamSpi.java b/src/java.desktop/share/classes/com/sun/imageio/spi/InputStreamImageInputStreamSpi.java index 2591f77a697..266b09c6d9d 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/spi/InputStreamImageInputStreamSpi.java +++ b/src/java.desktop/share/classes/com/sun/imageio/spi/InputStreamImageInputStreamSpi.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, 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 @@ -46,18 +46,22 @@ public class InputStreamImageInputStreamSpi extends ImageInputStreamSpi { super(vendorName, version, inputClass); } + @Override public String getDescription(Locale locale) { return "Service provider that instantiates a FileCacheImageInputStream or MemoryCacheImageInputStream from an InputStream"; } + @Override public boolean canUseCacheFile() { return true; } + @Override public boolean needsCacheFile() { return false; } + @Override public ImageInputStream createInputStreamInstance(Object input, boolean useCache, File cacheDir) diff --git a/src/java.desktop/share/classes/com/sun/imageio/spi/OutputStreamImageOutputStreamSpi.java b/src/java.desktop/share/classes/com/sun/imageio/spi/OutputStreamImageOutputStreamSpi.java index 391e00feb46..01c7df2145d 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/spi/OutputStreamImageOutputStreamSpi.java +++ b/src/java.desktop/share/classes/com/sun/imageio/spi/OutputStreamImageOutputStreamSpi.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, 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 @@ -46,18 +46,22 @@ public class OutputStreamImageOutputStreamSpi extends ImageOutputStreamSpi { super(vendorName, version, outputClass); } + @Override public String getDescription(Locale locale) { return "Service provider that instantiates an OutputStreamImageOutputStream from an OutputStream"; } + @Override public boolean canUseCacheFile() { return true; } + @Override public boolean needsCacheFile() { return false; } + @Override public ImageOutputStream createOutputStreamInstance(Object output, boolean useCache, File cacheDir) diff --git a/src/java.desktop/share/classes/com/sun/imageio/spi/RAFImageInputStreamSpi.java b/src/java.desktop/share/classes/com/sun/imageio/spi/RAFImageInputStreamSpi.java index b5c5112c14e..43498b30dbf 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/spi/RAFImageInputStreamSpi.java +++ b/src/java.desktop/share/classes/com/sun/imageio/spi/RAFImageInputStreamSpi.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, 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 @@ -44,10 +44,12 @@ public class RAFImageInputStreamSpi extends ImageInputStreamSpi { super(vendorName, version, inputClass); } + @Override public String getDescription(Locale locale) { return "Service provider that instantiates a FileImageInputStream from a RandomAccessFile"; } + @Override public ImageInputStream createInputStreamInstance(Object input, boolean useCache, File cacheDir) { diff --git a/src/java.desktop/share/classes/com/sun/imageio/spi/RAFImageOutputStreamSpi.java b/src/java.desktop/share/classes/com/sun/imageio/spi/RAFImageOutputStreamSpi.java index 373f8754f08..1fe6438b27d 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/spi/RAFImageOutputStreamSpi.java +++ b/src/java.desktop/share/classes/com/sun/imageio/spi/RAFImageOutputStreamSpi.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, 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 @@ -44,10 +44,12 @@ public class RAFImageOutputStreamSpi extends ImageOutputStreamSpi { super(vendorName, version, outputClass); } + @Override public String getDescription(Locale locale) { return "Service provider that instantiates a FileImageOutputStream from a RandomAccessFile"; } + @Override public ImageOutputStream createOutputStreamInstance(Object output, boolean useCache, File cacheDir) { diff --git a/src/java.desktop/share/classes/com/sun/imageio/stream/CloseableDisposerRecord.java b/src/java.desktop/share/classes/com/sun/imageio/stream/CloseableDisposerRecord.java index 5ea52def657..370606ea08f 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/stream/CloseableDisposerRecord.java +++ b/src/java.desktop/share/classes/com/sun/imageio/stream/CloseableDisposerRecord.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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,6 +41,7 @@ public class CloseableDisposerRecord implements DisposerRecord { this.closeable = closeable; } + @Override public synchronized void dispose() { if (closeable != null) { try { diff --git a/src/java.desktop/share/classes/com/sun/imageio/stream/StreamCloser.java b/src/java.desktop/share/classes/com/sun/imageio/stream/StreamCloser.java index 229c470335b..7de400ad199 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/stream/StreamCloser.java +++ b/src/java.desktop/share/classes/com/sun/imageio/stream/StreamCloser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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,6 +60,7 @@ public class StreamCloser { if (streamCloser == null) { final Runnable streamCloserRunnable = new Runnable() { + @Override public void run() { if (toCloseQueue != null) { synchronized (StreamCloser.class) { From 70b4eb249eb4bad727f83e0b004a0ce481208726 Mon Sep 17 00:00:00 2001 From: Tobias Hartmann Date: Fri, 28 Nov 2025 08:45:57 +0000 Subject: [PATCH 050/706] 8372720: Problem list compiler/arguments/TestCodeEntryAlignment.java Reviewed-by: mchevalier, epeter --- test/hotspot/jtreg/ProblemList.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index 55a43663568..7b4026484ca 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -79,6 +79,8 @@ compiler/c2/aarch64/TestStaticCallStub.java 8359963 linux-aarch64,macosx-aarch64 serviceability/jvmti/NMethodRelocation/NMethodRelocationTest.java 8369150 generic-all +compiler/arguments/TestCodeEntryAlignment.java 8372703 macosx-x64 + ############################################################################# # :hotspot_gc From 0021dc04100befd107d3aa763510b28dd62cd62c Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Fri, 28 Nov 2025 08:54:07 +0000 Subject: [PATCH 051/706] 8372565: Convert SATBMarkQueue to use Atomic Reviewed-by: tschatzl, shade, iwalulya --- src/hotspot/share/gc/shared/bufferNode.hpp | 9 +++++---- src/hotspot/share/gc/shared/satbMarkQueue.cpp | 15 +++++++-------- src/hotspot/share/gc/shared/satbMarkQueue.hpp | 9 +++++---- 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/src/hotspot/share/gc/shared/bufferNode.hpp b/src/hotspot/share/gc/shared/bufferNode.hpp index a453bbc964b..e4e2ff23fb1 100644 --- a/src/hotspot/share/gc/shared/bufferNode.hpp +++ b/src/hotspot/share/gc/shared/bufferNode.hpp @@ -27,6 +27,7 @@ #include "cppstdlib/limits.hpp" #include "gc/shared/freeListAllocator.hpp" +#include "runtime/atomic.hpp" #include "utilities/debug.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/lockFreeStack.hpp" @@ -38,7 +39,7 @@ class BufferNode { InternalSizeType _index; InternalSizeType _capacity; - BufferNode* volatile _next; + Atomic _next; void* _buffer[1]; // Pseudo flexible array member. BufferNode(InternalSizeType capacity) @@ -58,11 +59,11 @@ public: return std::numeric_limits::max(); } - static BufferNode* volatile* next_ptr(BufferNode& bn) { return &bn._next; } + static Atomic* next_ptr(BufferNode& bn) { return &bn._next; } typedef LockFreeStack Stack; - BufferNode* next() const { return _next; } - void set_next(BufferNode* n) { _next = n; } + BufferNode* next() const { return _next.load_relaxed(); } + void set_next(BufferNode* n) { _next.store_relaxed(n); } size_t index() const { return _index; } void set_index(size_t i) { diff --git a/src/hotspot/share/gc/shared/satbMarkQueue.cpp b/src/hotspot/share/gc/shared/satbMarkQueue.cpp index e6ffe39facf..93c52b499a0 100644 --- a/src/hotspot/share/gc/shared/satbMarkQueue.cpp +++ b/src/hotspot/share/gc/shared/satbMarkQueue.cpp @@ -27,7 +27,6 @@ #include "logging/log.hpp" #include "memory/allocation.inline.hpp" #include "oops/oop.inline.hpp" -#include "runtime/atomicAccess.hpp" #include "runtime/mutexLocker.hpp" #include "runtime/os.hpp" #include "runtime/safepoint.hpp" @@ -85,28 +84,28 @@ SATBMarkQueueSet::~SATBMarkQueueSet() { // remains set until the count is reduced to zero. // Increment count. If count > threshold, set flag, else maintain flag. -static void increment_count(volatile size_t* cfptr, size_t threshold) { +static void increment_count(Atomic* cfptr, size_t threshold) { size_t old; - size_t value = AtomicAccess::load(cfptr); + size_t value = cfptr->load_relaxed(); do { old = value; value += 2; assert(value > old, "overflow"); if (value > threshold) value |= 1; - value = AtomicAccess::cmpxchg(cfptr, old, value); + value = cfptr->compare_exchange(old, value); } while (value != old); } // Decrement count. If count == 0, clear flag, else maintain flag. -static void decrement_count(volatile size_t* cfptr) { +static void decrement_count(Atomic* cfptr) { size_t old; - size_t value = AtomicAccess::load(cfptr); + size_t value = cfptr->load_relaxed(); do { assert((value >> 1) != 0, "underflow"); old = value; value -= 2; if (value <= 1) value = 0; - value = AtomicAccess::cmpxchg(cfptr, old, value); + value = cfptr->compare_exchange(old, value); } while (value != old); } @@ -332,7 +331,7 @@ void SATBMarkQueueSet::print_all(const char* msg) { #endif // PRODUCT void SATBMarkQueueSet::abandon_completed_buffers() { - AtomicAccess::store(&_count_and_process_flag, size_t(0)); + _count_and_process_flag.store_relaxed(0u); BufferNode* buffers_to_delete = _list.pop_all(); while (buffers_to_delete != nullptr) { BufferNode* bn = buffers_to_delete; diff --git a/src/hotspot/share/gc/shared/satbMarkQueue.hpp b/src/hotspot/share/gc/shared/satbMarkQueue.hpp index e40b2a3ecf3..d2b14a3cc92 100644 --- a/src/hotspot/share/gc/shared/satbMarkQueue.hpp +++ b/src/hotspot/share/gc/shared/satbMarkQueue.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, 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 @@ #include "memory/allocation.hpp" #include "memory/padded.hpp" #include "oops/oopsHierarchy.hpp" +#include "runtime/atomic.hpp" class Thread; class Monitor; @@ -87,7 +88,7 @@ class SATBMarkQueueSet: public PtrQueueSet { DEFINE_PAD_MINUS_SIZE(1, DEFAULT_PADDING_SIZE, 0); PaddedEnd _list; - volatile size_t _count_and_process_flag; + Atomic _count_and_process_flag; // These are rarely (if ever) changed, so same cache line as count. size_t _process_completed_buffers_threshold; size_t _buffer_enqueue_threshold; @@ -148,12 +149,12 @@ public: // The number of buffers in the list. Racy and not updated atomically // with the set of completed buffers. size_t completed_buffers_num() const { - return _count_and_process_flag >> 1; + return _count_and_process_flag.load_relaxed() >> 1; } // Return true if completed buffers should be processed. bool process_completed_buffers() const { - return (_count_and_process_flag & 1) != 0; + return (_count_and_process_flag.load_relaxed() & 1) != 0; } #ifndef PRODUCT From 08c16c384ac9dac22da960ad718ceb95b41ca660 Mon Sep 17 00:00:00 2001 From: Jonas Norlinder Date: Fri, 28 Nov 2025 08:57:02 +0000 Subject: [PATCH 052/706] 8372704: ThreadMXBean.getThreadUserTime may return total time Reviewed-by: alanb, kevinw, dholmes --- .../share/classes/sun/management/ThreadImpl.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/java.management/share/classes/sun/management/ThreadImpl.java b/src/java.management/share/classes/sun/management/ThreadImpl.java index be54ced066d..a246e01dd63 100644 --- a/src/java.management/share/classes/sun/management/ThreadImpl.java +++ b/src/java.management/share/classes/sun/management/ThreadImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, 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 @@ -308,7 +308,7 @@ public class ThreadImpl implements ThreadMXBean { long id = ids[0]; Thread thread = Thread.currentThread(); if (id == thread.threadId()) { - times[0] = thread.isVirtual() ? -1L : getThreadTotalCpuTime0(0); + times[0] = thread.isVirtual() ? -1L : getThreadUserCpuTime0(0); } else { times[0] = getThreadUserCpuTime0(id); } From 78b155b2b5745fc88c13586f93b632f61e038a94 Mon Sep 17 00:00:00 2001 From: Volkan Yazici Date: Fri, 28 Nov 2025 12:05:17 +0000 Subject: [PATCH 053/706] 8372147: ConnectionFlowControlTest should use HttpResponse.connectionLabel() Reviewed-by: dfuchs --- .../net/httpclient/http2/ConnectionFlowControlTest.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/test/jdk/java/net/httpclient/http2/ConnectionFlowControlTest.java b/test/jdk/java/net/httpclient/http2/ConnectionFlowControlTest.java index 1eaf331c261..767d31f13e5 100644 --- a/test/jdk/java/net/httpclient/http2/ConnectionFlowControlTest.java +++ b/test/jdk/java/net/httpclient/http2/ConnectionFlowControlTest.java @@ -27,7 +27,7 @@ * @summary checks connection flow control * @library /test/lib /test/jdk/java/net/httpclient/lib * @build jdk.httpclient.test.lib.http2.Http2TestServer jdk.test.lib.net.SimpleSSLContext - * @run junit/othervm -Djdk.internal.httpclient.debug=true + * @run junit/othervm -Djdk.internal.httpclient.debug=err * -Djdk.httpclient.connectionWindowSize=65535 * -Djdk.httpclient.windowsize=16384 * ConnectionFlowControlTest @@ -122,7 +122,7 @@ public class ConnectionFlowControlTest { final HttpClient cc = client; var response = cc.send(request, BodyHandlers.ofInputStream()); responses.put(query, response); - String ckey = response.headers().firstValue("X-Connection-Key").get(); + String ckey = response.connectionLabel().get(); if (label == null) label = ckey; try { if (i < max - 1) { @@ -149,7 +149,7 @@ public class ConnectionFlowControlTest { try { String query = keys[i]; var response = responses.get(keys[i]); - String ckey = response.headers().firstValue("X-Connection-Key").get(); + String ckey = response.connectionLabel().get(); if (label == null) label = ckey; if (i < max - 1) { // the connection window might be exceeded at i == max - 2, which @@ -206,7 +206,7 @@ public class ConnectionFlowControlTest { System.out.println("\nSending last request:" + uriWithQuery); var response = client.send(request, BodyHandlers.ofString()); if (label != null) { - String ckey = response.headers().firstValue("X-Connection-Key").get(); + String ckey = response.connectionLabel().get(); assertNotEquals(label, ckey); System.out.printf("last request %s sent on different connection as expected:" + "\n\tlast: %s\n\tprevious: %s%n", query, ckey, label); @@ -281,7 +281,6 @@ public class ConnectionFlowControlTest { byte[] bytes = is.readAllBytes(); System.out.println("Server " + t.getLocalAddress() + " received:\n" + t.getRequestURI() + ": " + new String(bytes, StandardCharsets.UTF_8)); - t.getResponseHeaders().setHeader("X-Connection-Key", t.getConnectionKey()); if (bytes.length == 0) bytes = "no request body!".getBytes(StandardCharsets.UTF_8); int window = Math.max(16384, Integer.getInteger("jdk.httpclient.windowsize", 2*16*1024)); From e071afbfe4507b6b3a306f90bb645465fdab0070 Mon Sep 17 00:00:00 2001 From: Afshin Zafari Date: Fri, 28 Nov 2025 13:02:44 +0000 Subject: [PATCH 054/706] 8351334: [ubsan] memoryReserver.cpp:552:60: runtime error: applying non-zero offset 1073741824 to null pointer Reviewed-by: aboldtch, dholmes, jsjolen --- .../share/gc/shared/jvmFlagConstraintsGC.cpp | 2 +- src/hotspot/share/memory/memoryReserver.cpp | 51 ++++++++++--------- src/hotspot/share/runtime/arguments.cpp | 6 +-- 3 files changed, 31 insertions(+), 28 deletions(-) diff --git a/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.cpp b/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.cpp index cc446adba66..ea3d644d105 100644 --- a/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.cpp +++ b/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.cpp @@ -285,7 +285,7 @@ JVMFlag::Error SoftMaxHeapSizeConstraintFunc(size_t value, bool verbose) { JVMFlag::Error HeapBaseMinAddressConstraintFunc(size_t value, bool verbose) { // If an overflow happened in Arguments::set_heap_size(), MaxHeapSize will have too large a value. // Check for this by ensuring that MaxHeapSize plus the requested min base address still fit within max_uintx. - if (UseCompressedOops && FLAG_IS_ERGO(MaxHeapSize) && (value > (max_uintx - MaxHeapSize))) { + if (value > (max_uintx - MaxHeapSize)) { JVMFlag::printError(verbose, "HeapBaseMinAddress (%zu) or MaxHeapSize (%zu) is too large. " "Sum of them must be less than or equal to maximum of size_t (%zu)\n", diff --git a/src/hotspot/share/memory/memoryReserver.cpp b/src/hotspot/share/memory/memoryReserver.cpp index 11a0422f7b0..e8d1887f59f 100644 --- a/src/hotspot/share/memory/memoryReserver.cpp +++ b/src/hotspot/share/memory/memoryReserver.cpp @@ -437,7 +437,7 @@ ReservedSpace HeapReserver::Instance::try_reserve_range(char *highest_start, if (reserved.is_reserved()) { if (reserved.base() >= aligned_heap_base_min_address && - size <= (uintptr_t)(upper_bound - reserved.base())) { + size <= (size_t)(upper_bound - reserved.base())) { // Got a successful reservation. return reserved; } @@ -546,16 +546,16 @@ ReservedHeapSpace HeapReserver::Instance::reserve_compressed_oops_heap(const siz const size_t attach_point_alignment = lcm(alignment, os_attach_point_alignment); - char* aligned_heap_base_min_address = align_up((char*)HeapBaseMinAddress, alignment); - size_t noaccess_prefix = ((aligned_heap_base_min_address + size) > (char*)OopEncodingHeapMax) ? + uintptr_t aligned_heap_base_min_address = align_up(MAX2(HeapBaseMinAddress, alignment), alignment); + size_t noaccess_prefix = ((aligned_heap_base_min_address + size) > OopEncodingHeapMax) ? noaccess_prefix_size : 0; ReservedSpace reserved{}; // Attempt to alloc at user-given address. if (!FLAG_IS_DEFAULT(HeapBaseMinAddress)) { - reserved = try_reserve_memory(size + noaccess_prefix, alignment, page_size, aligned_heap_base_min_address); - if (reserved.base() != aligned_heap_base_min_address) { // Enforce this exact address. + reserved = try_reserve_memory(size + noaccess_prefix, alignment, page_size, (char*)aligned_heap_base_min_address); + if (reserved.base() != (char*)aligned_heap_base_min_address) { // Enforce this exact address. release(reserved); reserved = {}; } @@ -575,38 +575,41 @@ ReservedHeapSpace HeapReserver::Instance::reserve_compressed_oops_heap(const siz // Attempt to allocate so that we can run without base and scale (32-Bit unscaled compressed oops). // Give it several tries from top of range to bottom. - if (aligned_heap_base_min_address + size <= (char *)UnscaledOopHeapMax) { + if (aligned_heap_base_min_address + size <= UnscaledOopHeapMax) { // Calc address range within we try to attach (range of possible start addresses). - char* const highest_start = align_down((char *)UnscaledOopHeapMax - size, attach_point_alignment); - char* const lowest_start = align_up(aligned_heap_base_min_address, attach_point_alignment); - reserved = try_reserve_range(highest_start, lowest_start, attach_point_alignment, - aligned_heap_base_min_address, (char *)UnscaledOopHeapMax, size, alignment, page_size); + uintptr_t const highest_start = align_down(UnscaledOopHeapMax - size, attach_point_alignment); + uintptr_t const lowest_start = align_up(aligned_heap_base_min_address, attach_point_alignment); + assert(lowest_start <= highest_start, "lowest: " INTPTR_FORMAT " highest: " INTPTR_FORMAT , + lowest_start, highest_start); + reserved = try_reserve_range((char*)highest_start, (char*)lowest_start, attach_point_alignment, + (char*)aligned_heap_base_min_address, (char*)UnscaledOopHeapMax, size, alignment, page_size); } // zerobased: Attempt to allocate in the lower 32G. - char *zerobased_max = (char *)OopEncodingHeapMax; + const uintptr_t zerobased_max = OopEncodingHeapMax; // Give it several tries from top of range to bottom. if (aligned_heap_base_min_address + size <= zerobased_max && // Zerobased theoretical possible. ((!reserved.is_reserved()) || // No previous try succeeded. - (reserved.end() > zerobased_max))) { // Unscaled delivered an arbitrary address. + (reserved.end() > (char*)zerobased_max))) { // Unscaled delivered an arbitrary address. // Release previous reservation release(reserved); // Calc address range within we try to attach (range of possible start addresses). - char *const highest_start = align_down(zerobased_max - size, attach_point_alignment); + uintptr_t const highest_start = align_down(zerobased_max - size, attach_point_alignment); // Need to be careful about size being guaranteed to be less // than UnscaledOopHeapMax due to type constraints. - char *lowest_start = aligned_heap_base_min_address; - uint64_t unscaled_end = UnscaledOopHeapMax - size; - if (unscaled_end < UnscaledOopHeapMax) { // unscaled_end wrapped if size is large - lowest_start = MAX2(lowest_start, (char*)unscaled_end); + uintptr_t lowest_start = aligned_heap_base_min_address; + if (size < UnscaledOopHeapMax) { + lowest_start = MAX2(lowest_start, UnscaledOopHeapMax - size); } lowest_start = align_up(lowest_start, attach_point_alignment); - reserved = try_reserve_range(highest_start, lowest_start, attach_point_alignment, - aligned_heap_base_min_address, zerobased_max, size, alignment, page_size); + assert(lowest_start <= highest_start, "lowest: " INTPTR_FORMAT " highest: " INTPTR_FORMAT, + lowest_start, highest_start); + reserved = try_reserve_range((char*)highest_start, (char*)lowest_start, attach_point_alignment, + (char*)aligned_heap_base_min_address, (char*)zerobased_max, size, alignment, page_size); } // Now we go for heaps with base != 0. We need a noaccess prefix to efficiently @@ -616,17 +619,17 @@ ReservedHeapSpace HeapReserver::Instance::reserve_compressed_oops_heap(const siz // Try to attach at addresses that are aligned to OopEncodingHeapMax. Disjointbase mode. char** addresses = get_attach_addresses_for_disjoint_mode(); int i = 0; - while ((addresses[i] != nullptr) && // End of array not yet reached. - ((!reserved.is_reserved()) || // No previous try succeeded. - (reserved.end() > zerobased_max && // Not zerobased or unscaled address. - // Not disjoint address. + while ((addresses[i] != nullptr) && // End of array not yet reached. + ((!reserved.is_reserved()) || // No previous try succeeded. + (reserved.end() > (char*)zerobased_max && // Not zerobased or unscaled address. + // Not disjoint address. !CompressedOops::is_disjoint_heap_base_address((address)reserved.base())))) { // Release previous reservation release(reserved); char* const attach_point = addresses[i]; - assert(attach_point >= aligned_heap_base_min_address, "Flag support broken"); + assert((uintptr_t)attach_point >= aligned_heap_base_min_address, "Flag support broken"); reserved = try_reserve_memory(size + noaccess_prefix, alignment, page_size, attach_point); i++; } diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index 01fee949e33..4a983095593 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -1589,8 +1589,8 @@ void Arguments::set_heap_size() { } if (UseCompressedOops) { - size_t heap_end = HeapBaseMinAddress + MaxHeapSize; - size_t max_coop_heap = max_heap_for_compressed_oops(); + uintptr_t heap_end = HeapBaseMinAddress + MaxHeapSize; + uintptr_t max_coop_heap = max_heap_for_compressed_oops(); // Limit the heap size to the maximum possible when using compressed oops if (heap_end < max_coop_heap) { @@ -1607,7 +1607,7 @@ void Arguments::set_heap_size() { aot_log_info(aot)("UseCompressedOops disabled due to " "max heap %zu > compressed oop heap %zu. " "Please check the setting of MaxRAMPercentage %5.2f.", - reasonable_max, max_coop_heap, MaxRAMPercentage); + reasonable_max, (size_t)max_coop_heap, MaxRAMPercentage); FLAG_SET_ERGO(UseCompressedOops, false); } else { reasonable_max = max_coop_heap; From 52568bf4832b2bcc5dc547dbdf45a6a7172281fb Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Fri, 28 Nov 2025 22:50:18 +0000 Subject: [PATCH 055/706] 8372650: Convert GenericWaitBarrier to use Atomic Reviewed-by: shade, iwalulya --- .../share/utilities/waitBarrier_generic.cpp | 35 +++++++++---------- .../share/utilities/waitBarrier_generic.hpp | 9 ++--- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/hotspot/share/utilities/waitBarrier_generic.cpp b/src/hotspot/share/utilities/waitBarrier_generic.cpp index a6436d93ffc..b268b10c757 100644 --- a/src/hotspot/share/utilities/waitBarrier_generic.cpp +++ b/src/hotspot/share/utilities/waitBarrier_generic.cpp @@ -23,7 +23,6 @@ * */ -#include "runtime/atomicAccess.hpp" #include "runtime/orderAccess.hpp" #include "runtime/os.hpp" #include "utilities/spinYield.hpp" @@ -79,10 +78,10 @@ void GenericWaitBarrier::arm(int barrier_tag) { assert(barrier_tag != 0, "Pre arm: Should be arming with armed value"); - assert(AtomicAccess::load(&_barrier_tag) == 0, + assert(_barrier_tag.load_relaxed() == 0, "Pre arm: Should not be already armed. Tag: %d", - AtomicAccess::load(&_barrier_tag)); - AtomicAccess::release_store(&_barrier_tag, barrier_tag); + _barrier_tag.load_relaxed()); + _barrier_tag.release_store(barrier_tag); Cell &cell = tag_to_cell(barrier_tag); cell.arm(barrier_tag); @@ -92,9 +91,9 @@ void GenericWaitBarrier::arm(int barrier_tag) { } void GenericWaitBarrier::disarm() { - int barrier_tag = AtomicAccess::load_acquire(&_barrier_tag); + int barrier_tag = _barrier_tag.load_acquire(); assert(barrier_tag != 0, "Pre disarm: Should be armed. Tag: %d", barrier_tag); - AtomicAccess::release_store(&_barrier_tag, 0); + _barrier_tag.release_store(0); Cell &cell = tag_to_cell(barrier_tag); cell.disarm(barrier_tag); @@ -121,7 +120,7 @@ void GenericWaitBarrier::Cell::arm(int32_t requested_tag) { SpinYield sp; while (true) { - state = AtomicAccess::load_acquire(&_state); + state = _state.load_acquire(); assert(decode_tag(state) == 0, "Pre arm: Should not be armed. " "Tag: " INT32_FORMAT "; Waiters: " INT32_FORMAT, @@ -134,7 +133,7 @@ void GenericWaitBarrier::Cell::arm(int32_t requested_tag) { // Try to swing cell to armed. This should always succeed after the check above. int64_t new_state = encode(requested_tag, 0); - int64_t prev_state = AtomicAccess::cmpxchg(&_state, state, new_state); + int64_t prev_state = _state.compare_exchange(state, new_state); if (prev_state != state) { fatal("Cannot arm the wait barrier. " "Tag: " INT32_FORMAT "; Waiters: " INT32_FORMAT, @@ -145,14 +144,14 @@ void GenericWaitBarrier::Cell::arm(int32_t requested_tag) { int GenericWaitBarrier::Cell::signal_if_needed(int max) { int signals = 0; while (true) { - int cur = AtomicAccess::load_acquire(&_outstanding_wakeups); + int cur = _outstanding_wakeups.load_acquire(); if (cur == 0) { // All done, no more waiters. return 0; } assert(cur > 0, "Sanity"); - int prev = AtomicAccess::cmpxchg(&_outstanding_wakeups, cur, cur - 1); + int prev = _outstanding_wakeups.compare_exchange(cur, cur - 1); if (prev != cur) { // Contention, return to caller for early return or backoff. return prev; @@ -172,7 +171,7 @@ void GenericWaitBarrier::Cell::disarm(int32_t expected_tag) { int32_t waiters; while (true) { - int64_t state = AtomicAccess::load_acquire(&_state); + int64_t state = _state.load_acquire(); int32_t tag = decode_tag(state); waiters = decode_waiters(state); @@ -182,7 +181,7 @@ void GenericWaitBarrier::Cell::disarm(int32_t expected_tag) { tag, waiters); int64_t new_state = encode(0, waiters); - if (AtomicAccess::cmpxchg(&_state, state, new_state) == state) { + if (_state.compare_exchange(state, new_state) == state) { // Successfully disarmed. break; } @@ -191,19 +190,19 @@ void GenericWaitBarrier::Cell::disarm(int32_t expected_tag) { // Wake up waiters, if we have at least one. // Allow other threads to assist with wakeups, if possible. if (waiters > 0) { - AtomicAccess::release_store(&_outstanding_wakeups, waiters); + _outstanding_wakeups.release_store(waiters); SpinYield sp; while (signal_if_needed(INT_MAX) > 0) { sp.wait(); } } - assert(AtomicAccess::load(&_outstanding_wakeups) == 0, "Post disarm: Should not have outstanding wakeups"); + assert(_outstanding_wakeups.load_relaxed() == 0, "Post disarm: Should not have outstanding wakeups"); } void GenericWaitBarrier::Cell::wait(int32_t expected_tag) { // Try to register ourselves as pending waiter. while (true) { - int64_t state = AtomicAccess::load_acquire(&_state); + int64_t state = _state.load_acquire(); int32_t tag = decode_tag(state); if (tag != expected_tag) { // Cell tag had changed while waiting here. This means either the cell had @@ -219,7 +218,7 @@ void GenericWaitBarrier::Cell::wait(int32_t expected_tag) { tag, waiters); int64_t new_state = encode(tag, waiters + 1); - if (AtomicAccess::cmpxchg(&_state, state, new_state) == state) { + if (_state.compare_exchange(state, new_state) == state) { // Success! Proceed to wait. break; } @@ -238,7 +237,7 @@ void GenericWaitBarrier::Cell::wait(int32_t expected_tag) { // Register ourselves as completed waiter before leaving. while (true) { - int64_t state = AtomicAccess::load_acquire(&_state); + int64_t state = _state.load_acquire(); int32_t tag = decode_tag(state); int32_t waiters = decode_waiters(state); @@ -248,7 +247,7 @@ void GenericWaitBarrier::Cell::wait(int32_t expected_tag) { tag, waiters); int64_t new_state = encode(tag, waiters - 1); - if (AtomicAccess::cmpxchg(&_state, state, new_state) == state) { + if (_state.compare_exchange(state, new_state) == state) { // Success! break; } diff --git a/src/hotspot/share/utilities/waitBarrier_generic.hpp b/src/hotspot/share/utilities/waitBarrier_generic.hpp index 8ed9ef3ac6e..0cbba1041db 100644 --- a/src/hotspot/share/utilities/waitBarrier_generic.hpp +++ b/src/hotspot/share/utilities/waitBarrier_generic.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, 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 @@ #include "memory/allocation.hpp" #include "memory/padded.hpp" +#include "runtime/atomic.hpp" #include "runtime/semaphore.hpp" #include "utilities/globalDefinitions.hpp" @@ -43,10 +44,10 @@ private: Semaphore _sem; // Cell state, tracks the arming + waiters status - volatile int64_t _state; + Atomic _state; // Wakeups to deliver for current waiters - volatile int _outstanding_wakeups; + Atomic _outstanding_wakeups; int signal_if_needed(int max); @@ -83,7 +84,7 @@ private: // Trailing padding to protect the last cell. DEFINE_PAD_MINUS_SIZE(0, DEFAULT_PADDING_SIZE, 0); - volatile int _barrier_tag; + Atomic _barrier_tag; // Trailing padding to insulate the rest of the barrier from adjacent // data structures. The leading padding is not needed, as cell padding From 92e1357dfd2d874ef1a62ddd69c86a7bb189c6a2 Mon Sep 17 00:00:00 2001 From: Jaikiran Pai Date: Sat, 29 Nov 2025 01:25:25 +0000 Subject: [PATCH 056/706] 8371802: Do not let QUIC connection to idle terminate when HTTP/3 is configured with a higher idle timeout Reviewed-by: dfuchs --- .../internal/net/http/Http3Connection.java | 68 +++- .../net/http/Http3ConnectionPool.java | 29 +- .../net/http/quic/ConnectionTerminator.java | 70 +++- .../http/quic/ConnectionTerminatorImpl.java | 12 +- .../net/http/quic/IdleTimeoutManager.java | 316 +++++++++++++----- .../net/http/quic/QuicConnectionImpl.java | 4 +- .../net/http/quic/QuicTimedEvent.java | 3 +- .../http3/H3IdleExceedsQuicIdleTimeout.java | 178 ++++++++++ 8 files changed, 579 insertions(+), 101 deletions(-) create mode 100644 test/jdk/java/net/httpclient/http3/H3IdleExceedsQuicIdleTimeout.java diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/Http3Connection.java b/src/java.net.http/share/classes/jdk/internal/net/http/Http3Connection.java index b97a441881d..17f230f3b15 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/Http3Connection.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/Http3Connection.java @@ -126,11 +126,16 @@ public final class Http3Connection implements AutoCloseable { // as per spec // -1 is used to imply no GOAWAY received so far private final AtomicLong lowestGoAwayReceipt = new AtomicLong(-1); + + private final Duration idleTimeoutDuration; private volatile IdleConnectionTimeoutEvent idleConnectionTimeoutEvent; // value of true implies no more streams will be initiated on this connection, // and the connection will be closed once the in-progress streams complete. private volatile boolean finalStream; private volatile boolean allowOnlyOneStream; + // true if this connection has been placed in the HTTP/3 connection pool of the HttpClient. + // false otherwise. + private volatile boolean presentInConnPool; // set to true if we decide to open a new connection // due to stream limit reached private volatile boolean streamLimitReached; @@ -220,6 +225,17 @@ public final class Http3Connection implements AutoCloseable { // in case of exception. Throws in the dependent // action after wrapping the exception if needed. .exceptionally(this::exceptionallyAndClose); + + this.idleTimeoutDuration = client.client().idleConnectionTimeout(HTTP_3).orElse(null); + if (idleTimeoutDuration == null) { + // The absence of HTTP/3 idle timeout duration is considered to mean + // never idle terminating the connection + quicConnection.connectionTerminator().appLayerMaxIdle(Duration.MAX, + this::isQUICTrafficGenerationRequired); + } else { + quicConnection.connectionTerminator().appLayerMaxIdle(idleTimeoutDuration, + this::isQUICTrafficGenerationRequired); + } if (Log.http3()) { Log.logHttp3("HTTP/3 connection created for " + quicConnectionTag() + " - local address: " + quicConnection.localAddress()); @@ -732,9 +748,8 @@ public final class Http3Connection implements AutoCloseable { try { var te = idleConnectionTimeoutEvent; if (te == null && exchangeStreams.isEmpty()) { - te = idleConnectionTimeoutEvent = client.client().idleConnectionTimeout(HTTP_3) - .map(IdleConnectionTimeoutEvent::new).orElse(null); - if (te != null) { + if (idleTimeoutDuration != null) { + te = idleConnectionTimeoutEvent = new IdleConnectionTimeoutEvent(); client.client().registerTimer(te); } } @@ -873,6 +888,48 @@ public final class Http3Connection implements AutoCloseable { } } + /** + * Mark this connection as being present or absent from the connection pool. + */ + void setPooled(final boolean present) { + this.presentInConnPool = present; + } + + /** + * This callback method is invoked by the QUIC layer when it notices that this + * connection hasn't seen any traffic for certain period of time. QUIC + * invokes this method to ask HTTP/3 whether the QUIC layer + * should generate traffic to keep this connection active. + * This method returns true, indicating that the traffic must be generated, + * if this HTTP/3 connection is in pool and there's no current request/response + * in progress over this connection (i.e. the HTTP/3 connection is idle in the + * pool waiting for any new requests to be issued by the application). + */ + private boolean isQUICTrafficGenerationRequired() { + if (!isOpen()) { + return false; + } + lock(); + try { + // if there's no HTTP/3 request/responses in progress and the connection is + // in the pool (thus idle), then we instruct QUIC to generate traffic on the + // QUIC connection to prevent it from being idle terminated. + final boolean generateTraffic = this.presentInConnPool + && this.exchanges.isEmpty() + && this.reservedStreamCount.get() == 0 + // a connection in the pool could be marked as + // finalStream (for example when it receives a GOAWAY). we don't want + // to generate explicit QUIC traffic for such connections too. + && !this.finalStream; + if (debug.on()) { + debug.log("QUIC traffic generation required = " + generateTraffic); + } + return generateTraffic; + } finally { + unlock(); + } + } + /** * Cancels any event that might have been scheduled to shutdown this connection. Must be called * with the stateLock held. @@ -893,8 +950,9 @@ public final class Http3Connection implements AutoCloseable { private boolean cancelled; private boolean idleShutDownInitiated; - IdleConnectionTimeoutEvent(Duration duration) { - super(duration); + IdleConnectionTimeoutEvent() { + assert idleTimeoutDuration != null : "idle timeout duration is null"; + super(idleTimeoutDuration); } @Override diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/Http3ConnectionPool.java b/src/java.net.http/share/classes/jdk/internal/net/http/Http3ConnectionPool.java index eaacd8213cb..0f1fe2b7abf 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/Http3ConnectionPool.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/Http3ConnectionPool.java @@ -155,23 +155,34 @@ class Http3ConnectionPool { assert key.equals(c.key()); var altService = c.connection().getSourceAltService().orElse(null); if (altService != null && altService.wasAdvertised()) { - return advertised.putIfAbsent(key, c); + final var prev = advertised.putIfAbsent(key, c); + if (prev == null) { + c.setPooled(true); // mark the newly pooled connection as pooled + } + return prev; } assert altService == null || altService.originHasSameAuthority(); - return unadvertised.putIfAbsent(key, c); + final var prev = unadvertised.putIfAbsent(key, c); + if (prev == null) { + c.setPooled(true); // mark the newly pooled connection as pooled + } + return prev; } - Http3Connection put(String key, Http3Connection c) { + void put(String key, Http3Connection c) { Objects.requireNonNull(key); Objects.requireNonNull(c); assert key.equals(c.key()) : "key mismatch %s -> %s" .formatted(key, c.key()); var altService = c.connection().getSourceAltService().orElse(null); if (altService != null && altService.wasAdvertised()) { - return advertised.put(key, c); + advertised.put(key, c); + c.setPooled(true); + return; } assert altService == null || altService.originHasSameAuthority(); - return unadvertised.put(key, c); + unadvertised.put(key, c); + c.setPooled(true); } boolean remove(String key, Http3Connection c) { @@ -189,11 +200,17 @@ class Http3ConnectionPool { } assert altService == null || altService.originHasSameAuthority(); - return unadvertised.remove(key, c); + final boolean removed = unadvertised.remove(key, c); + if (removed) { + c.setPooled(false); + } + return removed; } void clear() { + advertised.values().forEach((c) -> c.setPooled(false)); advertised.clear(); + unadvertised.values().forEach((c) -> c.setPooled(false)); unadvertised.clear(); } diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/quic/ConnectionTerminator.java b/src/java.net.http/share/classes/jdk/internal/net/http/quic/ConnectionTerminator.java index 24230a0883d..14559db4a11 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/quic/ConnectionTerminator.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/quic/ConnectionTerminator.java @@ -24,15 +24,77 @@ */ package jdk.internal.net.http.quic; -// responsible for managing the connection termination of a QUIC connection +import java.time.Duration; +import java.util.function.Supplier; + +/** + * Responsible for managing the connection termination of a QUIC connection + */ public sealed interface ConnectionTerminator permits ConnectionTerminatorImpl { - // lets the terminator know that the connection is still alive and should not be - // idle timed out - void keepAlive(); + /** + * Instructs the connection terminator to consider the connection as active + * at the present point in time. The connection terminator will then restart its + * idle timeout timer from this point in time. + *

    + * This method must be called when an incoming packet is processed successfully + * or when an ack-eliciting packet is sent by the local endpoint on the connection. + */ + void markActive(); + /** + * Terminates the connection, if not already terminated, with the given cause. + *

    + * A connection is terminated only once with a {@link TerminationCause}. However, this method + * can be called any number of times. If the connection is not already terminated, + * then this method does the necessary work to terminate the connection. Any subsequent + * invocations of this method, after the connection has been terminated, will not + * change the termination cause of the connection. + * + * @param cause the termination cause + */ void terminate(TerminationCause cause); + /** + * Returns {@code true} if the connection is allowed for use, {@code false} otherwise. + *

    + * This method is typically called when a connection that has been idle, is about to be used + * for handling some request. This method allows for co-ordination between the connection usage + * and the connection terminator to prevent the connection from being idle timed out when it is + * about to be used for some request. The connection must only be used if this method + * returns {@code true}. + * + * @return true if the connection can be used, false otherwise + */ boolean tryReserveForUse(); + /** + * Instructs the connection terminator that the application layer allows the + * connection to stay idle for the given {@code maxIdle} duration. If the QUIC + * layer has negotiated an idle timeout for the connection, that's lower than + * the application's {@code maxIdle} duration, then the connection terminator + * upon noticing absence of traffic over the connection for certain duration, + * calls the {@code trafficGenerationCheck} to check if the QUIC layer should + * explicitly generate some traffic to prevent the connection + * from idle terminating. + *

    + * When the {@code trafficGenerationCheck} is invoked, the application layer + * must return {@code true} only if explicit traffic generation is necessary + * to keep the connection alive. + *

    + * If the application layer wishes to never idle terminate the connection, then + * a {@code maxIdle} duration of {@linkplain Duration#MAX Duration.MAX} is recommended. + * + * @param maxIdle the maximum idle duration of the connection, + * at the application layer + * @param trafficGenerationCheck the callback that will be invoked by the connection + * terminator to decide if the QUIC layer should generate + * any traffic to prevent the connection from idle terminating + * @throws NullPointerException if either {@code maxIdle} or {@code trafficGenerationCheck} + * is null + * @throws IllegalArgumentException if {@code maxIdle} is + * {@linkplain Duration#isNegative() negative} or + * {@linkplain Duration#isZero() zero} + */ + void appLayerMaxIdle(Duration maxIdle, Supplier trafficGenerationCheck); } diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/quic/ConnectionTerminatorImpl.java b/src/java.net.http/share/classes/jdk/internal/net/http/quic/ConnectionTerminatorImpl.java index 0f5aa4cb7ac..7870f4f1d8e 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/quic/ConnectionTerminatorImpl.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/quic/ConnectionTerminatorImpl.java @@ -25,11 +25,13 @@ package jdk.internal.net.http.quic; import java.nio.ByteBuffer; +import java.time.Duration; import java.util.List; import java.util.Objects; import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Function; +import java.util.function.Supplier; import jdk.internal.net.http.common.Log; import jdk.internal.net.http.common.Logger; @@ -52,7 +54,6 @@ import static jdk.internal.net.http.quic.QuicConnectionImpl.QuicConnectionState. import static jdk.internal.net.http.quic.TerminationCause.appLayerClose; import static jdk.internal.net.http.quic.TerminationCause.forSilentTermination; import static jdk.internal.net.http.quic.TerminationCause.forTransportError; -import static jdk.internal.net.quic.QuicTransportErrors.INTERNAL_ERROR; import static jdk.internal.net.quic.QuicTransportErrors.NO_ERROR; final class ConnectionTerminatorImpl implements ConnectionTerminator { @@ -70,8 +71,8 @@ final class ConnectionTerminatorImpl implements ConnectionTerminator { } @Override - public void keepAlive() { - this.connection.idleTimeoutManager.keepAlive(); + public void markActive() { + this.connection.idleTimeoutManager.markActive(); } @Override @@ -79,6 +80,11 @@ final class ConnectionTerminatorImpl implements ConnectionTerminator { return this.connection.idleTimeoutManager.tryReserveForUse(); } + @Override + public void appLayerMaxIdle(final Duration maxIdle, final Supplier trafficGenerationCheck) { + this.connection.idleTimeoutManager.appLayerMaxIdle(maxIdle, trafficGenerationCheck); + } + @Override public void terminate(final TerminationCause cause) { Objects.requireNonNull(cause); diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/quic/IdleTimeoutManager.java b/src/java.net.http/share/classes/jdk/internal/net/http/quic/IdleTimeoutManager.java index 72ce0290038..375a0dc8e16 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/quic/IdleTimeoutManager.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/quic/IdleTimeoutManager.java @@ -24,12 +24,15 @@ */ package jdk.internal.net.http.quic; +import java.time.Duration; import java.util.Objects; import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.locks.ReentrantLock; +import java.util.function.Supplier; import jdk.internal.net.http.common.Deadline; import jdk.internal.net.http.common.Log; @@ -58,17 +61,21 @@ final class IdleTimeoutManager { private IdleTimeoutEvent idleTimeoutEvent; // must be accessed only when holding stateLock private StreamDataBlockedEvent streamDataBlockedEvent; - // the time at which the last outgoing packet was sent or an + // the time (in nanos) at which the last outgoing packet was sent or an // incoming packet processed on the connection - private volatile long lastPacketActivityAt; + private volatile long lastPacketActivityNanos; private final ReentrantLock idleTerminationLock = new ReentrantLock(); // true if it has been decided to terminate the connection due to being idle, // false otherwise. should be accessed only when holding the idleTerminationLock private boolean chosenForIdleTermination; - // the time at which the connection was last reserved for use. + // the time (in nanos) at which the connection was last reserved for use. // should be accessed only when holding the idleTerminationLock - private long lastUsageReservationAt; + private long lastUsageReservationNanos; + + private final AtomicReference> trafficGenerationCheck = new AtomicReference<>(); + // must be accessed only when holding stateLock + private PingEvent pingEvent; IdleTimeoutManager(final QuicConnectionImpl connection) { this.connection = Objects.requireNonNull(connection, "connection"); @@ -79,28 +86,12 @@ final class IdleTimeoutManager { * Starts the idle timeout management for the connection. This should be called * after the handshake is complete for the connection. * - * @throw IllegalStateException if handshake hasn't yet completed or if the handshake - * has failed for the connection + * @throws IllegalStateException if handshake hasn't yet completed or if the handshake + * has failed for the connection */ void start() { - final CompletableFuture handshakeCF = - this.connection.handshakeFlow().handshakeCF(); // start idle management only for successfully completed handshake - if (!handshakeCF.isDone()) { - throw new IllegalStateException("handshake isn't yet complete," - + " cannot start idle connection management"); - } - if (handshakeCF.isCompletedExceptionally()) { - throw new IllegalStateException("cannot start idle connection management for a failed" - + " connection"); - } - startTimers(); - } - - /** - * Starts the idle timeout timer of the QUIC connection, if not already started. - */ - private void startTimers() { + requireSuccessfulHandshake(); if (shutdown.get()) { return; } @@ -116,6 +107,19 @@ final class IdleTimeoutManager { } } + private void requireSuccessfulHandshake() { + final CompletableFuture handshakeCF = + this.connection.handshakeFlow().handshakeCF(); + if (!handshakeCF.isDone()) { + throw new IllegalStateException("handshake isn't yet complete," + + " cannot use idle connection management"); + } + if (handshakeCF.isCompletedExceptionally()) { + throw new IllegalStateException("cannot use idle connection management for a failed" + + " connection"); + } + } + private void startIdleTerminationTimer() { assert stateLock.isHeldByCurrentThread() : "not holding state lock"; final Optional idleTimeoutMillis = getIdleTimeout(); @@ -154,18 +158,14 @@ final class IdleTimeoutManager { } final QuicEndpoint endpoint = this.connection.endpoint(); assert endpoint != null : "QUIC endpoint is null"; - // disable the event (refreshDeadline() of IdleTimeoutEvent will return Deadline.MAX) - final Deadline nextDeadline = this.idleTimeoutEvent.nextDeadline; - if (!nextDeadline.equals(Deadline.MAX)) { - this.idleTimeoutEvent.nextDeadline = Deadline.MAX; - endpoint.timer().reschedule(this.idleTimeoutEvent, Deadline.MIN); - } + // disable the idle timeout timer event + disableTimedEvent(endpoint.timer(), this.idleTimeoutEvent); this.idleTimeoutEvent = null; } private void startStreamDataBlockedTimer() { assert stateLock.isHeldByCurrentThread() : "not holding state lock"; - // 75% of idle timeout or if idle timeout is not configured, then 30 seconds + // 75% of QUIC idle timeout or if QUIC idle timeout is not configured, then 30 seconds final long timeoutMillis = getIdleTimeout() .map((v) -> (long) (0.75 * v)) .orElse(30000L); @@ -194,22 +194,95 @@ final class IdleTimeoutManager { } final QuicEndpoint endpoint = this.connection.endpoint(); assert endpoint != null : "QUIC endpoint is null"; - // disable the event (refreshDeadline() of StreamDataBlockedEvent will return Deadline.MAX) - final Deadline nextDeadline = this.streamDataBlockedEvent.nextDeadline; - if (!nextDeadline.equals(Deadline.MAX)) { - this.streamDataBlockedEvent.nextDeadline = Deadline.MAX; - endpoint.timer().reschedule(this.streamDataBlockedEvent, Deadline.MIN); - } + // disable the stream data blocked timer event + disableTimedEvent(endpoint.timer(), this.streamDataBlockedEvent); this.streamDataBlockedEvent = null; } + // set up a PING timer if the application layer's max idle duration for the connection + // is larger than that of the negotiated QUIC idle timeout for that connection + void appLayerMaxIdle(final Duration maxIdle, final Supplier trafficGenerationCheck) { + Objects.requireNonNull(maxIdle, "maxIdle"); + Objects.requireNonNull(trafficGenerationCheck, "trafficGenerationCheck"); + if (maxIdle.isZero() || maxIdle.isNegative()) { + throw new IllegalArgumentException("invalid maxIdle duration: " + maxIdle); + } + // the application layer must not configure its max idle duration + // until the QUIC connection's handshake has successfully completed + requireSuccessfulHandshake(); + + if (!this.trafficGenerationCheck.compareAndSet(null, trafficGenerationCheck)) { + throw new IllegalStateException("app layer max inactivity already set"); + } + final Optional quicIdleTimeout = getIdleTimeout(); + if (quicIdleTimeout.isEmpty()) { + // the QUIC connection will never idle timeout, nothing more to do + return; + } + // we start the PING sending timer event only if the QUIC layer idle timeout + // is lesser than the app layer's desired idle time + if (Duration.ofMillis(quicIdleTimeout.get()).compareTo(maxIdle) < 0) { + this.stateLock.lock(); + try { + if (shutdown.get()) { + return; + } + // QUIC connection has a lower idle timeout than the app layer. start a timer + // which checks with the app layer at regular intervals to decide whether to + // send a PING to keep the QUIC connection active. + startPingTimer(); + } finally { + this.stateLock.unlock(); + } + } + } + + private void startPingTimer() { + assert stateLock.isHeldByCurrentThread() : "not holding state lock"; + // we don't expect the timer to be started more than once + assert this.pingEvent == null : "PING timer already started"; + final Optional quicIdleTimeout = getIdleTimeout(); + assert quicIdleTimeout.isPresent() : "QUIC idle timeout is disabled, no need to start PING timer"; + // potential PING generation every 75% of QUIC idle timeout + final long pingFrequencyMillis = (long) (0.75 * quicIdleTimeout.get()); + assert pingFrequencyMillis > 0 : "unexpected ping frequency: " + pingFrequencyMillis; + final QuicTimerQueue timerQueue = connection.endpoint().timer(); + final Deadline deadline = timeLine().instant().plusMillis(pingFrequencyMillis); + // create the timeout event and register with the QuicTimerQueue. + this.pingEvent = new PingEvent(deadline, pingFrequencyMillis); + timerQueue.offer(this.pingEvent); + if (debug.on()) { + debug.log("started periodic PING for connection," + + " ping event: " + this.pingEvent + + " deadline: " + deadline); + } else { + Log.logQuic("{0} started periodic PING for connection," + + " ping event: {1} deadline: {2}", + connection.logTag(), this.pingEvent, deadline); + } + } + + private void stopPingTimer() { + assert stateLock.isHeldByCurrentThread() : "not holding state lock"; + if (this.pingEvent == null) { + return; + } + final QuicEndpoint endpoint = this.connection.endpoint(); + assert endpoint != null : "QUIC endpoint is null"; + // disable the ping timer event + disableTimedEvent(endpoint.timer(), this.pingEvent); + this.pingEvent = null; + this.trafficGenerationCheck.set(null); + } + + /** * Attempts to notify the idle connection management that this connection should * be considered "in use". This way the idle connection management doesn't close * this connection during the time the connection is handed out from the pool and any * new stream created on that connection. * - * @return true if the connection has been successfully reserved and is {@link #isOpen()}. false + * @return true if the connection has been successfully reserved. false * otherwise; in which case the connection must not be handed out from the pool. */ boolean tryReserveForUse() { @@ -221,7 +294,7 @@ final class IdleTimeoutManager { } // if the connection is nearing idle timeout due to lack of traffic then // don't use it - final long lastPktActivity = lastPacketActivityAt; + final long lastPktActivity = lastPacketActivityNanos; final long currentNanos = System.nanoTime(); final long inactivityMs = MILLISECONDS.convert((currentNanos - lastPktActivity), NANOSECONDS); @@ -232,7 +305,7 @@ final class IdleTimeoutManager { return false; } // express interest in using the connection - this.lastUsageReservationAt = System.nanoTime(); + this.lastUsageReservationNanos = System.nanoTime(); return true; } finally { this.idleTerminationLock.unlock(); @@ -256,8 +329,9 @@ final class IdleTimeoutManager { return val == NO_IDLE_TIMEOUT ? Optional.empty() : Optional.of(val); } - void keepAlive() { - lastPacketActivityAt = System.nanoTime(); // TODO: timeline().instant()? + // consider the connection as active as of this moment + void markActive() { + lastPacketActivityNanos = System.nanoTime(); // TODO: timeline().instant()? } void shutdown() { @@ -270,6 +344,7 @@ final class IdleTimeoutManager { // unregister the timeout events from the QuicTimerQueue stopIdleTerminationTimer(); stopStreamDataBlockedTimer(); + stopPingTimer(); } finally { this.stateLock.unlock(); } @@ -318,6 +393,15 @@ final class IdleTimeoutManager { return this.connection.endpoint().timeSource(); } + private static void disableTimedEvent(final QuicTimerQueue timer, final TimedEvent te) { + // disable the event (refreshDeadline() of TimedEvent will return Deadline.MAX) + final Deadline nextDeadline = te.nextDeadline; + if (!nextDeadline.equals(Deadline.MAX)) { + te.nextDeadline = Deadline.MAX; + timer.reschedule(te, Deadline.MIN); + } + } + // called when the connection has been idle past its idle timeout duration private void idleTimedOut() { if (shutdown.get()) { @@ -354,35 +438,51 @@ final class IdleTimeoutManager { } private long computeInactivityMillis() { + assert idleTerminationLock.isHeldByCurrentThread() : "not holding idle termination lock"; final long currentNanos = System.nanoTime(); - final long lastActiveNanos = Math.max(lastPacketActivityAt, lastUsageReservationAt); + final long lastActiveNanos = Math.max(lastPacketActivityNanos, lastUsageReservationNanos); return MILLISECONDS.convert((currentNanos - lastActiveNanos), NANOSECONDS); } - final class IdleTimeoutEvent implements QuicTimedEvent { - private final long eventId; - private volatile Deadline deadline; - private volatile Deadline nextDeadline; + sealed abstract class TimedEvent implements QuicTimedEvent { + protected final long eventId; + protected volatile Deadline deadline; + protected volatile Deadline nextDeadline; - private IdleTimeoutEvent(final Deadline deadline) { + private TimedEvent(final Deadline deadline) { assert deadline != null : "timeout deadline is null"; this.deadline = this.nextDeadline = deadline; this.eventId = QuicTimerQueue.newEventId(); } @Override - public Deadline deadline() { + public final Deadline deadline() { return this.deadline; } @Override - public Deadline refreshDeadline() { + public final Deadline refreshDeadline() { if (shutdown.get()) { return this.deadline = this.nextDeadline = Deadline.MAX; } return this.deadline = this.nextDeadline; } + @Override + public final long eventId() { + return this.eventId; + } + + @Override + public abstract Deadline handle(); + } + + final class IdleTimeoutEvent extends TimedEvent { + + private IdleTimeoutEvent(final Deadline deadline) { + super(deadline); + } + @Override public Deadline handle() { if (shutdown.get()) { @@ -442,41 +542,18 @@ final class IdleTimeoutManager { } } - @Override - public long eventId() { - return this.eventId; - } - @Override public String toString() { return "QuicIdleTimeoutEvent-" + this.eventId; } } - final class StreamDataBlockedEvent implements QuicTimedEvent { - private final long eventId; + final class StreamDataBlockedEvent extends TimedEvent { private final long timeoutMillis; - private volatile Deadline deadline; - private volatile Deadline nextDeadline; private StreamDataBlockedEvent(final Deadline deadline, final long timeoutMillis) { - assert deadline != null : "timeout deadline is null"; - this.deadline = this.nextDeadline = deadline; + super(deadline); this.timeoutMillis = timeoutMillis; - this.eventId = QuicTimerQueue.newEventId(); - } - - @Override - public Deadline deadline() { - return this.deadline; - } - - @Override - public Deadline refreshDeadline() { - if (shutdown.get()) { - return this.deadline = this.nextDeadline = Deadline.MAX; - } - return this.deadline = this.nextDeadline; } @Override @@ -517,14 +594,95 @@ final class IdleTimeoutManager { } } - @Override - public long eventId() { - return this.eventId; - } - @Override public String toString() { return "StreamDataBlockedEvent-" + this.eventId; } } + + + final class PingEvent extends TimedEvent { + private final long pingFrequencyNanos; + private final long idleTimeoutNanos; + + private PingEvent(final Deadline deadline, final long pingFrequencyMillis) { + super(deadline); + this.pingFrequencyNanos = MILLISECONDS.toNanos(pingFrequencyMillis); + if (this.pingFrequencyNanos <= 0) { + throw new IllegalArgumentException("ping frequency is too small: " + + pingFrequencyMillis + " milliseconds"); + } + this.idleTimeoutNanos = MILLISECONDS.toNanos(getIdleTimeout().get()); + } + + @Override + public Deadline handle() { + if (shutdown.get()) { + // timeout manager is shutdown, nothing more to do + return this.nextDeadline = Deadline.MAX; + } + if (!shouldInitiateAppLayerCheck()) { + // reschedule for next round + this.nextDeadline = timeLine().instant().plusNanos(this.pingFrequencyNanos); + return this.nextDeadline; + } + // check with the app layer if traffic generation is required + final Supplier check = trafficGenerationCheck.get(); + if (check == null) { + // generateTrafficCheck can be null if the timeout manager was shutdown + // when this event handling was in progress. don't send a PING frame + // in that case. + assert shutdown.get() : "trafficGenerationCheck is absent"; + return this.nextDeadline = Deadline.MAX; + } + if (check.get()) { + // app layer OKed sending a PING + connection.requestSendPing(); + if (debug.on()) { + debug.log("enqueued a PING frame"); + } else { + Log.logQuic("{0} enqueued a PING frame", connection.logTag()); + } + } else { + // app layer told us not to send a PING. + // we skip the PING generation only for the current round, no need + // to disable future PING checks + if (debug.on()) { + debug.log("skipping PING generation"); + } else { + Log.logQuic("{0} skipping PING generation", connection.logTag()); + } + } + this.nextDeadline = timeLine().instant().plusNanos(this.pingFrequencyNanos); + return this.nextDeadline; + } + + @Override + public String toString() { + return "PingEvent-" + this.eventId; + } + + // returns true if the app layer traffic generation check needs to be invoked, + // false otherwise. + private boolean shouldInitiateAppLayerCheck() { + final long lastPktAt = lastPacketActivityNanos; + final long now = System.nanoTime(); + if ((now - lastPktAt) >= this.pingFrequencyNanos) { + // no traffic during the ping interval, initiate a app layer check + // to see if explicit traffic needs to be generated + return true; + } + // check if the connection will potentially idle terminate before the next + // ping check is scheduled, if yes, then initiate a app layer traffic + // generation check now + final long idleTerminationAt = lastPktAt + this.idleTimeoutNanos; + final long nextPingCheck = now + this.pingFrequencyNanos; + if (idleTerminationAt - nextPingCheck <= 0) { + return true; + } + // connection appears to be receiving traffic, no need to initiate app layer + // traffic generation check + return false; + } + } } diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicConnectionImpl.java b/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicConnectionImpl.java index d90ad1b217e..240f90852bc 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicConnectionImpl.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicConnectionImpl.java @@ -1987,7 +1987,7 @@ public class QuicConnectionImpl extends QuicConnection implements QuicPacketRece case NONE -> throw new InternalError("Unrecognized packet type"); } // packet has been processed successfully - connection isn't idle (RFC-9000, section 10.1) - this.terminator.keepAlive(); + this.terminator.markActive(); if (packetSpace != null) { packetSpace.packetReceived( packetType, @@ -2819,7 +2819,7 @@ public class QuicConnectionImpl extends QuicConnection implements QuicPacketRece // RFC-9000, section 10.1: An endpoint also restarts its idle timer when sending // an ack-eliciting packet ... if (packet.isAckEliciting()) { - this.terminator.keepAlive(); + this.terminator.markActive(); } } diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicTimedEvent.java b/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicTimedEvent.java index 9269b12bf64..ac885c1950e 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicTimedEvent.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicTimedEvent.java @@ -45,8 +45,7 @@ sealed interface QuicTimedEvent permits PacketSpaceManager.PacketTransmissionTask, QuicTimerQueue.Marker, QuicEndpoint.ClosedConnection, - IdleTimeoutManager.IdleTimeoutEvent, - IdleTimeoutManager.StreamDataBlockedEvent, + IdleTimeoutManager.TimedEvent, QuicConnectionImpl.MaxInitialTimer { /** diff --git a/test/jdk/java/net/httpclient/http3/H3IdleExceedsQuicIdleTimeout.java b/test/jdk/java/net/httpclient/http3/H3IdleExceedsQuicIdleTimeout.java new file mode 100644 index 00000000000..6b62fcf6043 --- /dev/null +++ b/test/jdk/java/net/httpclient/http3/H3IdleExceedsQuicIdleTimeout.java @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2025, 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.io.IOException; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpOption; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.net.http.HttpResponse.BodyHandlers; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import javax.net.ssl.SSLContext; + +import jdk.httpclient.test.lib.common.HttpServerAdapters.HttpTestExchange; +import jdk.httpclient.test.lib.common.HttpServerAdapters.HttpTestHandler; +import jdk.httpclient.test.lib.common.HttpServerAdapters.HttpTestServer; +import jdk.test.lib.net.SimpleSSLContext; +import jdk.test.lib.net.URIBuilder; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import static java.net.http.HttpClient.Builder.NO_PROXY; +import static java.net.http.HttpClient.Version.HTTP_3; +import static java.net.http.HttpOption.Http3DiscoveryMode.HTTP_3_URI_ONLY; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +/* + * @test + * @bug 8371802 + * @summary verify that if a higher idle timeout is configured for a HTTP/3 connection + * then a lower negotiated QUIC idle timeout doesn't cause QUIC to + * idle terminate the connection + * @library /test/lib /test/jdk/java/net/httpclient/lib + * @build jdk.httpclient.test.lib.common.HttpServerAdapters + * jdk.test.lib.net.SimpleSSLContext + * + * @comment this test has some explicit delays to simulate a idle connection, the timeout=180 + * is merely to provide some leeway to the test and prevent timing out the test on busy + * systems + * @run junit/othervm/timeout=180 -Djdk.httpclient.quic.idleTimeout=30 + * -Djdk.httpclient.keepalive.timeout.h3=120 + * ${test.main.class} + */ +class H3IdleExceedsQuicIdleTimeout { + + private static final String REQ_PATH = "/8371802"; + + private static HttpTestServer h3Server; + private static SSLContext sslCtx; + + @BeforeAll + static void beforeAll() throws Exception { + sslCtx = new SimpleSSLContext().get(); + assert sslCtx != null : "SSLContext is null"; + h3Server = HttpTestServer.create(HTTP_3_URI_ONLY, sslCtx); + h3Server.addHandler(new Handler(), REQ_PATH); + h3Server.start(); + System.err.println("HTTP/3 server started at " + h3Server.getAddress()); + } + + @AfterAll + static void afterAll() throws Exception { + if (h3Server != null) { + System.err.println("stopping server at " + h3Server.getAddress()); + h3Server.stop(); + } + } + + /* + * With QUIC idle connection timeout configured to be lower than the HTTP/3 idle timeout, + * this test issues a HTTP/3 request and expects that request to establish a QUIC connection + * and receive a successful response. The test then stays idle for a duration larger + * than the QUIC idle timeout and issues a HTTP/3 request again after that idle period. + * The test then expects that the second request too is responded by the previously opened + * connection, thus proving that the QUIC layer did the necessary work to prevent the (idle) + * connection from terminating. + */ + @Test + void testQUICKeepsConnAlive() throws Exception { + final long quicIdleTimeoutSecs = 30; + assertEquals(quicIdleTimeoutSecs, + Integer.parseInt(System.getProperty("jdk.httpclient.quic.idleTimeout")), + "unexpected QUIC idle timeout"); + assertEquals(120, + Integer.parseInt(System.getProperty("jdk.httpclient.keepalive.timeout.h3")), + "unexpected HTTP/3 idle timeout"); + try (final HttpClient client = HttpClient.newBuilder() + .sslContext(sslCtx) + .proxy(NO_PROXY) + .version(HTTP_3) + .build()) { + + final URI req1URI = URIBuilder.newBuilder() + .scheme("https") + .host(h3Server.getAddress().getAddress()) + .port(h3Server.getAddress().getPort()) + .path(REQ_PATH) + .query("i=1") + .build(); + System.err.println("issuing request " + req1URI); + final HttpRequest req1 = HttpRequest.newBuilder() + .uri(req1URI) + .setOption(HttpOption.H3_DISCOVERY, HTTP_3_URI_ONLY) + .build(); + final HttpResponse resp1 = client.send(req1, BodyHandlers.discarding()); + assertEquals(200, resp1.statusCode(), "unexpected status code"); + final String resp1ConnLabel = resp1.connectionLabel().orElse(null); + System.err.println("first request handled by connection: " + resp1ConnLabel); + assertNotNull(resp1ConnLabel, "missing connection label on response"); + assertEquals(HTTP_3, resp1.version(), "unexpected response version"); + // don't generate any more traffic from the HTTP/3 side for longer than the QUIC + // idle timeout + stayIdle(quicIdleTimeoutSecs + 13, TimeUnit.SECONDS); + // now send the HTTP/3 request and expect the same previous connection to handle + // respond to this request + final URI req2URI = URIBuilder.newBuilder() + .scheme("https") + .host(h3Server.getAddress().getAddress()) + .port(h3Server.getAddress().getPort()) + .path(REQ_PATH) + .query("i=2") + .build(); + System.err.println("issuing request " + req2URI); + final HttpRequest req2 = HttpRequest.newBuilder() + .uri(req2URI) + .setOption(HttpOption.H3_DISCOVERY, HTTP_3_URI_ONLY) + .build(); + final HttpResponse resp2 = client.send(req2, BodyHandlers.discarding()); + assertEquals(200, resp2.statusCode(), "unexpected status code"); + final String resp2ConnLabel = resp2.connectionLabel().orElse(null); + System.err.println("second request handled by connection: " + resp2ConnLabel); + assertEquals(resp1ConnLabel, resp2ConnLabel, "second request handled by a different connection"); + assertEquals(HTTP_3, resp2.version(), "unexpected response version"); + } + } + + private static void stayIdle(final long time, final TimeUnit unit) throws InterruptedException { + // await on a CountDownLatch which no one counts down. this is merely + // to avoid using Thread.sleep(...) and other similar constructs and then + // having to deal with spurious wakeups. + final boolean countedDown = new CountDownLatch(1).await(time, unit); + assertFalse(countedDown, "wasn't expected to be counted down"); + } + + private static final class Handler implements HttpTestHandler { + private static final int NO_RESP_BODY = 0; + + @Override + public void handle(final HttpTestExchange exchange) throws IOException { + System.err.println("handling request " + exchange.getRequestURI()); + exchange.sendResponseHeaders(200, NO_RESP_BODY); + } + } +} From 282f339406d67d189e06c0bf8c7ca8d8cf5774e0 Mon Sep 17 00:00:00 2001 From: Lance Andersen Date: Sun, 30 Nov 2025 12:53:00 +0000 Subject: [PATCH 057/706] 8369432: Add Support for JDBC 4.5 MR Reviewed-by: alanb, rriggs --- .../share/classes/java/sql/Array.java | 38 +- src/java.sql/share/classes/java/sql/Blob.java | 42 +- src/java.sql/share/classes/java/sql/Clob.java | 40 +- .../share/classes/java/sql/Connection.java | 316 +++++- .../classes/java/sql/DriverPropertyInfo.java | 11 +- .../share/classes/java/sql/JDBCType.java | 18 +- .../share/classes/java/sql/NClob.java | 11 +- .../share/classes/java/sql/SQLPermission.java | 26 +- .../share/classes/java/sql/SQLUtils.java | 431 +++++++++ .../share/classes/java/sql/SQLXML.java | 44 +- .../share/classes/java/sql/Statement.java | 143 +-- .../share/classes/java/sql/Timestamp.java | 16 +- .../share/classes/java/sql/Types.java | 23 +- .../share/classes/java/sql/package-info.java | 42 +- .../test/sql/CallableStatementTests.java | 101 +- .../sql/testng/test/sql/ConnectionTests.java | 123 +++ .../test/sql/PreparedStatementTests.java | 103 +- .../sql/testng/test/sql/StatementTests.java | 127 +-- .../sql/testng/test/sql/TimestampTests.java | 40 +- test/jdk/java/sql/testng/util/BaseTest.java | 127 ++- .../testng/util/StubCallableStatement.java | 20 +- .../java/sql/testng/util/StubConnection.java | 19 +- .../sql/testng/util/StubDatabaseMetaData.java | 907 ++++++++++++++++++ .../testng/util/StubPreparedStatement.java | 23 +- .../java/sql/testng/util/StubStatement.java | 17 +- .../test/rowset/serial/SQLInputImplTests.java | 6 +- .../rowset/serial/SQLOutputImplTests.java | 3 +- 27 files changed, 2460 insertions(+), 357 deletions(-) create mode 100644 src/java.sql/share/classes/java/sql/SQLUtils.java create mode 100644 test/jdk/java/sql/testng/test/sql/ConnectionTests.java create mode 100644 test/jdk/java/sql/testng/util/StubDatabaseMetaData.java diff --git a/src/java.sql/share/classes/java/sql/Array.java b/src/java.sql/share/classes/java/sql/Array.java index 1c42d3e5b79..8fe84f4f930 100644 --- a/src/java.sql/share/classes/java/sql/Array.java +++ b/src/java.sql/share/classes/java/sql/Array.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, 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 @@ -61,13 +61,19 @@ package java.sql; * If the connection's type map or a type map supplied to a method has no entry * for the base type, the elements are mapped according to the standard mapping. *

    + * To release resources used by the {@code Array} object, applications must call + * either the {@link #free()} or the {@link #close()} method. Any attempt to + * invoke a method other than {@link #free()} or {@link #close()} after the + * {@code Array} object has been closed, will result in a {@link SQLException} + * being thrown. + *

    * All methods on the {@code Array} interface must be fully implemented if the * JDBC driver supports the data type. * * @since 1.2 */ -public interface Array { +public interface Array extends AutoCloseable { /** * Retrieves the SQL type name of the elements in @@ -345,21 +351,35 @@ public interface Array { java.util.Map> map) throws SQLException; /** - * This method frees the {@code Array} object and releases the resources that - * it holds. The object is invalid once the {@code free} - * method is called. + * Closes and releases the resources held by this {@code Array} object. *

    - * After {@code free} has been called, any attempt to invoke a - * method other than {@code free} will result in a {@code SQLException} - * being thrown. If {@code free} is called multiple times, the subsequent - * calls to {@code free} are treated as a no-op. + * If the {@code Array} object is already closed, then invoking this method + * has no effect. * * @throws SQLException if an error occurs releasing * the Array's resources * @throws SQLFeatureNotSupportedException if the JDBC driver does not support * this method * @since 1.6 + * @see #close() */ void free() throws SQLException; + /** + * Closes and releases the resources held by this {@code Array} object. + *

    + * If the {@code Array} object is already closed, then invoking this method + * has no effect. + * + * @throws SQLException if an error occurs releasing + * the Array's resources + * @throws SQLFeatureNotSupportedException if the JDBC driver + * does not support this method + * @implSpec The default implementation calls the {@link #free()} method. + * @see #free() + * @since 26 + */ + default void close() throws SQLException { + free(); + }; } diff --git a/src/java.sql/share/classes/java/sql/Blob.java b/src/java.sql/share/classes/java/sql/Blob.java index 5bf9cfcb7ad..4f5619616eb 100644 --- a/src/java.sql/share/classes/java/sql/Blob.java +++ b/src/java.sql/share/classes/java/sql/Blob.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, 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,7 @@ import java.io.InputStream; * the Java programming language of an SQL * {@code BLOB} value. An SQL {@code BLOB} is a built-in type * that stores a Binary Large Object as a column value in a row of - * a database table. By default drivers implement {@code Blob} using + * a database table. By default, drivers implement {@code Blob} using * an SQL {@code locator(BLOB)}, which means that a * {@code Blob} object contains a logical pointer to the * SQL {@code BLOB} data rather than the data itself. @@ -50,13 +50,19 @@ import java.io.InputStream; * {@code BLOB} value. In addition, this interface has methods for updating * a {@code BLOB} value. *

    + * To release resources used by the {@code Blob} object, applications must call + * either the {@link #free()} or the {@link #close()} method. Any attempt to + * invoke a method other than {@link #free()} or {@link #close()} after the + * {@code Blob} object has been closed, will result in a {@link SQLException} + * being thrown. + *

    * All methods on the {@code Blob} interface must be fully implemented if the * JDBC driver supports the data type. * * @since 1.2 */ -public interface Blob { +public interface Blob extends AutoCloseable { /** * Returns the number of bytes in the {@code BLOB} value @@ -266,20 +272,17 @@ public interface Blob { void truncate(long len) throws SQLException; /** - * This method frees the {@code Blob} object and releases the resources that - * it holds. The object is invalid once the {@code free} - * method is called. + * Closes and releases the resources held by this {@code Blob} object. *

    - * After {@code free} has been called, any attempt to invoke a - * method other than {@code free} will result in an {@code SQLException} - * being thrown. If {@code free} is called multiple times, the subsequent - * calls to {@code free} are treated as a no-op. + * If the {@code Blob} object is already closed, then invoking this method + * has no effect. * * @throws SQLException if an error occurs releasing * the Blob's resources * @throws SQLFeatureNotSupportedException if the JDBC driver * does not support this method * @since 1.6 + * @see #close() */ void free() throws SQLException; @@ -303,4 +306,23 @@ public interface Blob { * @since 1.6 */ InputStream getBinaryStream(long pos, long length) throws SQLException; + + /** + * Closes and releases the resources held by this {@code Blob} object. + *

    + * If the {@code Blob} object is already closed, then invoking this method + * has no effect. + * + * @implSpec The default implementation calls the {@link #free()} method. + * + * @throws SQLException if an error occurs releasing + * the Blob's resources + * @throws SQLFeatureNotSupportedException if the JDBC driver + * does not support this method + * @since 26 + * @see #free() + */ + default void close() throws SQLException { + free(); + }; } diff --git a/src/java.sql/share/classes/java/sql/Clob.java b/src/java.sql/share/classes/java/sql/Clob.java index 15e6897f711..141f7de81af 100644 --- a/src/java.sql/share/classes/java/sql/Clob.java +++ b/src/java.sql/share/classes/java/sql/Clob.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, 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,7 @@ import java.io.Reader; * An SQL {@code CLOB} is a built-in type * that stores a Character Large Object as a column value in a row of * a database table. - * By default drivers implement a {@code Clob} object using an SQL + * By default, drivers implement a {@code Clob} object using an SQL * {@code locator(CLOB)}, which means that a {@code Clob} object * contains a logical pointer to the SQL {@code CLOB} data rather than * the data itself. A {@code Clob} object is valid for the duration @@ -49,13 +49,19 @@ import java.io.Reader; * access an SQL {@code CLOB} value. In addition, this interface * has methods for updating a {@code CLOB} value. *

    + * To release resources used by the {@code Clob} object, applications must call + * either the {@link #free()} or the {@link #close()} method. Any attempt to + * invoke a method other than {@link #free()} or {@link #close()} after the + * {@code Clob} object has been closed, will result in a {@link SQLException} + * being thrown. + *

    * All methods on the {@code Clob} interface must be * fully implemented if the JDBC driver supports the data type. * * @since 1.2 */ -public interface Clob { +public interface Clob extends AutoCloseable { /** * Retrieves the number of characters @@ -310,14 +316,10 @@ public interface Clob { void truncate(long len) throws SQLException; /** - * This method releases the resources that the {@code Clob} object - * holds. The object is invalid once the {@code free} method - * is called. + * Closes and releases the resources held by this {@code Clob} object. *

    - * After {@code free} has been called, any attempt to invoke a - * method other than {@code free} will result in a {@code SQLException} - * being thrown. If {@code free} is called multiple times, the subsequent - * calls to {@code free} are treated as a no-op. + * If the {@code Clob} object is already closed, then invoking this method + * has no effect. * * @throws SQLException if an error occurs releasing * the Clob's resources @@ -325,6 +327,7 @@ public interface Clob { * @throws SQLFeatureNotSupportedException if the JDBC driver * does not support this method * @since 1.6 + * @see #close() */ void free() throws SQLException; @@ -350,4 +353,21 @@ public interface Clob { */ Reader getCharacterStream(long pos, long length) throws SQLException; + /** + * Closes and releases the resources held by this {@code Clob} object. + *

    + * If the {@code Clob} object is already closed, then invoking this method + * has no effect. + * + * @throws SQLException if an error occurs releasing + * the Clob's resources + * @throws SQLFeatureNotSupportedException if the JDBC driver + * does not support this method + * @implSpec The default implementation calls the {@link #free()} method. + * @see #free() + * @since 26 + */ + default void close() throws SQLException { + free(); + }; } diff --git a/src/java.sql/share/classes/java/sql/Connection.java b/src/java.sql/share/classes/java/sql/Connection.java index 19f283f5762..946459adf7b 100644 --- a/src/java.sql/share/classes/java/sql/Connection.java +++ b/src/java.sql/share/classes/java/sql/Connection.java @@ -43,8 +43,8 @@ import java.util.Map; * should use the appropriate {@code Connection} method such as * {@code setAutoCommit} or {@code setTransactionIsolation}. * Applications should not invoke SQL commands directly to change the connection's - * configuration when there is a JDBC method available. By default a {@code Connection} object is in - * auto-commit mode, which means that it automatically commits changes + * configuration when there is a JDBC method available. By default, a {@code Connection} + * object is in auto-commit mode, which means that it automatically commits changes * after executing each statement. If auto-commit mode has been * disabled, the method {@code commit} must be called explicitly in * order to commit changes; otherwise, database changes will not be saved. @@ -77,7 +77,7 @@ import java.util.Map; * con.setTypeMap(map); * * - * @see DriverManager#getConnection + * @see DriverManager#getConnection(String) * @see Statement * @see ResultSet * @see DatabaseMetaData @@ -1505,7 +1505,7 @@ public interface Connection extends Wrapper, AutoCloseable { * * @throws SQLException if an error occurs * @since 9 - * @see endRequest + * @see #endRequest() * @see javax.sql.PooledConnection */ default void beginRequest() throws SQLException { @@ -1548,7 +1548,7 @@ public interface Connection extends Wrapper, AutoCloseable { * * @throws SQLException if an error occurs * @since 9 - * @see beginRequest + * @see #beginRequest() * @see javax.sql.PooledConnection */ default void endRequest() throws SQLException { @@ -1676,5 +1676,311 @@ public interface Connection extends Wrapper, AutoCloseable { default void setShardingKey(ShardingKey shardingKey) throws SQLException { throw new SQLFeatureNotSupportedException("setShardingKey not implemented"); } + // JDBC 4.5 + /** + * Returns a {@code String} enclosed in single quotes. Any occurrence of a + * single quote within the string will be replaced by two single quotes. + * + *

    + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
    Examples of the conversion:
    ValueResult
    Hello 'Hello'
    G'Day 'G''Day'
    'G''Day''''G''''Day'''
    I'''M 'I''''''M'
    + *
    + * @implSpec + * The default implementation creates the literal as: + * {@code "'" + val.replace("'", "''") + "'"}. + * @implNote + * JDBC driver implementations may need to provide their own implementation + * of this method in order to meet the requirements of the underlying + * datasource. + * @param val a character string + * @return A string enclosed by single quotes with every single quote + * converted to two single quotes + * @throws NullPointerException if val is {@code null} + * @throws SQLException if a database access error occurs + * + * @since 26 + */ + default String enquoteLiteral(String val) throws SQLException { + return SQLUtils.enquoteLiteral(val); + } + + /** + * Returns a {@link #isSimpleIdentifier(String) simple SQL identifier} or a + * delimited identifier. A delimited identifier represents the name of a + * database object such as a table, column, or view that is enclosed by a + * delimiter, which is typically a double quote as defined by the SQL standard. + *

    + * If {@code identifier} is a simple SQL identifier: + *

      + *
    • If {@code alwaysDelimit} is {@code false}, return the original value
    • + *
    • if {@code alwaysDelimit} is {@code true}, enquote the original value + * and return as a delimited identifier
    • + *
    + * + * If {@code identifier} is not a simple SQL identifier, the delimited + * {@code identifier} to be returned must be enclosed by the delimiter + * returned from {@link DatabaseMetaData#getIdentifierQuoteString}. If + * the datasource does not support delimited identifiers, a + * {@code SQLFeatureNotSupportedException} is thrown. + *

    + * A {@code SQLException} will be thrown if {@code identifier} contains any + * invalid characters within a delimited identifier or the identifier length + * is invalid for the datasource. + * + * @implSpec + * The default implementation uses the following criteria to + * determine a valid simple SQL identifier: + *

      + *
    • The string is not enclosed in double quotes
    • + *
    • The first character is an alphabetic character from a ({@code '\u005C0061'}) + * through z ({@code '\u005Cu007A'}), or from A ({@code '\u005Cu0041'}) + * through Z ({@code '\u005Cu005A'})
    • + *
    • The name only contains alphanumeric characters([0-9A-Za-z]) + * or the character "_"
    • + *
    + * + * The default implementation will throw a {@code SQLException} if: + *
      + *
    • {@link DatabaseMetaData#getIdentifierQuoteString} does not return a + * double quote
    • + *
    • {@code identifier} contains a {@code null} character or double quote
    • + *
    • The length of {@code identifier} is less than 1 or greater than 128 characters + *
    + *
    + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
    Examples of the conversion:
    identifieralwaysDelimitResult
    HellofalseHello
    Hellotrue"Hello"
    G'Dayfalse"G'Day"
    "Bruce Wayne"false"Bruce Wayne"
    "Bruce Wayne"true"Bruce Wayne"
    "select"false"select"
    "select"true"select"
    GoodDay$false"GoodDay$"
    Hello"WorldfalseSQLException
    "Hello"World"falseSQLException
    + *
    + * @implNote + * JDBC driver implementations may need to provide their own implementation + * of this method in order to meet the requirements of the underlying + * datasource. + * @param identifier a SQL identifier + * @param alwaysDelimit indicates if a simple SQL identifier should be + * returned as a delimited identifier + * @return A simple SQL identifier or a delimited identifier + * @throws SQLException if identifier is not a valid identifier + * @throws SQLFeatureNotSupportedException if the datasource does not support + * delimited identifiers + * @throws NullPointerException if identifier is {@code null} + * + * @since 26 + */ + default String enquoteIdentifier(String identifier, boolean alwaysDelimit) throws SQLException { + String delimiter = this.getMetaData().getIdentifierQuoteString(); + return SQLUtils.enquoteIdentifier(delimiter, identifier, alwaysDelimit); + } + + /** + * Returns whether {@code identifier} is a simple SQL identifier. + * A simple SQL identifier is referred to as regular (or ordinary) identifier + * within the SQL standard. A regular identifier represents the name of a database + * object such as a table, column, or view. + *

    + * The rules for a regular Identifier are: + *

      + *
    • The first character is an alphabetic character from a ({@code '\u005Cu0061'}) + * through z ({@code '\u005Cu007A'}), or from A ({@code '\u005Cu0041'}) + * through Z ({@code '\u005Cu005A'})
    • + *
    • The name only contains alphanumeric characters([0-9A-Za-z]) + * or the character "_"
    • + *
    • It cannot be a SQL reserved word
    • + *
    + *

    + * A datasource may have additional rules for a regular identifier such as: + *

      + *
    • Supports additional characters within the name based on + * the locale being used
    • + *
    • Supports a different maximum length for the identifier
    • + *
    + * + * @implSpec The default implementation uses the following criteria to + * determine a valid simple SQL identifier: + *
      + *
    • The identifier is not enclosed in double quotes
    • + *
    • The first character is an alphabetic character from a through z, or + * from A through Z
    • + *
    • The identifier only contains alphanumeric characters([0-9A-Za-z]) or + * the character "_"
    • + *
    • The identifier is not a SQL reserved word
    • + *
    • The identifier is between 1 and 128 characters in length inclusive
    • + *
    + * + *
    + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
    Examples of the conversion:
    identifierSimple Identifier
    Hellotrue
    G'Dayfalse
    "Bruce Wayne"false
    GoodDay$false
    Hello"Worldfalse
    "Hello"World"false
    "select"false
    "from"false
    + *
    + * @implNote JDBC driver implementations may need to provide their own + * implementation of this method in order to meet the requirements of the + * underlying datasource. + * @param identifier a SQL identifier + * @return true if a simple SQL identifier, false otherwise + * @throws NullPointerException if identifier is {@code null} + * @throws SQLException if a database access error occurs + * + * @since 26 + */ + default boolean isSimpleIdentifier(String identifier) throws SQLException { + return SQLUtils.isSimpleIdentifier(identifier); + } + + /** + * Returns a {@code String} representing a National Character Set Literal + * enclosed in single quotes and prefixed with a upper case letter N. + * Any occurrence of a single quote within the string will be replaced + * by two single quotes. + * + *
    + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
    Examples of the conversion:
    ValueResult
    Hello N'Hello'
    G'Day N'G''Day'
    'G''Day'N'''G''''Day'''
    I'''M N'I''''''M'
    N'Hello' N'N''Hello'''
    + *
    + * @implSpec + * The default implementation creates the literal as: + * {@code "N'" + val.replace("'", "''") + "'"}. + * @implNote + * JDBC driver implementations may need to provide their own implementation + * of this method in order to meet the requirements of the underlying + * datasource. An implementation of enquoteNCharLiteral may accept a different + * set of characters than that accepted by the same drivers implementation of + * enquoteLiteral. + * @param val a character string + * @return the result of replacing every single quote character in the + * argument by two single quote characters where this entire result is + * then prefixed with 'N'. + * @throws NullPointerException if val is {@code null} + * @throws SQLException if a database access error occurs + * + * @since 26 + */ + default String enquoteNCharLiteral(String val) throws SQLException { + return SQLUtils.enquoteNCharLiteral(val); + } } diff --git a/src/java.sql/share/classes/java/sql/DriverPropertyInfo.java b/src/java.sql/share/classes/java/sql/DriverPropertyInfo.java index c5f5fc30ee9..426a49b7ae0 100644 --- a/src/java.sql/share/classes/java/sql/DriverPropertyInfo.java +++ b/src/java.sql/share/classes/java/sql/DriverPropertyInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2025, 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,12 +25,13 @@ package java.sql; +import java.util.Properties; + /** *

    Driver properties for making a connection. The - * {@code DriverPropertyInfo} class is of interest only to advanced programmers - * who need to interact with a Driver via the method - * {@code getDriverProperties} to discover - * and supply properties for connections. + * {@code DriverPropertyInfo} class is of interest only to advanced programmers. + * The method {@link Driver#getPropertyInfo(String, Properties)} may be used + * to discover Driver properties. * * @since 1.1 */ diff --git a/src/java.sql/share/classes/java/sql/JDBCType.java b/src/java.sql/share/classes/java/sql/JDBCType.java index 9c9d314b7f1..9da51c27925 100644 --- a/src/java.sql/share/classes/java/sql/JDBCType.java +++ b/src/java.sql/share/classes/java/sql/JDBCType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2025, 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 @@ -200,7 +200,21 @@ public enum JDBCType implements SQLType { /** * Identifies the generic SQL type {@code TIMESTAMP_WITH_TIMEZONE}. */ - TIMESTAMP_WITH_TIMEZONE(Types.TIMESTAMP_WITH_TIMEZONE); + TIMESTAMP_WITH_TIMEZONE(Types.TIMESTAMP_WITH_TIMEZONE), + + /* JDBC 4.5 Types */ + + /** + * Identifies the generic SQL type {@code DECFLOAT}. + * @since 26 + */ + DECFLOAT(Types.DECFLOAT), + + /** + * Identifies the generic SQL type {@code JSON}. + * @since 26 + */ + JSON(Types.JSON); /** * The Integer value for the JDBCType. It maps to a value in diff --git a/src/java.sql/share/classes/java/sql/NClob.java b/src/java.sql/share/classes/java/sql/NClob.java index 587f6e1f843..0639f894146 100644 --- a/src/java.sql/share/classes/java/sql/NClob.java +++ b/src/java.sql/share/classes/java/sql/NClob.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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,7 +31,8 @@ package java.sql; * An SQL {@code NCLOB} is a built-in type * that stores a Character Large Object using the National Character Set * as a column value in a row of a database table. - *

    The {@code NClob} interface extends the {@code Clob} interface + *

    + * The {@code NClob} interface extends the {@code Clob} interface * which provides methods for getting the * length of an SQL {@code NCLOB} value, * for materializing a {@code NCLOB} value on the client, and for @@ -44,6 +45,12 @@ package java.sql; * access an SQL {@code NCLOB} value. In addition, this interface * has methods for updating a {@code NCLOB} value. *

    + * To release resources used by the {@code NClob} object, applications must call + * either the {@link #free()} or the {@link #close()} method. Any attempt to + * invoke a method other than {@link #free()} or {@link #close()} after the + * {@code NClob} object has been closed, will result in a {@link SQLException} + * being thrown. + *

    * All methods on the {@code NClob} interface must be fully implemented if the * JDBC driver supports the data type. * diff --git a/src/java.sql/share/classes/java/sql/SQLPermission.java b/src/java.sql/share/classes/java/sql/SQLPermission.java index 84e41c51a33..f9a0c7e2ed6 100644 --- a/src/java.sql/share/classes/java/sql/SQLPermission.java +++ b/src/java.sql/share/classes/java/sql/SQLPermission.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2025, 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,30 +29,14 @@ package java.sql; import java.security.*; /** - * A {@code SQLPermission} object contains - * a name (also referred to as a "target name") but no actions - * list; there is either a named permission or there is not. - * The target name is the name of the permission. The - * naming convention follows the hierarchical property naming convention. - * In addition, an asterisk - * may appear at the end of the name, following a ".", or by itself, to - * signify a wildcard match. For example: {@code loadLibrary.*} - * and {@code *} signify a wildcard match, - * while {@code *loadLibrary} and {@code a*b} do not. - * - * @apiNote - * This permission cannot be used for controlling access to resources - * as the Security Manager is no longer supported. + * This class was only useful in conjunction with the {@link java.lang.SecurityManager}, + * which is no longer supported. There is no replacement for this class. * * @since 1.3 - * @see java.security.BasicPermission - * @see java.security.Permission - * @see java.security.Permissions - * @see java.security.PermissionCollection - * @see java.lang.SecurityManager * + * @deprecated There is no replacement for this class. */ - +@Deprecated(since="26", forRemoval=true) public final class SQLPermission extends BasicPermission { /** diff --git a/src/java.sql/share/classes/java/sql/SQLUtils.java b/src/java.sql/share/classes/java/sql/SQLUtils.java new file mode 100644 index 00000000000..49757d7e8ad --- /dev/null +++ b/src/java.sql/share/classes/java/sql/SQLUtils.java @@ -0,0 +1,431 @@ +/* + * Copyright (c) 2025, 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 java.sql; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; +import java.util.regex.Pattern; + +/** + * Utility class used by the Connection & Statement interfaces for their + * shared default methods. + */ +class SQLUtils { + // Pattern used to verify if an identifier is a Simple SQL identifier + private static final Pattern SIMPLE_IDENTIFIER_PATTERN + = Pattern.compile("[\\p{Alpha}][\\p{Alnum}_]*"); + // Pattern to check if an identifier contains a null character or a double quote + private static final Pattern INVALID_IDENTIFIER_CHARACTERS_PATTERN + = Pattern.compile("[^\u0000\"]+"); + // SQL 2023 reserved words + private static final String[] SQL2023_RESERVED_WORDS = { + "ABS", "ABSENT", "ACOS", "ALL", "ALLOCATE", "ALTER", "AND", "ANY", + "ANY_VALUE", "ARE", "ARRAY", "ARRAY_AGG", "ARRAY_MAX_CARDINALITY", + "AS", "ASENSITIVE", "ASIN", "ASYMMETRIC", "AT", "ATAN", + "ATOMIC", "AUTHORIZATION", "AVG", + "BEGIN", "BEGIN_FRAME", "BEGIN_PARTITION", "BETWEEN", "BIGINT", + "BINARY", "BLOB", "BOOLEAN", "BOTH", "BTRIM", "BY", + "CALL", "CALLED", "CARDINALITY", "CASCADED", "CASE", "CAST", "CEIL", + "CEILING", "CHAR", "CHAR_LENGTH", + "CHARACTER", "CHARACTER_LENGTH", "CHECK", "CLASSIFIER", "CLOB", + "CLOSE", "COALESCE", "COLLATE", "COLLECT", "COLUMN", "COMMIT", "CONDITION", + "CONNECT", "CONSTRAINT", "CONTAINS", "CONVERT", "COPY", "CORR", "CORRESPONDING", + "COS", "COSH", "COUNT", "COVAR_POP", "COVAR_SAMP", "CREATE", "CROSS", "CUBE", + "CUME_DIST", "CURRENT", + "CURRENT_CATALOG", "CURRENT_DATE", "CURRENT_DEFAULT_TRANSFORM_GROUP", "CURRENT_PATH", + "CURRENT_ROLE", "CURRENT_SCHEMA", "CURRENT_TIME", "CURRENT_TIMESTAMP", + "CURRENT_TRANSFORM_GROUP_FOR_TYPE", "CURRENT_USER", "CURSOR", "CYCLE", + "DATE", "DAY", "DEALLOCATE", "DEC", "DECFLOAT", "DECIMAL", "DECLARE", "DEFAULT", + "DEFINE", "DELETE", "DENSE_RANK", "DEREF", "DESCRIBE", "DETERMINISTIC", + "DISCONNECT", "DISTINCT", "DOUBLE", "DROP", "DYNAMIC", + "EACH", "ELEMENT", "ELSE", "EMPTY", "END", "END_FRAME", "END_PARTITION", + "END-EXEC", "EQUALS", "ESCAPE", "EVERY", "EXCEPT", "EXEC", "EXECUTE", + "EXISTS", "EXP", "EXTERNAL", "EXTRACT", + "FALSE", "FETCH", "FILTER", "FIRST_VALUE", "FLOAT", "FLOOR", "FOR", "FOREIGN", "FRAME_ROW", + "FREE", "FROM", "FULL", "FUNCTION", "FUSION", + "GET", "GLOBAL", "GRANT", "GREATEST", "GROUP", "GROUPING", "GROUPS", + "HAVING", "HOLD", "HOUR", + "IDENTITY", "IN", "INDICATOR", "INITIAL", "INNER", "INOUT", "INSENSITIVE", + "INSERT", "INT", "INTEGER", + "INTERSECT", "INTERSECTION", "INTERVAL", "INTO", "IS", + "JOIN", "JSON", "JSON_ARRAY", "JSON_ARRAYAGG", "JSON_EXISTS", + "JSON_OBJECT", "JSON_OBJECTAGG", "JSON_QUERY", "JSON_SCALAR", + "JSON_SERIALIZE", "JSON_TABLE", "JSON_TABLE_PRIMITIVE", "JSON_VALUE", + "LAG", "LANGUAGE", "LARGE", " LAST_VALUE", "LATERAL", "LEAD", + "LEADING", "LEAST", "LEFT", "LIKE", "LIKE_REGEX", "LISTAGG", + "LN", "LOCAL", "LOCALTIME", "LOCALTIMESTAMP", "LOG", "LOG10", + "LOWER", "LPAD", "LTRIM", + "MATCH", "MATCH_NUMBER", "MATCH_RECOGNIZE", "MATCHES", "MAX", + "MEMBER", "MERGE", "METHOD", "MIN", "MINUTE", "MOD", "MODIFIES", + "MODULE", "MONTH", "MULTISET", + "NATIONAL", "NATURAL", "NCHAR", "NCLOB", "NEW", "NO", "NONE", + "NORMALIZE", "NOT", "NTH_VALUE", "NTILE", "NULL", "NULLIF", "NUMERIC", + "OCCURRENCES_REGEX", "OCTET_LENGTH", "OF", "OFFSET", "OLD", "OMIT", + "ON", "ONE", "ONLY", "OPEN", "OR", "ORDER", "OUT", "OUTER", "OUTPUT", + "OVER", "OVERLAPS", "OVERLAY", + "PARAMETER", "PARTITION", "PATTERN", "PER", "PERCENT", "PERCENT_RANK", + "PERCENTILE_CONT", "PERCENTILE_DISC", "PERIOD", "PORTION", "POSITION", + "POSITION_REGEX", "POWER", "PRECEDES", + "PRECISION", "PREPARE", "PRIMARY", "PROCEDURE", "PTF", + "RANGE", "RANK", "READS", "REAL", "RECURSIVE", "REF", "REFERENCES", + "REFERENCING", "REGR_AVGX", "REGR_AVGY", "REGR_COUNT", "REGR_INTERCEPT", + "REGR_R2", "REGR_SLOPE", "REGR_SXX", "REGR_SXY", "REGR_SYY", + "RELEASE", "RESULT", "RETURN", "RETURNS", "REVOKE", "RIGHT", + "ROLLBACK", "ROLLUP", "ROW", "ROW_NUMBER", "ROWS", "RPAD", "RTRIM", + "RUNNING", + "SAVEPOINT", "SCOPE", "SCROLL", "SEARCH", "SECOND", "SEEK", + "SELECT", "SENSITIVE", "SESSION_USER", "SET", "SHOW", "SIMILAR", + "SIN", "SINH", "SKIP", "SMALLINT", + "SOME", "SPECIFIC", "SPECIFICTYPE", "SQL", "SQLEXCEPTION", "SQLSTATE", + "SQLWARNING", "SQRT", "START", "STATIC", "STDDEV_POP", "STDDEV_SAMP", + "SUBMULTISET", "SUBSET", "SUBSTRING", "SUBSTRING_REGEX", "SUCCEEDS", + "SUM", "SYMMETRIC", "SYSTEM", "SYSTEM_TIME", "SYSTEM_USER", + "TABLE", "TABLESAMPLE", "TAN", "TANH", "THEN", "TIME", "TIMESTAMP", + "TIMEZONE_HOUR", "TIMEZONE_MINUTE", "TO", "TRAILING", "TRANSLATE", + "TRANSLATE_REGEX", "TRANSLATION", "TREAT", "TRIGGER", "TRIM", + "TRIM_ARRAY", "TRUE", "TRUNCATE", + "UESCAPE", "UNION", "UNIQUE", "UNKNOWN", "UNNEST", "UPDATE", "UPPER", + "USER", "USING", + "VALUE", "VALUES", "VALUE_OF", "VAR_POP", "VAR_SAMP", "VARBINARY", + "VARCHAR", "VARYING", "VERSIONING", + "WHEN", "WHENEVER", "WHERE", "WHILE", "WIDTH_BUCKET", "WINDOW", + "WITH", "WITHIN", "WITHOUT", + "YEAR" + }; + private static final Set SQL_RESERVED_WORDS = + new HashSet<>(Arrays.asList(SQL2023_RESERVED_WORDS)); + + /** + * Returns a {@code String} enclosed in single quotes. Any occurrence of a + * single quote within the string will be replaced by two single quotes. + * + *

    + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
    Examples of the conversion:
    ValueResult
    Hello 'Hello'
    G'Day 'G''Day'
    'G''Day''''G''''Day'''
    I'''M 'I''''''M'
    + *
    + * + * @param val a character string + * @return A string enclosed by single quotes with every single quote + * converted to two single quotes + * @throws NullPointerException if val is {@code null} + * @throws SQLException if a database access error occurs + * @implNote JDBC driver implementations may need to provide their own implementation + * of this method in order to meet the requirements of the underlying + * datasource. + */ + static String enquoteLiteral(String val) throws SQLException { + return "'" + val.replace("'", "''") + "'"; + } + + /** + * Returns a {@link #isSimpleIdentifier(String) simple SQL identifier} or a + * delimited identifier. A delimited identifier represents the name of a + * database object such as a table, column, or view that is enclosed by a + * delimiter, which is typically a double quote as defined by the SQL standard. + *

    + * If {@code identifier} is a simple SQL identifier: + *

      + *
    • If {@code alwaysDelimit} is {@code false}, return the original value
    • + *
    • if {@code alwaysDelimit} is {@code true}, enquote the original value + * and return as a delimited identifier
    • + *
    + * + * If {@code identifier} is not a simple SQL identifier, the delimited + * {@code identifier} to be returned must be enclosed by the delimiter + * returned from {@link DatabaseMetaData#getIdentifierQuoteString}. If + * the datasource does not support delimited identifiers, a + * {@code SQLFeatureNotSupportedException} is thrown. + *

    + * A {@code SQLException} will be thrown if {@code identifier} contains any + * invalid characters within a delimited identifier or the identifier length + * is invalid for the datasource. + * + * @implSpec + * The default implementation uses the following criteria to + * determine a valid simple SQL identifier: + *

      + *
    • The string is not enclosed in double quotes
    • + *
    • The first character is an alphabetic character from a ({@code '\u005C0061'}) + * through z ({@code '\u005Cu007A'}), or from A ({@code '\u005Cu0041'}) + * through Z ({@code '\u005Cu005A'})
    • + *
    • The name only contains alphanumeric characters or the character "_"
    • + *
    + * + * The default implementation will throw a {@code SQLException} if: + *
      + *
    • {@link DatabaseMetaData#getIdentifierQuoteString} does not return a + * double quote
    • + *
    • {@code identifier} contains a {@code null} character or double quote
    • + *
    • The length of {@code identifier} is less than 1 or greater than 128 characters + *
    + *
    + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
    Examples of the conversion:
    identifieralwaysDelimitResult
    HellofalseHello
    Hellotrue"Hello"
    G'Dayfalse"G'Day"
    "Bruce Wayne"false"Bruce Wayne"
    "Bruce Wayne"true"Bruce Wayne"
    "select"false"select"
    "select"true"select"
    GoodDay$false"GoodDay$"
    Hello"WorldfalseSQLException
    "Hello"World"falseSQLException
    + *
    + * @implNote + * JDBC driver implementations may need to provide their own implementation + * of this method in order to meet the requirements of the underlying + * datasource. + * @param identifier a SQL identifier + * @param alwaysDelimit indicates if a simple SQL identifier should be + * returned as a delimited identifier + * @return A simple SQL identifier or a delimited identifier + * @throws SQLException if identifier is not a valid identifier + * @throws SQLFeatureNotSupportedException if the datasource does not support + * delimited identifiers + * @throws NullPointerException if identifier is {@code null} + */ + static String enquoteIdentifier(String delimiter, String identifier, boolean alwaysDelimit) throws SQLException { + int len = identifier.length(); + if (len < 1 || len > 128) { + throw new SQLException("Invalid identifier length"); + } + if (!delimiter.equals("\"")) { + throw new SQLException("Unsupported delimiter"); + } + if (isSimpleIdentifier(identifier)) { + return alwaysDelimit ? "\"" + identifier + "\"" : identifier; + } + if (identifier.matches("^\".+\"$")) { + identifier = identifier.substring(1, len - 1); + } + // Enclose the identifier in double quotes. If the identifier + // contains a null character or a double quote, throw a SQLException + if (INVALID_IDENTIFIER_CHARACTERS_PATTERN.matcher(identifier).matches()) { + return "\"" + identifier + "\""; + } else { + throw new SQLException("Invalid name"); + } + } + + /** + * Returns whether {@code identifier} is a simple SQL identifier. + * A simple SQL identifier is referred to as regular (or ordinary) identifier + * within the SQL standard. A regular identifier represents the name of a database + * object such as a table, column, or view. + *

    + * The rules for a regular Identifier are: + *

      + *
    • The first character is an alphabetic character from a ({@code '\u005Cu0061'}) + * through z ({@code '\u005Cu007A'}), or from A ({@code '\u005Cu0041'}) + * through Z ({@code '\u005Cu005A'})
    • + *
    • The name only contains alphanumeric characters or the character "_"
    • + *
    • It cannot be a SQL reserved word
    • + *
    + *

    + * A datasource may have additional rules for a regular identifier such as: + *

      + *
    • Supports additional characters within the name based on + * the locale being used
    • + *
    • Supports a different maximum length for the identifier
    • + *
    + * + * @implSpec The default implementation uses the following criteria to + * determine a valid simple SQL identifier: + *
      + *
    • The identifier is not enclosed in double quotes
    • + *
    • The first character is an alphabetic character from a through z, or + * from A through Z
    • + *
    • The identifier only contains alphanumeric characters or the character + * "_"
    • + *
    • The identifier is not a SQL reserved word
    • + *
    • The identifier is between 1 and 128 characters in length inclusive
    • + *
    + * + *
    + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
    Examples of the conversion:
    identifierSimple Identifier
    Hellotrue
    G'Dayfalse
    "Bruce Wayne"false
    GoodDay$false
    Hello"Worldfalse
    "Hello"World"false
    "select"false
    "from"false
    + *
    + * @implNote JDBC driver implementations may need to provide their own + * implementation of this method in order to meet the requirements of the + * underlying datasource. + * @param identifier a SQL identifier + * @return true if a simple SQL identifier, false otherwise + * @throws NullPointerException if identifier is {@code null} + * @throws SQLException if a database access error occurs + */ + static boolean isSimpleIdentifier(String identifier) throws SQLException { + int len = identifier.length(); + return !SQL_RESERVED_WORDS.contains(identifier.toUpperCase()) && + len >= 1 && len <= 128 + && SIMPLE_IDENTIFIER_PATTERN.matcher(identifier).matches(); + } + + /** + * Returns a {@code String} representing a National Character Set Literal + * enclosed in single quotes and prefixed with an upper case letter N. + * Any occurrence of a single quote within the string will be replaced + * by two single quotes. + * + *
    + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
    Examples of the conversion:
    ValueResult
    Hello N'Hello'
    G'Day N'G''Day'
    'G''Day'N'''G''''Day'''
    I'''M N'I''''''M'
    N'Hello' N'N''Hello'''
    + *
    + * + * @param val a character string + * @return the result of replacing every single quote character in the + * argument by two single quote characters where this entire result is + * then prefixed with 'N'. + * @throws NullPointerException if val is {@code null} + * @throws SQLException if a database access error occurs + * @implNote JDBC driver implementations may need to provide their own implementation + * of this method in order to meet the requirements of the underlying + * datasource. An implementation of enquoteNCharLiteral may accept a different + * set of characters than that accepted by the same drivers implementation of + * enquoteLiteral. + */ + static String enquoteNCharLiteral(String val) throws SQLException { + return "N'" + val.replace("'", "''") + "'"; + } +} diff --git a/src/java.sql/share/classes/java/sql/SQLXML.java b/src/java.sql/share/classes/java/sql/SQLXML.java index 3edae8a9508..70d481822e2 100644 --- a/src/java.sql/share/classes/java/sql/SQLXML.java +++ b/src/java.sql/share/classes/java/sql/SQLXML.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -170,14 +170,19 @@ import javax.xml.transform.Source; * The conceptual states of writable and not writable determine if one * of the writing APIs will set a value or throw an exception. *

    - * The state moves from readable to not readable once free() or any of the + * The state moves from readable to not readable once close(), free() or any of the * reading APIs are called: getBinaryStream(), getCharacterStream(), getSource(), and getString(). * Implementations may also change the state to not writable when this occurs. *

    - * The state moves from writable to not writable once free() or any of the + * The state moves from writable to not writable once close(), free() or any of the * writing APIs are called: setBinaryStream(), setCharacterStream(), setResult(), and setString(). * Implementations may also change the state to not readable when this occurs. - * + *

    + * To release resources used by the {@code SQLXML} object, applications must call + * either the {@link #free()} or the {@link #close()} method. Any attempt to + * invoke a method other than {@link #free()} or {@link #close()} after the + * {@code SQLXML} object has been closed, will result in a {@link SQLException} + * being thrown. *

    * All methods on the {@code SQLXML} interface must be fully implemented if the * JDBC driver supports the data type. @@ -188,21 +193,19 @@ import javax.xml.transform.Source; * @see javax.xml.xpath * @since 1.6 */ -public interface SQLXML +public interface SQLXML extends AutoCloseable { /** - * This method closes this object and releases the resources that it held. - * The SQL XML object becomes invalid and neither readable or writable - * when this method is called. + * Closes and releases the resources held by this {@code SQLXML} object. + *

    + * If the {@code SQLXML} object is already closed, then invoking this method + * has no effect. * - * After {@code free} has been called, any attempt to invoke a - * method other than {@code free} will result in a {@code SQLException} - * being thrown. If {@code free} is called multiple times, the subsequent - * calls to {@code free} are treated as a no-op. * @throws SQLException if there is an error freeing the XML value. * @throws SQLFeatureNotSupportedException if the JDBC driver does not support * this method * @since 1.6 + * @see #close() */ void free() throws SQLException; @@ -424,4 +427,21 @@ public interface SQLXML */ T setResult(Class resultClass) throws SQLException; + /** + * Closes and releases the resources held by this {@code SQLXML} object. + *

    + * If the {@code SQLXML} object is already closed, then invoking this method + * has no effect. + * + * @throws SQLException if an error occurs releasing + * the SQLXML's resources + * @throws SQLFeatureNotSupportedException if the JDBC driver + * does not support this method + * @implSpec The default implementation calls the {@link #free()} method. + * @see #free() + * @since 26 + */ + default void close() throws SQLException { + free(); + }; } diff --git a/src/java.sql/share/classes/java/sql/Statement.java b/src/java.sql/share/classes/java/sql/Statement.java index bb5a5cfd64d..4da510f6749 100644 --- a/src/java.sql/share/classes/java/sql/Statement.java +++ b/src/java.sql/share/classes/java/sql/Statement.java @@ -25,9 +25,6 @@ package java.sql; -import java.util.regex.Pattern; -import static java.util.stream.Collectors.joining; - /** *

    The object used for executing a static SQL statement * and returning the results it produces. @@ -1395,6 +1392,9 @@ public interface Statement extends Wrapper, AutoCloseable { * * * + * @implSpec + * The default implementation creates the literal as: + * {@code "'" + val.replace("'", "''") + "'"}. * @implNote * JDBC driver implementations may need to provide their own implementation * of this method in order to meet the requirements of the underlying @@ -1407,46 +1407,50 @@ public interface Statement extends Wrapper, AutoCloseable { * * @since 9 */ - default String enquoteLiteral(String val) throws SQLException { - return "'" + val.replace("'", "''") + "'"; + default String enquoteLiteral(String val) throws SQLException { + return SQLUtils.enquoteLiteral(val); } - - /** - * Returns a SQL identifier. If {@code identifier} is a simple SQL identifier: + /** + * Returns a {@link #isSimpleIdentifier(String) simple SQL identifier} or a + * delimited identifier. A delimited identifier represents the name of a + * database object such as a table, column, or view that is enclosed by a + * delimiter, which is typically a double quote as defined by the SQL standard. + *

    + * If {@code identifier} is a simple SQL identifier: *

      - *
    • Return the original value if {@code alwaysQuote} is - * {@code false}
    • - *
    • Return a delimited identifier if {@code alwaysQuote} is - * {@code true}
    • + *
    • If {@code alwaysDelimit} is {@code false}, return the original value
    • + *
    • if {@code alwaysDelimit} is {@code true}, enquote the original value + * and return as a delimited identifier
    • *
    * - * If {@code identifier} is not a simple SQL identifier, {@code identifier} will be - * enclosed in double quotes if not already present. If the datasource does - * not support double quotes for delimited identifiers, the - * identifier should be enclosed by the string returned from - * {@link DatabaseMetaData#getIdentifierQuoteString}. If the datasource - * does not support delimited identifiers, a - * {@code SQLFeatureNotSupportedException} should be thrown. + * If {@code identifier} is not a simple SQL identifier, the delimited + * {@code identifier} to be returned must be enclosed by the delimiter + * returned from {@link DatabaseMetaData#getIdentifierQuoteString}. If + * the datasource does not support delimited identifiers, a + * {@code SQLFeatureNotSupportedException} is thrown. *

    * A {@code SQLException} will be thrown if {@code identifier} contains any - * characters invalid in a delimited identifier or the identifier length is - * invalid for the datasource. + * invalid characters within a delimited identifier or the identifier length + * is invalid for the datasource. * * @implSpec * The default implementation uses the following criteria to * determine a valid simple SQL identifier: *

      *
    • The string is not enclosed in double quotes
    • - *
    • The first character is an alphabetic character from a through z, or - * from A through Z
    • - *
    • The name only contains alphanumeric characters or the character "_"
    • + *
    • The first character is an alphabetic character from a ({@code '\u005C0061'}) + * through z ({@code '\u005Cu007A'}), or from A ({@code '\u005Cu0041'}) + * through Z ({@code '\u005Cu005A'})
    • + *
    • The name only contains alphanumeric characters([0-9A-Za-z]) + * or the character "_"
    • *
    * * The default implementation will throw a {@code SQLException} if: *
      - *
    • {@code identifier} contains a {@code null} character or double quote and is not - * a simple SQL identifier.
    • + *
    • {@link DatabaseMetaData#getIdentifierQuoteString} does not return a + * double quote
    • + *
    • {@code identifier} contains a {@code null} character or double quote
    • *
    • The length of {@code identifier} is less than 1 or greater than 128 characters *
    *
    @@ -1455,7 +1459,7 @@ public interface Statement extends Wrapper, AutoCloseable { * * * identifier - * alwaysQuote + * alwaysDelimit * Result * * @@ -1485,6 +1489,16 @@ public interface Statement extends Wrapper, AutoCloseable { * "Bruce Wayne" * * + * "select" + * false + * "select" + * + * + * "select" + * true + * "select" + * + * * GoodDay$ * false * "GoodDay$" @@ -1507,8 +1521,8 @@ public interface Statement extends Wrapper, AutoCloseable { * of this method in order to meet the requirements of the underlying * datasource. * @param identifier a SQL identifier - * @param alwaysQuote indicates if a simple SQL identifier should be - * returned as a quoted identifier + * @param alwaysDelimit indicates if a simple SQL identifier should be + * returned as a delimited identifier * @return A simple SQL identifier or a delimited identifier * @throws SQLException if identifier is not a valid identifier * @throws SQLFeatureNotSupportedException if the datasource does not support @@ -1517,36 +1531,43 @@ public interface Statement extends Wrapper, AutoCloseable { * * @since 9 */ - default String enquoteIdentifier(String identifier, boolean alwaysQuote) throws SQLException { - int len = identifier.length(); - if (len < 1 || len > 128) { - throw new SQLException("Invalid name"); - } - if (Pattern.compile("[\\p{Alpha}][\\p{Alnum}_]*").matcher(identifier).matches()) { - return alwaysQuote ? "\"" + identifier + "\"" : identifier; - } - if (identifier.matches("^\".+\"$")) { - identifier = identifier.substring(1, len - 1); - } - if (Pattern.compile("[^\u0000\"]+").matcher(identifier).matches()) { - return "\"" + identifier + "\""; - } else { - throw new SQLException("Invalid name"); - } + default String enquoteIdentifier(String identifier, boolean alwaysDelimit) throws SQLException { + return getConnection().enquoteIdentifier(identifier,alwaysDelimit); } /** - * Retrieves whether {@code identifier} is a simple SQL identifier. + * Returns whether {@code identifier} is a simple SQL identifier. + * A simple SQL identifier is referred to as regular (or ordinary) identifier + * within the SQL standard. A regular identifier represents the name of a database + * object such as a table, column, or view. + *

    + * The rules for a regular Identifier are: + *

      + *
    • The first character is an alphabetic character from a ({@code '\u005Cu0061'}) + * through z ({@code '\u005Cu007A'}), or from A ({@code '\u005Cu0041'}) + * through Z ({@code '\u005Cu005A'})
    • + *
    • The name only contains alphanumeric characters([0-9A-Za-z]) or the + * character "_"
    • + *
    • It cannot be a SQL reserved word
    • + *
    + *

    + * A datasource may have additional rules for a regular identifier such as: + *

      + *
    • Supports additional characters within the name based on + * the locale being used
    • + *
    • Supports a different maximum length for the identifier
    • + *
    * * @implSpec The default implementation uses the following criteria to * determine a valid simple SQL identifier: *
      - *
    • The string is not enclosed in double quotes
    • + *
    • The identifier is not enclosed in double quotes
    • *
    • The first character is an alphabetic character from a through z, or * from A through Z
    • - *
    • The string only contains alphanumeric characters or the character - * "_"
    • - *
    • The string is between 1 and 128 characters in length inclusive
    • + *
    • The identifier only contains alphanumeric characters([0-9A-Za-z]) + * or the character "_"
    • + *
    • The identifier is not a SQL reserved word
    • + *
    • The identifier is between 1 and 128 characters in length inclusive
    • *
    * *
    @@ -1583,6 +1604,13 @@ public interface Statement extends Wrapper, AutoCloseable { * "Hello"World" * false * + * + * "select" + * false + * + * "from" + * false + * * * *
    @@ -1590,16 +1618,14 @@ public interface Statement extends Wrapper, AutoCloseable { * implementation of this method in order to meet the requirements of the * underlying datasource. * @param identifier a SQL identifier - * @return true if a simple SQL identifier, false otherwise + * @return true if a simple SQL identifier, false otherwise * @throws NullPointerException if identifier is {@code null} * @throws SQLException if a database access error occurs * * @since 9 */ default boolean isSimpleIdentifier(String identifier) throws SQLException { - int len = identifier.length(); - return len >= 1 && len <= 128 - && Pattern.compile("[\\p{Alpha}][\\p{Alnum}_]*").matcher(identifier).matches(); + return SQLUtils.isSimpleIdentifier(identifier); } /** @@ -1628,7 +1654,10 @@ public interface Statement extends Wrapper, AutoCloseable { * * *
    - * @implNote + * @implSpec + * The default implementation creates the literal as: + * {@code "N'" + val.replace("'", "''") + "'"}. + * @implNote * JDBC driver implementations may need to provide their own implementation * of this method in order to meet the requirements of the underlying * datasource. An implementation of enquoteNCharLiteral may accept a different @@ -1643,7 +1672,7 @@ public interface Statement extends Wrapper, AutoCloseable { * * @since 9 */ - default String enquoteNCharLiteral(String val) throws SQLException { - return "N'" + val.replace("'", "''") + "'"; + default String enquoteNCharLiteral(String val) throws SQLException { + return SQLUtils.enquoteNCharLiteral(val); } } diff --git a/src/java.sql/share/classes/java/sql/Timestamp.java b/src/java.sql/share/classes/java/sql/Timestamp.java index a91ab7210c5..c550291bb95 100644 --- a/src/java.sql/share/classes/java/sql/Timestamp.java +++ b/src/java.sql/share/classes/java/sql/Timestamp.java @@ -54,10 +54,7 @@ import java.time.LocalDateTime; * because the nanos component of a date is unknown. * As a result, the {@code Timestamp.equals(Object)} * method is not symmetric with respect to the - * {@code java.util.Date.equals(Object)} - * method. Also, the {@code hashCode} method uses the underlying - * {@code java.util.Date} - * implementation and therefore does not include nanos in its computation. + * {@code java.util.Date.equals(Object)} method. *

    * Due to the differences between the {@code Timestamp} class * and the {@code java.util.Date} @@ -465,10 +462,15 @@ public class Timestamp extends java.util.Date { } /** - * {@inheritDoc} + * Returns a hash code value for this Timestamp. The result is the + * exclusive OR of the two halves of the primitive {@code long} + * value returned by the {@link #getTime} method. That is, + * the hash code is the value of the expression: + * {@snippet : + * (int)(this.getTime()^(this.getTime() >>> 32)) + * } * - * The {@code hashCode} method uses the underlying {@code java.util.Date} - * implementation and therefore does not include nanos in its computation. + * @return a hash code value for this Timestamp. * */ @Override diff --git a/src/java.sql/share/classes/java/sql/Types.java b/src/java.sql/share/classes/java/sql/Types.java index 2b3b571647b..778d782ddaf 100644 --- a/src/java.sql/share/classes/java/sql/Types.java +++ b/src/java.sql/share/classes/java/sql/Types.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2025, 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 @@ -339,6 +339,27 @@ public class Types { */ public static final int TIMESTAMP_WITH_TIMEZONE = 2014; + + //--------------------------JDBC 4.5 ----------------------------- + + /** + * The constant in the Java programming language, sometimes referred to + * as a type code, that identifies the generic SQL type + * {@code DECFLOAT}. + * + * @since 26 + */ + public static final int DECFLOAT = 2015; + + /** + * The constant in the Java programming language, sometimes referred to + * as a type code, that identifies the generic SQL type + * {@code JSON}. + * + * @since 26 + */ + public static final int JSON = 2016; + // Prevent instantiation private Types() {} } diff --git a/src/java.sql/share/classes/java/sql/package-info.java b/src/java.sql/share/classes/java/sql/package-info.java index 495119effac..64b23dba76f 100644 --- a/src/java.sql/share/classes/java/sql/package-info.java +++ b/src/java.sql/share/classes/java/sql/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, 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,20 +38,22 @@ * use and update data from a spread sheet, flat file, or any other tabular * data source. * - *

    What the JDBC 4.3 API Includes

    - * The JDBC 4.3 API includes both + *

    What the JDBC 4.5 API Includes

    + * The JDBC 4.5 API includes both * the {@code java.sql} package, referred to as the JDBC core API, * and the {@code javax.sql} package, referred to as the JDBC Optional * Package API. This complete JDBC API - * is included in the Java Standard Edition (Java SE), version 7. + * is included in the Java Standard Edition (Java SE). * The {@code javax.sql} package extends the functionality of the JDBC API * from a client-side API to a server-side API, and it is an essential part * of the Java Enterprise Edition * (Java EE) technology. * *

    Versions

    - * The JDBC 4.3 API incorporates all of the previous JDBC API versions: + * The JDBC 4.5 API incorporates all the previous JDBC API versions: *
      + *
    • The JDBC 4.4 API
    • + *
    • The JDBC 4.3 API
    • *
    • The JDBC 4.2 API
    • *
    • The JDBC 4.1 API
    • *
    • The JDBC 4.0 API
    • @@ -70,6 +72,10 @@ * Javadoc comments for the JDBC API, * they indicate the following: *
        + *
      • Since 26 -- new in the JDBC 4.5 API and part of the Java SE platform, + * version 26
      • + *
      • Since 24 -- new in the JDBC 4.4 API and part of the Java SE platform, + * version 24
      • *
      • Since 9 -- new in the JDBC 4.3 API and part of the Java SE platform, * version 9
      • *
      • Since 1.8 -- new in the JDBC 4.2 API and part of the Java SE platform, @@ -126,6 +132,7 @@ *
      • {@code Blob} interface -- mapping for SQL {@code BLOB} *
      • {@code Clob} interface -- mapping for SQL {@code CLOB} *
      • {@code Date} class -- mapping for SQL {@code DATE} + *
      • {@code JDBCType} class -- provides enum constants for SQL types *
      • {@code NClob} interface -- mapping for SQL {@code NCLOB} *
      • {@code Ref} interface -- mapping for SQL {@code REF} *
      • {@code RowId} interface -- mapping for SQL {@code ROWID} @@ -166,6 +173,26 @@ *
      *
    * + *

    {@code java.sql} and {@code javax.sql} Features Introduced in the JDBC 4.5 API

    + *
      + *
    • The interfaces {@code Array}, {@code Blob}, {@code Clob}, {@code NClob} + * and {@code SQLXML} now extend the {@code AutoCloseable} interface and + * include a default {@code close} method implementation
    • + *
    • Added support to {@code Connection} for enquoting literals + * and simple identifiers
    • + *
    • {@code SQLPermissions} has been deprecated for removal
    • + *
    • The SQL Types {@code JSON} and {@code DECFLOAT} have been added to + * {@code JDBCType} and {@code Types}
    • + *
    + *

    {@code java.sql} and {@code javax.sql} Features Introduced in the JDBC 4.4 API

    + *
      + *
    • Remove mention of {@code SecurityManager} and {@code SecurityException} + * as the {@code SecurityManager} is no longer supported
    • + *
    • {@code SQLPermissions} can no longer be used to control access to + * resources as the {@code SecurityManager} is no longer supported
    • + *
    • Added support to {@code Connection} for enquoting literals + * and simple identifiers
    • + *
    *

    {@code java.sql} and {@code javax.sql} Features Introduced in the JDBC 4.3 API

    *
      *
    • Added {@code Sharding} support
    • @@ -232,7 +259,6 @@ * *
    * - * *

    {@code java.sql} and {@code javax.sql} Features Introduced in the JDBC 3.0 API

    *
      *
    • Pooled statements -- reuse of statements associated with a pooled @@ -288,7 +314,6 @@ * handling and passing data *
    * - * *

    Custom Mapping of UDTs

    * A user-defined type (UDT) defined in SQL can be mapped to a class in the Java * programming language. An SQL structured type or an SQL {@code DISTINCT} @@ -317,7 +342,7 @@ *

    Package Specification

    * * * *

    Related Documentation

    @@ -326,7 +351,6 @@ *
  • * Lesson:JDBC Basics(The Java Tutorials > JDBC Database Access) * - *
  • JDBC API Tutorial and Reference, Third Edition” * * @since 1.1 */ diff --git a/test/jdk/java/sql/testng/test/sql/CallableStatementTests.java b/test/jdk/java/sql/testng/test/sql/CallableStatementTests.java index f917b6af4dc..7a4fe15ecac 100644 --- a/test/jdk/java/sql/testng/test/sql/CallableStatementTests.java +++ b/test/jdk/java/sql/testng/test/sql/CallableStatementTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, 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,15 +22,108 @@ */ package test.sql; +import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; -import util.StubCallableStatement; +import org.testng.annotations.Test; +import util.BaseTest; +import util.StubConnection; -public class CallableStatementTests extends PreparedStatementTests { +import java.sql.CallableStatement; +import java.sql.SQLException; + +import static org.testng.Assert.assertEquals; + +public class CallableStatementTests extends BaseTest { + private CallableStatement cstmt; @BeforeMethod public void setUpMethod() throws Exception { - stmt = new StubCallableStatement(); + cstmt = new StubConnection().prepareCall("{call SuperHero_Proc(?)}"); } + @AfterMethod + public void tearDownMethod() throws Exception { + cstmt.close(); + } + /* + * Verify that enquoteLiteral creates a valid literal and converts every + * single quote to two single quotes + */ + @Test(dataProvider = "validEnquotedLiteralValues") + public void test00(String s, String expected) throws SQLException { + assertEquals(cstmt.enquoteLiteral(s), expected); + } + + /* + * Validate a NullPointerException is thrown if the string passed to + * enquoteLiteral is null + */ + @Test(expectedExceptions = NullPointerException.class) + public void test01() throws SQLException { + cstmt.enquoteLiteral(null); + } + + /* + * Validate that enquoteIdentifier returns the expected value + */ + @Test(dataProvider = "validIdentifierValues") + public void test02(String s, boolean alwaysQuote, String expected) throws SQLException { + assertEquals(cstmt.enquoteIdentifier(s, alwaysQuote), expected); + } + + /* + * Validate that a SQLException is thrown for values that are not valid + * for a SQL identifier + */ + @Test(dataProvider = "invalidIdentifierValues", + expectedExceptions = SQLException.class) + public void test03(String s, boolean alwaysQuote) throws SQLException { + cstmt.enquoteIdentifier(s, alwaysQuote); + } + + /* + * Validate a NullPointerException is thrown is the string passed to + * enquoteIdentiifer is null + */ + @Test(dataProvider = "trueFalse", + expectedExceptions = NullPointerException.class) + public void test04(boolean alwaysQuote) throws SQLException { + cstmt.enquoteIdentifier(null, alwaysQuote); + } + + /* + * Validate that isSimpleIdentifier returns the expected value + */ + @Test(dataProvider = "simpleIdentifierValues") + public void test05(String s, boolean expected) throws SQLException { + assertEquals(cstmt.isSimpleIdentifier(s), expected); + } + + /* + * Validate a NullPointerException is thrown if the string passed to + * isSimpleIdentifier is null + */ + @Test(expectedExceptions = NullPointerException.class) + public void test06() throws SQLException { + cstmt.isSimpleIdentifier(null); + } + + /* + * Verify that enquoteLiteral creates a valid literal and converts every + * single quote to two single quotes + */ + @Test(dataProvider = "validEnquotedNCharLiteralValues") + public void test07(String s, String expected) throws SQLException { + assertEquals(cstmt.enquoteNCharLiteral(s), expected); + } + + /* + * Validate a NullPointerException is thrown if the string passed to + * enquoteNCharLiteral is null + */ + @Test(expectedExceptions = NullPointerException.class) + public void test08() throws SQLException { + cstmt.enquoteNCharLiteral(null); + } } diff --git a/test/jdk/java/sql/testng/test/sql/ConnectionTests.java b/test/jdk/java/sql/testng/test/sql/ConnectionTests.java new file mode 100644 index 00000000000..f40c2784e4a --- /dev/null +++ b/test/jdk/java/sql/testng/test/sql/ConnectionTests.java @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2025, 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 test.sql; + +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; +import util.BaseTest; +import util.StubConnection; + +import java.sql.SQLException; + +import static org.testng.Assert.*; + +public class ConnectionTests extends BaseTest { + + protected StubConnection conn; + + @BeforeMethod + public void setUpMethod() throws Exception { + conn = new StubConnection(); + } + + /* + * Verify that enquoteLiteral creates a valid literal and converts every + * single quote to two single quotes + */ + @Test(dataProvider = "validEnquotedLiteralValues") + public void test00(String s, String expected) throws SQLException { + assertEquals(conn.enquoteLiteral(s), expected); + } + + /* + * Validate a NullPointerException is thrown if the string passed to + * enquoteLiteral is null + */ + @Test(expectedExceptions = NullPointerException.class) + public void test01() throws SQLException { + conn.enquoteLiteral(null); + } + + /* + * Validate that enquoteIdentifier returns the expected value + */ + @Test(dataProvider = "validIdentifierValues") + public void test02(String s, boolean alwaysQuote, String expected) throws SQLException { + assertEquals(conn.enquoteIdentifier(s, alwaysQuote), expected); + } + + /* + * Validate that a SQLException is thrown for values that are not valid + * for a SQL identifier + */ + @Test(dataProvider = "invalidIdentifierValues", + expectedExceptions = SQLException.class) + public void test03(String s, boolean alwaysQuote) throws SQLException { + conn.enquoteIdentifier(s, alwaysQuote); + } + + /* + * Validate a NullPointerException is thrown is the string passed to + * enquoteIdentiifer is null + */ + @Test(dataProvider = "trueFalse", + expectedExceptions = NullPointerException.class) + public void test04(boolean alwaysQuote) throws SQLException { + conn.enquoteIdentifier(null, alwaysQuote); + } + + /* + * Validate that isSimpleIdentifier returns the expected value + */ + @Test(dataProvider = "simpleIdentifierValues") + public void test05(String s, boolean expected) throws SQLException { + assertEquals(conn.isSimpleIdentifier(s), expected); + } + + /* + * Validate a NullPointerException is thrown if the string passed to + * isSimpleIdentifier is null + */ + @Test(expectedExceptions = NullPointerException.class) + public void test06() throws SQLException { + conn.isSimpleIdentifier(null); + } + + /* + * Verify that enquoteLiteral creates a valid literal and converts every + * single quote to two single quotes + */ + @Test(dataProvider = "validEnquotedNCharLiteralValues") + public void test07(String s, String expected) throws SQLException { + assertEquals(conn.enquoteNCharLiteral(s), expected); + } + + /* + * Validate a NullPointerException is thrown if the string passed to + * enquoteNCharLiteral is null + */ + @Test(expectedExceptions = NullPointerException.class) + public void test08() throws SQLException { + conn.enquoteNCharLiteral(null); + } +} diff --git a/test/jdk/java/sql/testng/test/sql/PreparedStatementTests.java b/test/jdk/java/sql/testng/test/sql/PreparedStatementTests.java index d54763189c5..7813038361d 100644 --- a/test/jdk/java/sql/testng/test/sql/PreparedStatementTests.java +++ b/test/jdk/java/sql/testng/test/sql/PreparedStatementTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, 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,14 +22,109 @@ */ package test.sql; +import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; -import util.StubPreparedStatement; +import org.testng.annotations.Test; +import util.BaseTest; +import util.StubConnection; -public class PreparedStatementTests extends StatementTests { +import java.sql.PreparedStatement; +import java.sql.SQLException; + +import static org.testng.Assert.assertEquals; + +public class PreparedStatementTests extends BaseTest { + + private PreparedStatement pstmt; @BeforeMethod public void setUpMethod() throws Exception { - stmt = new StubPreparedStatement(); + pstmt = new StubConnection().prepareStatement("Select * from foo were bar = ?"); } + @AfterMethod + public void tearDownMethod() throws Exception { + pstmt.close(); + } + + /* + * Verify that enquoteLiteral creates a valid literal and converts every + * single quote to two single quotes + */ + @Test(dataProvider = "validEnquotedLiteralValues") + public void test00(String s, String expected) throws SQLException { + assertEquals(pstmt.enquoteLiteral(s), expected); + } + + /* + * Validate a NullPointerException is thrown if the string passed to + * enquoteLiteral is null + */ + @Test(expectedExceptions = NullPointerException.class) + public void test01() throws SQLException { + pstmt.enquoteLiteral(null); + } + + /* + * Validate that enquoteIdentifier returns the expected value + */ + @Test(dataProvider = "validIdentifierValues") + public void test02(String s, boolean alwaysQuote, String expected) throws SQLException { + assertEquals(pstmt.enquoteIdentifier(s, alwaysQuote), expected); + } + + /* + * Validate that a SQLException is thrown for values that are not valid + * for a SQL identifier + */ + @Test(dataProvider = "invalidIdentifierValues", + expectedExceptions = SQLException.class) + public void test03(String s, boolean alwaysQuote) throws SQLException { + pstmt.enquoteIdentifier(s, alwaysQuote); + } + + /* + * Validate a NullPointerException is thrown is the string passed to + * enquoteIdentiifer is null + */ + @Test(dataProvider = "trueFalse", + expectedExceptions = NullPointerException.class) + public void test04(boolean alwaysQuote) throws SQLException { + pstmt.enquoteIdentifier(null, alwaysQuote); + } + + /* + * Validate that isSimpleIdentifier returns the expected value + */ + @Test(dataProvider = "simpleIdentifierValues") + public void test05(String s, boolean expected) throws SQLException { + assertEquals(pstmt.isSimpleIdentifier(s), expected); + } + + /* + * Validate a NullPointerException is thrown if the string passed to + * isSimpleIdentifier is null + */ + @Test(expectedExceptions = NullPointerException.class) + public void test06() throws SQLException { + pstmt.isSimpleIdentifier(null); + } + + /* + * Verify that enquoteLiteral creates a valid literal and converts every + * single quote to two single quotes + */ + @Test(dataProvider = "validEnquotedNCharLiteralValues") + public void test07(String s, String expected) throws SQLException { + assertEquals(pstmt.enquoteNCharLiteral(s), expected); + } + + /* + * Validate a NullPointerException is thrown if the string passed to + * enquoteNCharLiteral is null + */ + @Test(expectedExceptions = NullPointerException.class) + public void test08() throws SQLException { + pstmt.enquoteNCharLiteral(null); + } } diff --git a/test/jdk/java/sql/testng/test/sql/StatementTests.java b/test/jdk/java/sql/testng/test/sql/StatementTests.java index 88697b77f9d..f2bfe712eb5 100644 --- a/test/jdk/java/sql/testng/test/sql/StatementTests.java +++ b/test/jdk/java/sql/testng/test/sql/StatementTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, 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 @@ -23,38 +23,31 @@ package test.sql; import java.sql.SQLException; +import java.sql.Statement; + import static org.testng.Assert.assertEquals; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; + +import org.testng.annotations.*; import util.BaseTest; -import util.StubStatement; +import util.StubConnection; public class StatementTests extends BaseTest { - protected StubStatement stmt; - protected static String maxIdentifier; + private Statement stmt; @BeforeMethod public void setUpMethod() throws Exception { - stmt = new StubStatement(); + stmt = new StubConnection().createStatement(); } - @BeforeClass - public static void setUpClass() throws Exception { - int maxLen = 128; - StringBuilder s = new StringBuilder(maxLen); - for (int i = 0; i < maxLen; i++) { - s.append('a'); - } - maxIdentifier = s.toString(); + @AfterMethod + public void tearDownMethod() throws Exception { + stmt.close(); } /* * Verify that enquoteLiteral creates a valid literal and converts every * single quote to two single quotes */ - @Test(dataProvider = "validEnquotedLiteralValues") public void test00(String s, String expected) throws SQLException { assertEquals(stmt.enquoteLiteral(s), expected); @@ -67,7 +60,6 @@ public class StatementTests extends BaseTest { @Test(expectedExceptions = NullPointerException.class) public void test01() throws SQLException { stmt.enquoteLiteral(null); - } /* @@ -76,7 +68,6 @@ public class StatementTests extends BaseTest { @Test(dataProvider = "validIdentifierValues") public void test02(String s, boolean alwaysQuote, String expected) throws SQLException { assertEquals(stmt.enquoteIdentifier(s, alwaysQuote), expected); - } /* @@ -87,7 +78,6 @@ public class StatementTests extends BaseTest { expectedExceptions = SQLException.class) public void test03(String s, boolean alwaysQuote) throws SQLException { stmt.enquoteIdentifier(s, alwaysQuote); - } /* @@ -98,7 +88,6 @@ public class StatementTests extends BaseTest { expectedExceptions = NullPointerException.class) public void test04(boolean alwaysQuote) throws SQLException { stmt.enquoteIdentifier(null, alwaysQuote); - } /* @@ -116,7 +105,6 @@ public class StatementTests extends BaseTest { @Test(expectedExceptions = NullPointerException.class) public void test06() throws SQLException { stmt.isSimpleIdentifier(null); - } /* @@ -136,97 +124,4 @@ public class StatementTests extends BaseTest { public void test08() throws SQLException { stmt.enquoteNCharLiteral(null); } - - /* - * DataProvider used to provide strings that will be used to validate - * that enquoteLiteral converts a string to a literal and every instance of - * a single quote will be converted into two single quotes in the literal. - */ - @DataProvider(name = "validEnquotedLiteralValues") - protected Object[][] validEnquotedLiteralValues() { - return new Object[][]{ - {"Hello", "'Hello'"}, - {"G'Day", "'G''Day'"}, - {"'G''Day'", "'''G''''Day'''"}, - {"I'''M", "'I''''''M'"}, - {"The Dark Knight", "'The Dark Knight'"} - - }; - } - - /* - * DataProvider used to provide strings that will be used to validate - * that enqouteIdentifier returns a simple SQL Identifier or a double - * quoted identifier - */ - @DataProvider(name = "validIdentifierValues") - protected Object[][] validEnquotedIdentifierValues() { - return new Object[][]{ - {"b", false, "b"}, - {"b", true, "\"b\""}, - {maxIdentifier, false, maxIdentifier}, - {maxIdentifier, true, "\"" + maxIdentifier + "\""}, - {"Hello", false, "Hello"}, - {"Hello", true, "\"Hello\""}, - {"G'Day", false, "\"G'Day\""}, - {"G'Day", true, "\"G'Day\""}, - {"Bruce Wayne", false, "\"Bruce Wayne\""}, - {"Bruce Wayne", true, "\"Bruce Wayne\""}, - {"GoodDay$", false, "\"GoodDay$\""}, - {"GoodDay$", true, "\"GoodDay$\""},}; - } - - /* - * DataProvider used to provide strings are invalid for enquoteIdentifier - * resulting in a SQLException being thrown - */ - @DataProvider(name = "invalidIdentifierValues") - protected Object[][] invalidEnquotedIdentifierValues() { - return new Object[][]{ - {"Hel\"lo", false}, - {"\"Hel\"lo\"", true}, - {"Hello" + '\0', false}, - {"", false}, - {maxIdentifier + 'a', false},}; - } - - /* - * DataProvider used to provide strings that will be used to validate - * that isSimpleIdentifier returns the correct value based on the - * identifier specified. - */ - @DataProvider(name = "simpleIdentifierValues") - protected Object[][] simpleIdentifierValues() { - return new Object[][]{ - {"b", true}, - {"Hello", true}, - {"\"Gotham\"", false}, - {"G'Day", false}, - {"Bruce Wayne", false}, - {"GoodDay$", false}, - {"Dick_Grayson", true}, - {"Batmobile1966", true}, - {maxIdentifier, true}, - {maxIdentifier + 'a', false}, - {"", false},}; - } - - /* - * DataProvider used to provide strings that will be used to validate - * that enquoteNCharLiteral converts a string to a National Character - * literal and every instance of - * a single quote will be converted into two single quotes in the literal. - */ - @DataProvider(name = "validEnquotedNCharLiteralValues") - protected Object[][] validEnquotedNCharLiteralValues() { - return new Object[][]{ - {"Hello", "N'Hello'"}, - {"G'Day", "N'G''Day'"}, - {"'G''Day'", "N'''G''''Day'''"}, - {"I'''M", "N'I''''''M'"}, - {"N'Hello'", "N'N''Hello'''"}, - {"The Dark Knight", "N'The Dark Knight'"} - - }; - } } diff --git a/test/jdk/java/sql/testng/test/sql/TimestampTests.java b/test/jdk/java/sql/testng/test/sql/TimestampTests.java index fefe3276d47..6baea9fa26f 100644 --- a/test/jdk/java/sql/testng/test/sql/TimestampTests.java +++ b/test/jdk/java/sql/testng/test/sql/TimestampTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, 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 @@ -667,6 +667,44 @@ public class TimestampTests extends BaseTest { expectThrows(IllegalArgumentException.class, () -> Timestamp.from(Instant.MIN)); } + /* + * Validate that two Timestamp hashCode values are equal when + * the Timestamp values match, including the nanos. + */ + @Test + public void test54() { + long t = System.currentTimeMillis(); + Timestamp ts1 = new Timestamp(t); + Timestamp ts2 = new Timestamp(t); + ts1.setNanos(123456789); + ts2.setNanos(123456789); + assertTrue(ts1.equals(ts1)); + assertTrue(ts2.equals(ts2)); + assertTrue(ts1.equals(ts2)); + // As the Timestamp values, including the nanos are the same, the hashCode's + // should be equal + assertEquals(ts1.hashCode(), ts2.hashCode()); + } + + /* + * Validate that two Timestamp hashCode values are not equal when only + * the nanos value for the Timestamp differ. + */ + @Test + public void test55() { + long t = System.currentTimeMillis(); + Timestamp ts1 = new Timestamp(t); + Timestamp ts2 = new Timestamp(t); + // Modify the nanos so that the Timestamp values differ + ts1.setNanos(123456789); + ts2.setNanos(987654321); + assertTrue(ts1.equals(ts1)); + assertTrue(ts2.equals(ts2)); + assertFalse(ts1.equals(ts2)); + // As the nanos differ, the hashCode values should differ + assertNotEquals(ts1.hashCode(), ts2.hashCode()); + } + /* * DataProvider used to provide Timestamps which are not valid and are used * to validate that an IllegalArgumentException will be thrown from the diff --git a/test/jdk/java/sql/testng/util/BaseTest.java b/test/jdk/java/sql/testng/util/BaseTest.java index 6821940b7ce..8751183726d 100644 --- a/test/jdk/java/sql/testng/util/BaseTest.java +++ b/test/jdk/java/sql/testng/util/BaseTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, 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,13 +27,9 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; -import java.security.Policy; import java.sql.JDBCType; import java.sql.SQLException; -import org.testng.annotations.AfterClass; -import org.testng.annotations.AfterMethod; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.BeforeMethod; + import org.testng.annotations.DataProvider; public class BaseTest { @@ -47,22 +43,7 @@ public class BaseTest { protected final int errorCode = 21; protected final String[] msgs = {"Exception 1", "cause 1", "Exception 2", "Exception 3", "cause 2"}; - - @BeforeClass - public static void setUpClass() throws Exception { - } - - @AfterClass - public static void tearDownClass() throws Exception { - } - - @BeforeMethod - public void setUpMethod() throws Exception { - } - - @AfterMethod - public void tearDownMethod() throws Exception { - } + private static final String MAX_LENGTH_IDENTIFIER = "a".repeat(128); /* * Take some form of SQLException, serialize and deserialize it @@ -92,13 +73,6 @@ public class BaseTest { return o1; } - /* - * Utility Method used to set the current Policy - */ - protected static void setPolicy(Policy p) { - Policy.setPolicy(p); - } - /* * DataProvider used to specify the value to set and check for * methods using boolean values @@ -123,4 +97,99 @@ public class BaseTest { } return o; } + + /* + * DataProvider used to provide strings that will be used to validate + * that enquoteLiteral converts a string to a literal and every instance of + * a single quote will be converted into two single quotes in the literal. + */ + @DataProvider(name = "validEnquotedLiteralValues") + protected Object[][] validEnquotedLiteralValues() { + return new Object[][]{ + {"Hello", "'Hello'"}, + {"G'Day", "'G''Day'"}, + {"'G''Day'", "'''G''''Day'''"}, + {"I'''M", "'I''''''M'"}, + {"The Dark Knight", "'The Dark Knight'"}, + }; + } + + /* + * DataProvider used to provide strings that will be used to validate + * that enqouteIdentifier returns a simple SQL Identifier or a + * quoted identifier + */ + @DataProvider(name = "validIdentifierValues") + protected Object[][] validEnquotedIdentifierValues() { + return new Object[][]{ + {"b", false, "b"}, + {"b", true, "\"b\""}, + {MAX_LENGTH_IDENTIFIER, false, MAX_LENGTH_IDENTIFIER}, + {MAX_LENGTH_IDENTIFIER, true, "\"" + MAX_LENGTH_IDENTIFIER + "\""}, + {"Hello", false, "Hello"}, + {"Hello", true, "\"Hello\""}, + {"G'Day", false, "\"G'Day\""}, + {"G'Day", true, "\"G'Day\""}, + {"Bruce Wayne", false, "\"Bruce Wayne\""}, + {"Bruce Wayne", true, "\"Bruce Wayne\""}, + {"select", false, "\"select\""}, + {"table", true, "\"table\""}, + {"GoodDay$", false, "\"GoodDay$\""}, + {"GoodDay$", true, "\"GoodDay$\""},}; + } + + /* + * DataProvider used to provide strings are invalid for enquoteIdentifier + * resulting in a SQLException being thrown + */ + @DataProvider(name = "invalidIdentifierValues") + protected Object[][] invalidEnquotedIdentifierValues() { + return new Object[][]{ + {"Hel\"lo", false}, + {"\"Hel\"lo\"", true}, + {"Hello" + '\0', false}, + {"", false}, + {MAX_LENGTH_IDENTIFIER + 'a', false},}; + } + + /* + * DataProvider used to provide strings that will be used to validate + * that isSimpleIdentifier returns the correct value based on the + * identifier specified. + */ + @DataProvider(name = "simpleIdentifierValues") + protected Object[][] simpleIdentifierValues() { + return new Object[][]{ + {"b", true}, + {"Hello", true}, + {"\"Gotham\"", false}, + {"G'Day", false}, + {"Bruce Wayne", false}, + {"GoodDay$", false}, + {"Dick_Grayson", true}, + {"Batmobile1966", true}, + {MAX_LENGTH_IDENTIFIER, true}, + {MAX_LENGTH_IDENTIFIER + 'a', false}, + {"", false}, + {"select", false} + }; + } + + /* + * DataProvider used to provide strings that will be used to validate + * that enquoteNCharLiteral converts a string to a National Character + * literal and every instance of + * a single quote will be converted into two single quotes in the literal. + */ + @DataProvider(name = "validEnquotedNCharLiteralValues") + protected Object[][] validEnquotedNCharLiteralValues() { + return new Object[][]{ + {"Hello", "N'Hello'"}, + {"G'Day", "N'G''Day'"}, + {"'G''Day'", "N'''G''''Day'''"}, + {"I'''M", "N'I''''''M'"}, + {"N'Hello'", "N'N''Hello'''"}, + {"The Dark Knight", "N'The Dark Knight'"} + }; + } } diff --git a/test/jdk/java/sql/testng/util/StubCallableStatement.java b/test/jdk/java/sql/testng/util/StubCallableStatement.java index 1833a44d56d..4a7c27314bb 100644 --- a/test/jdk/java/sql/testng/util/StubCallableStatement.java +++ b/test/jdk/java/sql/testng/util/StubCallableStatement.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, 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,24 +26,17 @@ import java.io.InputStream; import java.io.Reader; import java.math.BigDecimal; import java.net.URL; -import java.sql.Array; -import java.sql.Blob; -import java.sql.CallableStatement; -import java.sql.Clob; -import java.sql.Date; -import java.sql.NClob; -import java.sql.Ref; -import java.sql.RowId; -import java.sql.SQLException; -import java.sql.SQLXML; -import java.sql.Time; -import java.sql.Timestamp; +import java.sql.*; import java.util.Calendar; import java.util.Map; public class StubCallableStatement extends StubPreparedStatement implements CallableStatement{ + public StubCallableStatement(StubConnection con) { + super(con); + } + @Override public void registerOutParameter(int parameterIndex, int sqlType) throws SQLException { throw new UnsupportedOperationException("Not supported yet."); @@ -608,5 +601,4 @@ implements CallableStatement{ public T getObject(String parameterName, Class type) throws SQLException { throw new UnsupportedOperationException("Not supported yet."); } - } diff --git a/test/jdk/java/sql/testng/util/StubConnection.java b/test/jdk/java/sql/testng/util/StubConnection.java index b9ab97062d3..cd013572adc 100644 --- a/test/jdk/java/sql/testng/util/StubConnection.java +++ b/test/jdk/java/sql/testng/util/StubConnection.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, 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 @@ -44,20 +44,25 @@ import java.util.concurrent.Executor; public class StubConnection implements Connection { private boolean autoCommit = false; + private boolean isclosed; + + public StubConnection() { + isclosed = false; + } @Override public Statement createStatement() throws SQLException { - throw new UnsupportedOperationException("Not supported yet."); + return new StubStatement(this); } @Override public PreparedStatement prepareStatement(String sql) throws SQLException { - throw new UnsupportedOperationException("Not supported yet."); + return new StubPreparedStatement(this); } @Override public CallableStatement prepareCall(String sql) throws SQLException { - throw new UnsupportedOperationException("Not supported yet."); + return new StubCallableStatement(this); } @Override @@ -89,17 +94,17 @@ public class StubConnection implements Connection { @Override public void close() throws SQLException { - throw new UnsupportedOperationException("Not supported yet."); + isclosed = true; } @Override public boolean isClosed() throws SQLException { - throw new UnsupportedOperationException("Not supported yet."); + return isclosed; } @Override public DatabaseMetaData getMetaData() throws SQLException { - throw new UnsupportedOperationException("Not supported yet."); + return new StubDatabaseMetaData(); } @Override diff --git a/test/jdk/java/sql/testng/util/StubDatabaseMetaData.java b/test/jdk/java/sql/testng/util/StubDatabaseMetaData.java new file mode 100644 index 00000000000..3bf70afaa8f --- /dev/null +++ b/test/jdk/java/sql/testng/util/StubDatabaseMetaData.java @@ -0,0 +1,907 @@ +/* + * Copyright (c) 2025, 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 util; + +import java.sql.*; + +public class StubDatabaseMetaData implements DatabaseMetaData { + @Override + public boolean allProceduresAreCallable() throws SQLException { + return false; + } + + @Override + public boolean allTablesAreSelectable() throws SQLException { + return false; + } + + @Override + public String getURL() throws SQLException { + return ""; + } + + @Override + public String getUserName() throws SQLException { + return ""; + } + + @Override + public boolean isReadOnly() throws SQLException { + return false; + } + + @Override + public boolean nullsAreSortedHigh() throws SQLException { + return false; + } + + @Override + public boolean nullsAreSortedLow() throws SQLException { + return false; + } + + @Override + public boolean nullsAreSortedAtStart() throws SQLException { + return false; + } + + @Override + public boolean nullsAreSortedAtEnd() throws SQLException { + return false; + } + + @Override + public String getDatabaseProductName() throws SQLException { + return ""; + } + + @Override + public String getDatabaseProductVersion() throws SQLException { + return ""; + } + + @Override + public String getDriverName() throws SQLException { + return ""; + } + + @Override + public String getDriverVersion() throws SQLException { + return ""; + } + + @Override + public int getDriverMajorVersion() { + return 0; + } + + @Override + public int getDriverMinorVersion() { + return 0; + } + + @Override + public boolean usesLocalFiles() throws SQLException { + return false; + } + + @Override + public boolean usesLocalFilePerTable() throws SQLException { + return false; + } + + @Override + public boolean supportsMixedCaseIdentifiers() throws SQLException { + return false; + } + + @Override + public boolean storesUpperCaseIdentifiers() throws SQLException { + return false; + } + + @Override + public boolean storesLowerCaseIdentifiers() throws SQLException { + return false; + } + + @Override + public boolean storesMixedCaseIdentifiers() throws SQLException { + return false; + } + + @Override + public boolean supportsMixedCaseQuotedIdentifiers() throws SQLException { + return false; + } + + @Override + public boolean storesUpperCaseQuotedIdentifiers() throws SQLException { + return false; + } + + @Override + public boolean storesLowerCaseQuotedIdentifiers() throws SQLException { + return false; + } + + @Override + public boolean storesMixedCaseQuotedIdentifiers() throws SQLException { + return false; + } + + @Override + public String getIdentifierQuoteString() throws SQLException { + return "\""; + } + + @Override + public String getSQLKeywords() throws SQLException { + return ""; + } + + @Override + public String getNumericFunctions() throws SQLException { + return ""; + } + + @Override + public String getStringFunctions() throws SQLException { + return ""; + } + + @Override + public String getSystemFunctions() throws SQLException { + return ""; + } + + @Override + public String getTimeDateFunctions() throws SQLException { + return ""; + } + + @Override + public String getSearchStringEscape() throws SQLException { + return ""; + } + + @Override + public String getExtraNameCharacters() throws SQLException { + return ""; + } + + @Override + public boolean supportsAlterTableWithAddColumn() throws SQLException { + return false; + } + + @Override + public boolean supportsAlterTableWithDropColumn() throws SQLException { + return false; + } + + @Override + public boolean supportsColumnAliasing() throws SQLException { + return false; + } + + @Override + public boolean nullPlusNonNullIsNull() throws SQLException { + return false; + } + + @Override + public boolean supportsConvert() throws SQLException { + return false; + } + + @Override + public boolean supportsConvert(int fromType, int toType) throws SQLException { + return false; + } + + @Override + public boolean supportsTableCorrelationNames() throws SQLException { + return false; + } + + @Override + public boolean supportsDifferentTableCorrelationNames() throws SQLException { + return false; + } + + @Override + public boolean supportsExpressionsInOrderBy() throws SQLException { + return false; + } + + @Override + public boolean supportsOrderByUnrelated() throws SQLException { + return false; + } + + @Override + public boolean supportsGroupBy() throws SQLException { + return false; + } + + @Override + public boolean supportsGroupByUnrelated() throws SQLException { + return false; + } + + @Override + public boolean supportsGroupByBeyondSelect() throws SQLException { + return false; + } + + @Override + public boolean supportsLikeEscapeClause() throws SQLException { + return false; + } + + @Override + public boolean supportsMultipleResultSets() throws SQLException { + return false; + } + + @Override + public boolean supportsMultipleTransactions() throws SQLException { + return false; + } + + @Override + public boolean supportsNonNullableColumns() throws SQLException { + return false; + } + + @Override + public boolean supportsMinimumSQLGrammar() throws SQLException { + return false; + } + + @Override + public boolean supportsCoreSQLGrammar() throws SQLException { + return false; + } + + @Override + public boolean supportsExtendedSQLGrammar() throws SQLException { + return false; + } + + @Override + public boolean supportsANSI92EntryLevelSQL() throws SQLException { + return false; + } + + @Override + public boolean supportsANSI92IntermediateSQL() throws SQLException { + return false; + } + + @Override + public boolean supportsANSI92FullSQL() throws SQLException { + return false; + } + + @Override + public boolean supportsIntegrityEnhancementFacility() throws SQLException { + return false; + } + + @Override + public boolean supportsOuterJoins() throws SQLException { + return false; + } + + @Override + public boolean supportsFullOuterJoins() throws SQLException { + return false; + } + + @Override + public boolean supportsLimitedOuterJoins() throws SQLException { + return false; + } + + @Override + public String getSchemaTerm() throws SQLException { + return ""; + } + + @Override + public String getProcedureTerm() throws SQLException { + return ""; + } + + @Override + public String getCatalogTerm() throws SQLException { + return ""; + } + + @Override + public boolean isCatalogAtStart() throws SQLException { + return false; + } + + @Override + public String getCatalogSeparator() throws SQLException { + return ""; + } + + @Override + public boolean supportsSchemasInDataManipulation() throws SQLException { + return false; + } + + @Override + public boolean supportsSchemasInProcedureCalls() throws SQLException { + return false; + } + + @Override + public boolean supportsSchemasInTableDefinitions() throws SQLException { + return false; + } + + @Override + public boolean supportsSchemasInIndexDefinitions() throws SQLException { + return false; + } + + @Override + public boolean supportsSchemasInPrivilegeDefinitions() throws SQLException { + return false; + } + + @Override + public boolean supportsCatalogsInDataManipulation() throws SQLException { + return false; + } + + @Override + public boolean supportsCatalogsInProcedureCalls() throws SQLException { + return false; + } + + @Override + public boolean supportsCatalogsInTableDefinitions() throws SQLException { + return false; + } + + @Override + public boolean supportsCatalogsInIndexDefinitions() throws SQLException { + return false; + } + + @Override + public boolean supportsCatalogsInPrivilegeDefinitions() throws SQLException { + return false; + } + + @Override + public boolean supportsPositionedDelete() throws SQLException { + return false; + } + + @Override + public boolean supportsPositionedUpdate() throws SQLException { + return false; + } + + @Override + public boolean supportsSelectForUpdate() throws SQLException { + return false; + } + + @Override + public boolean supportsStoredProcedures() throws SQLException { + return false; + } + + @Override + public boolean supportsSubqueriesInComparisons() throws SQLException { + return false; + } + + @Override + public boolean supportsSubqueriesInExists() throws SQLException { + return false; + } + + @Override + public boolean supportsSubqueriesInIns() throws SQLException { + return false; + } + + @Override + public boolean supportsSubqueriesInQuantifieds() throws SQLException { + return false; + } + + @Override + public boolean supportsCorrelatedSubqueries() throws SQLException { + return false; + } + + @Override + public boolean supportsUnion() throws SQLException { + return false; + } + + @Override + public boolean supportsUnionAll() throws SQLException { + return false; + } + + @Override + public boolean supportsOpenCursorsAcrossCommit() throws SQLException { + return false; + } + + @Override + public boolean supportsOpenCursorsAcrossRollback() throws SQLException { + return false; + } + + @Override + public boolean supportsOpenStatementsAcrossCommit() throws SQLException { + return false; + } + + @Override + public boolean supportsOpenStatementsAcrossRollback() throws SQLException { + return false; + } + + @Override + public int getMaxBinaryLiteralLength() throws SQLException { + return 0; + } + + @Override + public int getMaxCharLiteralLength() throws SQLException { + return 0; + } + + @Override + public int getMaxColumnNameLength() throws SQLException { + return 0; + } + + @Override + public int getMaxColumnsInGroupBy() throws SQLException { + return 0; + } + + @Override + public int getMaxColumnsInIndex() throws SQLException { + return 0; + } + + @Override + public int getMaxColumnsInOrderBy() throws SQLException { + return 0; + } + + @Override + public int getMaxColumnsInSelect() throws SQLException { + return 0; + } + + @Override + public int getMaxColumnsInTable() throws SQLException { + return 0; + } + + @Override + public int getMaxConnections() throws SQLException { + return 0; + } + + @Override + public int getMaxCursorNameLength() throws SQLException { + return 0; + } + + @Override + public int getMaxIndexLength() throws SQLException { + return 0; + } + + @Override + public int getMaxSchemaNameLength() throws SQLException { + return 0; + } + + @Override + public int getMaxProcedureNameLength() throws SQLException { + return 0; + } + + @Override + public int getMaxCatalogNameLength() throws SQLException { + return 0; + } + + @Override + public int getMaxRowSize() throws SQLException { + return 0; + } + + @Override + public boolean doesMaxRowSizeIncludeBlobs() throws SQLException { + return false; + } + + @Override + public int getMaxStatementLength() throws SQLException { + return 0; + } + + @Override + public int getMaxStatements() throws SQLException { + return 0; + } + + @Override + public int getMaxTableNameLength() throws SQLException { + return 0; + } + + @Override + public int getMaxTablesInSelect() throws SQLException { + return 0; + } + + @Override + public int getMaxUserNameLength() throws SQLException { + return 0; + } + + @Override + public int getDefaultTransactionIsolation() throws SQLException { + return 0; + } + + @Override + public boolean supportsTransactions() throws SQLException { + return false; + } + + @Override + public boolean supportsTransactionIsolationLevel(int level) throws SQLException { + return false; + } + + @Override + public boolean supportsDataDefinitionAndDataManipulationTransactions() throws SQLException { + return false; + } + + @Override + public boolean supportsDataManipulationTransactionsOnly() throws SQLException { + return false; + } + + @Override + public boolean dataDefinitionCausesTransactionCommit() throws SQLException { + return false; + } + + @Override + public boolean dataDefinitionIgnoredInTransactions() throws SQLException { + return false; + } + + @Override + public ResultSet getProcedures(String catalog, String schemaPattern, String procedureNamePattern) throws SQLException { + return null; + } + + @Override + public ResultSet getProcedureColumns(String catalog, String schemaPattern, String procedureNamePattern, String columnNamePattern) throws SQLException { + return null; + } + + @Override + public ResultSet getTables(String catalog, String schemaPattern, String tableNamePattern, String[] types) throws SQLException { + return null; + } + + @Override + public ResultSet getSchemas() throws SQLException { + return null; + } + + @Override + public ResultSet getCatalogs() throws SQLException { + return null; + } + + @Override + public ResultSet getTableTypes() throws SQLException { + return null; + } + + @Override + public ResultSet getColumns(String catalog, String schemaPattern, String tableNamePattern, String columnNamePattern) throws SQLException { + return null; + } + + @Override + public ResultSet getColumnPrivileges(String catalog, String schema, String table, String columnNamePattern) throws SQLException { + return null; + } + + @Override + public ResultSet getTablePrivileges(String catalog, String schemaPattern, String tableNamePattern) throws SQLException { + return null; + } + + @Override + public ResultSet getBestRowIdentifier(String catalog, String schema, String table, int scope, boolean nullable) throws SQLException { + return null; + } + + @Override + public ResultSet getVersionColumns(String catalog, String schema, String table) throws SQLException { + return null; + } + + @Override + public ResultSet getPrimaryKeys(String catalog, String schema, String table) throws SQLException { + return null; + } + + @Override + public ResultSet getImportedKeys(String catalog, String schema, String table) throws SQLException { + return null; + } + + @Override + public ResultSet getExportedKeys(String catalog, String schema, String table) throws SQLException { + return null; + } + + @Override + public ResultSet getCrossReference(String parentCatalog, String parentSchema, String parentTable, String foreignCatalog, String foreignSchema, String foreignTable) throws SQLException { + return null; + } + + @Override + public ResultSet getTypeInfo() throws SQLException { + return null; + } + + @Override + public ResultSet getIndexInfo(String catalog, String schema, String table, boolean unique, boolean approximate) throws SQLException { + return null; + } + + @Override + public boolean supportsResultSetType(int type) throws SQLException { + return false; + } + + @Override + public boolean supportsResultSetConcurrency(int type, int concurrency) throws SQLException { + return false; + } + + @Override + public boolean ownUpdatesAreVisible(int type) throws SQLException { + return false; + } + + @Override + public boolean ownDeletesAreVisible(int type) throws SQLException { + return false; + } + + @Override + public boolean ownInsertsAreVisible(int type) throws SQLException { + return false; + } + + @Override + public boolean othersUpdatesAreVisible(int type) throws SQLException { + return false; + } + + @Override + public boolean othersDeletesAreVisible(int type) throws SQLException { + return false; + } + + @Override + public boolean othersInsertsAreVisible(int type) throws SQLException { + return false; + } + + @Override + public boolean updatesAreDetected(int type) throws SQLException { + return false; + } + + @Override + public boolean deletesAreDetected(int type) throws SQLException { + return false; + } + + @Override + public boolean insertsAreDetected(int type) throws SQLException { + return false; + } + + @Override + public boolean supportsBatchUpdates() throws SQLException { + return false; + } + + @Override + public ResultSet getUDTs(String catalog, String schemaPattern, String typeNamePattern, int[] types) throws SQLException { + return null; + } + + @Override + public Connection getConnection() throws SQLException { + return null; + } + + @Override + public boolean supportsSavepoints() throws SQLException { + return false; + } + + @Override + public boolean supportsNamedParameters() throws SQLException { + return false; + } + + @Override + public boolean supportsMultipleOpenResults() throws SQLException { + return false; + } + + @Override + public boolean supportsGetGeneratedKeys() throws SQLException { + return false; + } + + @Override + public ResultSet getSuperTypes(String catalog, String schemaPattern, String typeNamePattern) throws SQLException { + return null; + } + + @Override + public ResultSet getSuperTables(String catalog, String schemaPattern, String tableNamePattern) throws SQLException { + return null; + } + + @Override + public ResultSet getAttributes(String catalog, String schemaPattern, String typeNamePattern, String attributeNamePattern) throws SQLException { + return null; + } + + @Override + public boolean supportsResultSetHoldability(int holdability) throws SQLException { + return false; + } + + @Override + public int getResultSetHoldability() throws SQLException { + return 0; + } + + @Override + public int getDatabaseMajorVersion() throws SQLException { + return 0; + } + + @Override + public int getDatabaseMinorVersion() throws SQLException { + return 0; + } + + @Override + public int getJDBCMajorVersion() throws SQLException { + return 0; + } + + @Override + public int getJDBCMinorVersion() throws SQLException { + return 0; + } + + @Override + public int getSQLStateType() throws SQLException { + return 0; + } + + @Override + public boolean locatorsUpdateCopy() throws SQLException { + return false; + } + + @Override + public boolean supportsStatementPooling() throws SQLException { + return false; + } + + @Override + public RowIdLifetime getRowIdLifetime() throws SQLException { + return null; + } + + @Override + public ResultSet getSchemas(String catalog, String schemaPattern) throws SQLException { + return null; + } + + @Override + public boolean supportsStoredFunctionsUsingCallSyntax() throws SQLException { + return false; + } + + @Override + public boolean autoCommitFailureClosesAllResultSets() throws SQLException { + return false; + } + + @Override + public ResultSet getClientInfoProperties() throws SQLException { + return null; + } + + @Override + public ResultSet getFunctions(String catalog, String schemaPattern, String functionNamePattern) throws SQLException { + return null; + } + + @Override + public ResultSet getFunctionColumns(String catalog, String schemaPattern, String functionNamePattern, String columnNamePattern) throws SQLException { + return null; + } + + @Override + public ResultSet getPseudoColumns(String catalog, String schemaPattern, String tableNamePattern, String columnNamePattern) throws SQLException { + return null; + } + + @Override + public boolean generatedKeyAlwaysReturned() throws SQLException { + return false; + } + + @Override + public T unwrap(Class iface) throws SQLException { + return null; + } + + @Override + public boolean isWrapperFor(Class iface) throws SQLException { + return false; + } +} diff --git a/test/jdk/java/sql/testng/util/StubPreparedStatement.java b/test/jdk/java/sql/testng/util/StubPreparedStatement.java index 4e272bcee2d..a3b95a65f4e 100644 --- a/test/jdk/java/sql/testng/util/StubPreparedStatement.java +++ b/test/jdk/java/sql/testng/util/StubPreparedStatement.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, 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,25 +26,15 @@ import java.io.InputStream; import java.io.Reader; import java.math.BigDecimal; import java.net.URL; -import java.sql.Array; -import java.sql.Blob; -import java.sql.Clob; -import java.sql.Date; -import java.sql.NClob; -import java.sql.ParameterMetaData; -import java.sql.PreparedStatement; -import java.sql.Ref; -import java.sql.ResultSet; -import java.sql.ResultSetMetaData; -import java.sql.RowId; -import java.sql.SQLException; -import java.sql.SQLXML; -import java.sql.Time; -import java.sql.Timestamp; +import java.sql.*; import java.util.Calendar; public class StubPreparedStatement extends StubStatement implements PreparedStatement{ + public StubPreparedStatement(StubConnection con) { + super(con); + } + @Override public ResultSet executeQuery() throws SQLException { throw new UnsupportedOperationException("Not supported yet."); @@ -319,5 +309,4 @@ public class StubPreparedStatement extends StubStatement implements PreparedStat public void setNClob(int parameterIndex, Reader reader) throws SQLException { throw new UnsupportedOperationException("Not supported yet."); } - } diff --git a/test/jdk/java/sql/testng/util/StubStatement.java b/test/jdk/java/sql/testng/util/StubStatement.java index df792e2e4fe..c8f6a3ac071 100644 --- a/test/jdk/java/sql/testng/util/StubStatement.java +++ b/test/jdk/java/sql/testng/util/StubStatement.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, 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,11 +27,15 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.sql.SQLWarning; import java.sql.Statement; -import java.util.regex.Pattern; -import static java.util.stream.Collectors.joining; public class StubStatement implements Statement { + protected final Connection con; + + public StubStatement(StubConnection con) { + this.con = con; + } + @Override public ResultSet executeQuery(String sql) throws SQLException { throw new UnsupportedOperationException("Not supported yet."); @@ -44,7 +48,7 @@ public class StubStatement implements Statement { @Override public void close() throws SQLException { - throw new UnsupportedOperationException("Not supported yet."); + con.close(); } @Override @@ -169,7 +173,7 @@ public class StubStatement implements Statement { @Override public Connection getConnection() throws SQLException { - throw new UnsupportedOperationException("Not supported yet."); + return con; } @Override @@ -251,7 +255,4 @@ public class StubStatement implements Statement { public boolean isWrapperFor(Class iface) throws SQLException { throw new UnsupportedOperationException("Not supported yet."); } - - - } diff --git a/test/jdk/javax/sql/testng/test/rowset/serial/SQLInputImplTests.java b/test/jdk/javax/sql/testng/test/rowset/serial/SQLInputImplTests.java index 95cc508828a..5bd10ed8848 100644 --- a/test/jdk/javax/sql/testng/test/rowset/serial/SQLInputImplTests.java +++ b/test/jdk/javax/sql/testng/test/rowset/serial/SQLInputImplTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, 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,7 +55,6 @@ public class SQLInputImplTests extends BaseTest { private final String sqlType = "SUPERHERO"; @BeforeMethod - @Override public void setUpMethod() throws Exception { map = new HashMap<>(); impl = new TestSQLDataImpl("TestSQLData"); @@ -120,7 +119,6 @@ public class SQLInputImplTests extends BaseTest { SQLInputImpl sqli = new SQLInputImpl(values, map); Object o = sqli.readObject(); assertTrue(hero.equals(o)); - } /* @@ -204,8 +202,6 @@ public class SQLInputImplTests extends BaseTest { Object[] values = {struct}; SQLInputImpl sqli = new SQLInputImpl(values, map); Object o = sqli.readObject(); - assertTrue(hero.equals(o)); - } } diff --git a/test/jdk/javax/sql/testng/test/rowset/serial/SQLOutputImplTests.java b/test/jdk/javax/sql/testng/test/rowset/serial/SQLOutputImplTests.java index 00f62df6f79..1f90c9981a7 100644 --- a/test/jdk/javax/sql/testng/test/rowset/serial/SQLOutputImplTests.java +++ b/test/jdk/javax/sql/testng/test/rowset/serial/SQLOutputImplTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, 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 @@ -65,7 +65,6 @@ public class SQLOutputImplTests extends BaseTest { private SQLOutputImpl outImpl; @BeforeMethod - @Override public void setUpMethod() throws Exception { results = new Vector(); impl = new TestSQLDataImpl("TestSQLData"); From 3fd551f9926601b05a13a22b556d55425a37ee4d Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Mon, 1 Dec 2025 02:29:53 +0000 Subject: [PATCH 058/706] 8371769: TestMemoryInvisibleParent.java fails with java.nio.file.AccessDeniedException Reviewed-by: sgehwolf, shade --- .../docker/TestMemoryInvisibleParent.java | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/test/hotspot/jtreg/containers/docker/TestMemoryInvisibleParent.java b/test/hotspot/jtreg/containers/docker/TestMemoryInvisibleParent.java index 208dd603615..68331f26766 100644 --- a/test/hotspot/jtreg/containers/docker/TestMemoryInvisibleParent.java +++ b/test/hotspot/jtreg/containers/docker/TestMemoryInvisibleParent.java @@ -33,6 +33,7 @@ import java.nio.file.Path; import java.nio.file.Files; import java.util.ArrayList; +import jdk.test.lib.Platform; import jtreg.SkippedException; /* @@ -64,6 +65,9 @@ public class TestMemoryInvisibleParent { if (DockerTestUtils.isRootless()) { throw new SkippedException("Test skipped in rootless mode"); } + if (!Platform.isRoot()) { + throw new SkippedException("Test should be run as root"); + } DockerTestUtils.buildJdkContainerImage(imageName); if ("cgroupv1".equals(metrics.getProvider())) { @@ -84,16 +88,16 @@ public class TestMemoryInvisibleParent { Common.logNewTestCase("Cgroup V1 hidden parent memory limit: " + valueToSet); try { - String cgroupParent = setParentWithLimit(valueToSet); - DockerRunOptions opts = new DockerRunOptions(imageName, "/jdk/bin/java", "-version", "-Xlog:os+container=trace"); - opts.appendTestJavaOptions = false; - if (DockerTestUtils.isPodman()) { - // Podman needs to run this test with engine option --cgroup-manager=cgroupfs - opts.addEngineOpts("--cgroup-manager", "cgroupfs"); - } - opts.addDockerOpts("--cgroup-parent=/" + cgroupParent); - Common.run(opts) - .shouldContain("Hierarchical Memory Limit is: " + expectedValue); + String cgroupParent = setParentWithLimit(valueToSet); + DockerRunOptions opts = new DockerRunOptions(imageName, "/jdk/bin/java", "-version", "-Xlog:os+container=trace"); + opts.appendTestJavaOptions = false; + if (DockerTestUtils.isPodman()) { + // Podman needs to run this test with engine option --cgroup-manager=cgroupfs + opts.addEngineOpts("--cgroup-manager", "cgroupfs"); + } + opts.addDockerOpts("--cgroup-parent=/" + cgroupParent); + Common.run(opts) + .shouldContain("Hierarchical Memory Limit is: " + expectedValue); } finally { // Reset the parent memory limit to unlimited (-1) setParentWithLimit(UNLIMITED); From c7a489db9e4a7d696623fc2155a5504d9d2adb0d Mon Sep 17 00:00:00 2001 From: Jayathirth D V Date: Mon, 1 Dec 2025 05:40:51 +0000 Subject: [PATCH 059/706] 8372534: Update Libpng to 1.6.51 Reviewed-by: serb, azvegint, prr --- .../java.desktop/lib/ClientLibraries.gmk | 3 +- src/java.desktop/share/legal/libpng.md | 12 +- .../native/libsplashscreen/libpng/CHANGES | 53 +++++++ .../native/libsplashscreen/libpng/README | 4 +- .../share/native/libsplashscreen/libpng/png.c | 28 ++-- .../share/native/libsplashscreen/libpng/png.h | 73 +++++---- .../native/libsplashscreen/libpng/pngconf.h | 47 +++--- .../native/libsplashscreen/libpng/pngdebug.h | 11 +- .../native/libsplashscreen/libpng/pngerror.c | 140 +----------------- .../native/libsplashscreen/libpng/pngget.c | 2 +- .../native/libsplashscreen/libpng/pnginfo.h | 51 ++----- .../libsplashscreen/libpng/pnglibconf.h | 2 +- .../native/libsplashscreen/libpng/pngmem.c | 2 +- .../native/libsplashscreen/libpng/pngpread.c | 10 +- .../native/libsplashscreen/libpng/pngpriv.h | 88 ++++++++--- .../native/libsplashscreen/libpng/pngread.c | 87 ++++++++++- .../native/libsplashscreen/libpng/pngrio.c | 4 +- .../native/libsplashscreen/libpng/pngrtran.c | 116 ++++++++++----- .../native/libsplashscreen/libpng/pngrutil.c | 14 +- .../native/libsplashscreen/libpng/pngset.c | 19 +-- .../native/libsplashscreen/libpng/pngstruct.h | 16 +- 21 files changed, 436 insertions(+), 346 deletions(-) diff --git a/make/modules/java.desktop/lib/ClientLibraries.gmk b/make/modules/java.desktop/lib/ClientLibraries.gmk index b036973b776..4cd7f5bac90 100644 --- a/make/modules/java.desktop/lib/ClientLibraries.gmk +++ b/make/modules/java.desktop/lib/ClientLibraries.gmk @@ -237,7 +237,7 @@ ifeq ($(ENABLE_HEADLESS_ONLY), false) DISABLED_WARNINGS_gcc_dgif_lib.c := sign-compare, \ DISABLED_WARNINGS_gcc_jcmaster.c := implicit-fallthrough, \ DISABLED_WARNINGS_gcc_jdphuff.c := shift-negative-value, \ - DISABLED_WARNINGS_gcc_png.c := maybe-uninitialized unused-function, \ + DISABLED_WARNINGS_gcc_png.c := maybe-uninitialized, \ DISABLED_WARNINGS_gcc_pngerror.c := maybe-uninitialized, \ DISABLED_WARNINGS_gcc_splashscreen_gfx_impl.c := implicit-fallthrough \ maybe-uninitialized, \ @@ -248,7 +248,6 @@ ifeq ($(ENABLE_HEADLESS_ONLY), false) DISABLED_WARNINGS_clang := deprecated-non-prototype, \ DISABLED_WARNINGS_clang_dgif_lib.c := sign-compare, \ DISABLED_WARNINGS_clang_gzwrite.c := format-nonliteral, \ - DISABLED_WARNINGS_clang_png.c := unused-function, \ DISABLED_WARNINGS_clang_splashscreen_impl.c := sign-compare \ unused-but-set-variable unused-function, \ DISABLED_WARNINGS_clang_splashscreen_png.c := \ diff --git a/src/java.desktop/share/legal/libpng.md b/src/java.desktop/share/legal/libpng.md index d43ccf2e8e4..8899491c6c0 100644 --- a/src/java.desktop/share/legal/libpng.md +++ b/src/java.desktop/share/legal/libpng.md @@ -1,4 +1,4 @@ -## libpng v1.6.47 +## libpng v1.6.51 ### libpng License
    @@ -9,7 +9,7 @@ COPYRIGHT NOTICE, DISCLAIMER, and LICENSE
     PNG Reference Library License version 2
     ---------------------------------------
     
    -Copyright (c) 1995-2025 The PNG Reference Library Authors.
    +Copyright (C) 1995-2025 The PNG Reference Library Authors.
     Copyright (C) 2018-2025 Cosmin Truta
     Copyright (C) 1998-2018 Glenn Randers-Pehrson
     Copyright (C) 1996-1997 Andreas Dilger
    @@ -173,6 +173,7 @@ Authors, for copyright and licensing purposes.
      * Lucas Chollet
      * Magnus Holmgren
      * Mandar Sahastrabuddhe
    + * Manfred Schlaegl
      * Mans Rullgard
      * Matt Sarett
      * Mike Klein
    @@ -184,6 +185,7 @@ Authors, for copyright and licensing purposes.
      * Samuel Williams
      * Simon-Pierre Cadieux
      * Tim Wegner
    + * Tobias Stoeckmann
      * Tom Lane
      * Tom Tanner
      * Vadim Barkov
    @@ -193,8 +195,9 @@ Authors, for copyright and licensing purposes.
         - Zixu Wang (王子旭)
      * Arm Holdings
         - Richard Townsend
    - * Google Inc.
    + * Google LLC
         - Dan Field
    +    - Dragoș Tiselice
         - Leon Scroggins III
         - Matt Sarett
         - Mike Klein
    @@ -204,6 +207,8 @@ Authors, for copyright and licensing purposes.
         - GuXiWei (顾希伟)
         - JinBo (金波)
         - ZhangLixia (张利霞)
    + * Samsung Group
    +    - Filip Wasil
     
     The build projects, the build scripts, the test scripts, and other
     files in the "projects", "scripts" and "tests" directories, have
    @@ -214,3 +219,4 @@ of the tools-generated files that are distributed with libpng, have
     other copyright owners, and are released under other open source
     licenses.
     ```
    +
    diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/CHANGES b/src/java.desktop/share/native/libsplashscreen/libpng/CHANGES
    index 834b5e19277..2478fd0fc08 100644
    --- a/src/java.desktop/share/native/libsplashscreen/libpng/CHANGES
    +++ b/src/java.desktop/share/native/libsplashscreen/libpng/CHANGES
    @@ -6251,6 +6251,59 @@ Version 1.6.47 [February 18, 2025]
         colorspace precedence rules, due to pre-existing colorspace checks.
         (Reported by Bob Friesenhahn; fixed by John Bowler)
     
    +Version 1.6.48 [April 30, 2025]
    +  Fixed the floating-point version of the mDCv setter `png_set_mDCv`.
    +    (Reported by Mohit Bakshi; fixed by John Bowler)
    +  Added #error directives to discourage the inclusion of private
    +    libpng implementation header files in PNG-supporting applications.
    +  Added the CMake build option `PNG_LIBCONF_HEADER`, to be used as an
    +    alternative to `DFA_XTRA`.
    +  Removed the Travis CI configuration files, with heartfelt thanks for
    +    their generous support of our project over the past five years!
    +
    +Version 1.6.49 [June 12, 2025]
    +  Added SIMD-optimized code for the RISC-V Vector Extension (RVV).
    +    (Contributed by Manfred Schlaegl, Dragos Tiselice and Filip Wasil)
    +  Added various fixes and improvements to the build scripts and to
    +    the sample code.
    +
    +Version 1.6.50 [July 1, 2025]
    +  Improved the detection of the RVV Extension on the RISC-V platform.
    +    (Contributed by Filip Wasil)
    +  Replaced inline ASM with C intrinsics in the RVV code.
    +    (Contributed by Filip Wasil)
    +  Fixed a decoder defect in which unknown chunks trailing IDAT, set
    +    to go through the unknown chunk handler, incorrectly triggered
    +    out-of-place IEND errors.
    +    (Contributed by John Bowler)
    +  Fixed the CMake file for cross-platform builds that require `libm`.
    +
    +Version 1.6.51 [November 21, 2025]
    +  Fixed CVE-2025-64505 (moderate severity):
    +    Heap buffer overflow in `png_do_quantize` via malformed palette index.
    +    (Reported by Samsung; analyzed by Fabio Gritti.)
    +  Fixed CVE-2025-64506 (moderate severity):
    +    Heap buffer over-read in `png_write_image_8bit` with 8-bit input and
    +    `convert_to_8bit` enabled.
    +    (Reported by Samsung and ;
    +    analyzed by Fabio Gritti.)
    +  Fixed CVE-2025-64720 (high severity):
    +    Buffer overflow in `png_image_read_composite` via incorrect palette
    +    premultiplication.
    +    (Reported by Samsung; analyzed by John Bowler.)
    +  Fixed CVE-2025-65018 (high severity):
    +    Heap buffer overflow in `png_combine_row` triggered via
    +    `png_image_finish_read`.
    +    (Reported by .)
    +  Fixed a memory leak in `png_set_quantize`.
    +    (Reported by Samsung; analyzed by Fabio Gritti.)
    +  Removed the experimental and incomplete ERROR_NUMBERS code.
    +    (Contributed by Tobias Stoeckmann.)
    +  Improved the RISC-V vector extension support; required RVV 1.0 or newer.
    +    (Contributed by Filip Wasil.)
    +  Added GitHub Actions workflows for automated testing.
    +  Performed various refactorings and cleanups.
    +
     Send comments/corrections/commendations to png-mng-implement at lists.sf.net.
     Subscription is required; visit
     https://lists.sourceforge.net/lists/listinfo/png-mng-implement
    diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/README b/src/java.desktop/share/native/libsplashscreen/libpng/README
    index 57952fb215a..5ea329ee3da 100644
    --- a/src/java.desktop/share/native/libsplashscreen/libpng/README
    +++ b/src/java.desktop/share/native/libsplashscreen/libpng/README
    @@ -1,4 +1,4 @@
    -README for libpng version 1.6.47
    +README for libpng version 1.6.51
     ================================
     
     See the note about version numbers near the top of `png.h`.
    @@ -147,6 +147,7 @@ Files included in this distribution
         loongarch/    =>  Optimized code for LoongArch LSX
         mips/         =>  Optimized code for MIPS MSA and MIPS MMI
         powerpc/      =>  Optimized code for PowerPC VSX
    +    riscv/        =>  Optimized code for the RISC-V platform
         ci/           =>  Scripts for continuous integration
         contrib/      =>  External contributions
             arm-neon/     =>  Optimized code for the ARM-NEON platform
    @@ -162,6 +163,7 @@ Files included in this distribution
                               programs demonstrating the use of pngusr.dfa
             pngminus/     =>  Simple pnm2png and png2pnm programs
             pngsuite/     =>  Test images
    +        riscv-rvv/    =>  Optimized code for the RISC-V Vector platform
             testpngs/     =>  Test images
             tools/        =>  Various tools
             visupng/      =>  VisualPng, a Windows viewer for PNG images
    diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/png.c b/src/java.desktop/share/native/libsplashscreen/libpng/png.c
    index 7b6de2f8ec3..7d85e7c8d5f 100644
    --- a/src/java.desktop/share/native/libsplashscreen/libpng/png.c
    +++ b/src/java.desktop/share/native/libsplashscreen/libpng/png.c
    @@ -42,7 +42,7 @@
     #include "pngpriv.h"
     
     /* Generate a compiler error if there is an old png.h in the search path. */
    -typedef png_libpng_version_1_6_47 Your_png_h_is_not_version_1_6_47;
    +typedef png_libpng_version_1_6_51 Your_png_h_is_not_version_1_6_51;
     
     /* Sanity check the chunks definitions - PNG_KNOWN_CHUNKS from pngpriv.h and the
      * corresponding macro definitions.  This causes a compile time failure if
    @@ -137,10 +137,16 @@ png_zalloc,(voidpf png_ptr, uInt items, uInt size),PNG_ALLOCATED)
        if (png_ptr == NULL)
           return NULL;
     
    -   if (items >= (~(png_alloc_size_t)0)/size)
    +   /* This check against overflow is vestigial, dating back from
    +    * the old times when png_zalloc used to be an exported function.
    +    * We're still keeping it here for now, as an extra-cautious
    +    * prevention against programming errors inside zlib, although it
    +    * should rather be a debug-time assertion instead.
    +    */
    +   if (size != 0 && items >= (~(png_alloc_size_t)0) / size)
        {
    -      png_warning (png_voidcast(png_structrp, png_ptr),
    -          "Potential overflow in png_zalloc()");
    +      png_warning(png_voidcast(png_structrp, png_ptr),
    +                  "Potential overflow in png_zalloc()");
           return NULL;
        }
     
    @@ -267,10 +273,6 @@ png_user_version_check(png_structrp png_ptr, png_const_charp user_png_ver)
           png_warning(png_ptr, m);
     #endif
     
    -#ifdef PNG_ERROR_NUMBERS_SUPPORTED
    -      png_ptr->flags = 0;
    -#endif
    -
           return 0;
        }
     
    @@ -729,7 +731,7 @@ png_get_io_ptr(png_const_structrp png_ptr)
      * function of your own because "FILE *" isn't necessarily available.
      */
     void PNGAPI
    -png_init_io(png_structrp png_ptr, png_FILE_p fp)
    +png_init_io(png_structrp png_ptr, FILE *fp)
     {
        png_debug(1, "in png_init_io");
     
    @@ -844,7 +846,7 @@ png_get_copyright(png_const_structrp png_ptr)
        return PNG_STRING_COPYRIGHT
     #else
        return PNG_STRING_NEWLINE \
    -      "libpng version 1.6.47" PNG_STRING_NEWLINE \
    +      "libpng version 1.6.51" PNG_STRING_NEWLINE \
           "Copyright (c) 2018-2025 Cosmin Truta" PNG_STRING_NEWLINE \
           "Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson" \
           PNG_STRING_NEWLINE \
    @@ -1520,7 +1522,7 @@ png_XYZ_from_xy(png_XYZ *XYZ, const png_xy *xy)
     }
     #endif /* COLORSPACE */
     
    -#ifdef PNG_iCCP_SUPPORTED
    +#ifdef PNG_READ_iCCP_SUPPORTED
     /* Error message generation */
     static char
     png_icc_tag_char(png_uint_32 byte)
    @@ -1596,9 +1598,7 @@ png_icc_profile_error(png_const_structrp png_ptr, png_const_charp name,
     
        return 0;
     }
    -#endif /* iCCP */
     
    -#ifdef PNG_READ_iCCP_SUPPORTED
     /* Encoded value of D50 as an ICC XYZNumber.  From the ICC 2010 spec the value
      * is XYZ(0.9642,1.0,0.8249), which scales to:
      *
    @@ -3998,7 +3998,7 @@ png_image_free_function(png_voidp argument)
     #  ifdef PNG_STDIO_SUPPORTED
           if (cp->owned_file != 0)
           {
    -         FILE *fp = png_voidcast(FILE*, cp->png_ptr->io_ptr);
    +         FILE *fp = png_voidcast(FILE *, cp->png_ptr->io_ptr);
              cp->owned_file = 0;
     
              /* Ignore errors here. */
    diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/png.h b/src/java.desktop/share/native/libsplashscreen/libpng/png.h
    index ede12c34fe6..d39ff73552c 100644
    --- a/src/java.desktop/share/native/libsplashscreen/libpng/png.h
    +++ b/src/java.desktop/share/native/libsplashscreen/libpng/png.h
    @@ -29,7 +29,7 @@
      * However, the following notice accompanied the original version of this
      * file and, per its terms, should not be removed:
      *
    - * libpng version 1.6.47
    + * libpng version 1.6.51
      *
      * Copyright (c) 2018-2025 Cosmin Truta
      * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
    @@ -43,7 +43,7 @@
      *   libpng versions 0.89, June 1996, through 0.96, May 1997: Andreas Dilger
      *   libpng versions 0.97, January 1998, through 1.6.35, July 2018:
      *     Glenn Randers-Pehrson
    - *   libpng versions 1.6.36, December 2018, through 1.6.47, February 2025:
    + *   libpng versions 1.6.36, December 2018, through 1.6.51, November 2025:
      *     Cosmin Truta
      *   See also "Contributing Authors", below.
      */
    @@ -267,7 +267,7 @@
      *    ...
      *    1.5.30                  15    10530  15.so.15.30[.0]
      *    ...
    - *    1.6.47                  16    10647  16.so.16.47[.0]
    + *    1.6.51                  16    10651  16.so.16.51[.0]
      *
      *    Henceforth the source version will match the shared-library major and
      *    minor numbers; the shared-library major version number will be used for
    @@ -303,7 +303,7 @@
      */
     
     /* Version information for png.h - this should match the version in png.c */
    -#define PNG_LIBPNG_VER_STRING "1.6.47"
    +#define PNG_LIBPNG_VER_STRING "1.6.51"
     #define PNG_HEADER_VERSION_STRING " libpng version " PNG_LIBPNG_VER_STRING "\n"
     
     /* The versions of shared library builds should stay in sync, going forward */
    @@ -314,7 +314,7 @@
     /* These should match the first 3 components of PNG_LIBPNG_VER_STRING: */
     #define PNG_LIBPNG_VER_MAJOR   1
     #define PNG_LIBPNG_VER_MINOR   6
    -#define PNG_LIBPNG_VER_RELEASE 47
    +#define PNG_LIBPNG_VER_RELEASE 51
     
     /* This should be zero for a public release, or non-zero for a
      * development version.
    @@ -345,7 +345,7 @@
      * From version 1.0.1 it is:
      * XXYYZZ, where XX=major, YY=minor, ZZ=release
      */
    -#define PNG_LIBPNG_VER 10647 /* 1.6.47 */
    +#define PNG_LIBPNG_VER 10651 /* 1.6.51 */
     
     /* Library configuration: these options cannot be changed after
      * the library has been built.
    @@ -455,7 +455,7 @@ extern "C" {
     /* This triggers a compiler error in png.c, if png.c and png.h
      * do not agree upon the version number.
      */
    -typedef char* png_libpng_version_1_6_47;
    +typedef char* png_libpng_version_1_6_51;
     
     /* Basic control structions.  Read libpng-manual.txt or libpng.3 for more info.
      *
    @@ -1599,7 +1599,7 @@ PNG_EXPORT(226, void, png_set_text_compression_method, (png_structrp png_ptr,
     
     #ifdef PNG_STDIO_SUPPORTED
     /* Initialize the input/output for the PNG file to the default functions. */
    -PNG_EXPORT(74, void, png_init_io, (png_structrp png_ptr, png_FILE_p fp));
    +PNG_EXPORT(74, void, png_init_io, (png_structrp png_ptr, FILE *fp));
     #endif
     
     /* Replace the (error and abort), and warning functions with user
    @@ -3117,7 +3117,7 @@ PNG_EXPORT(234, int, png_image_begin_read_from_file, (png_imagep image,
         */
     
     PNG_EXPORT(235, int, png_image_begin_read_from_stdio, (png_imagep image,
    -   FILE* file));
    +   FILE *file));
        /* The PNG header is read from the stdio FILE object. */
     #endif /* STDIO */
     
    @@ -3192,7 +3192,7 @@ PNG_EXPORT(239, int, png_image_write_to_file, (png_imagep image,
     PNG_EXPORT(240, int, png_image_write_to_stdio, (png_imagep image, FILE *file,
        int convert_to_8_bit, const void *buffer, png_int_32 row_stride,
        const void *colormap));
    -   /* Write the image to the given (FILE*). */
    +   /* Write the image to the given FILE object. */
     #endif /* SIMPLIFIED_WRITE_STDIO */
     
     /* With all write APIs if image is in one of the linear formats with 16-bit
    @@ -3332,26 +3332,45 @@ PNG_EXPORT(245, int, png_image_write_to_memory, (png_imagep image, void *memory,
      *           selected at run time.
      */
     #ifdef PNG_SET_OPTION_SUPPORTED
    +
    +/* HARDWARE: ARM Neon SIMD instructions supported */
     #ifdef PNG_ARM_NEON_API_SUPPORTED
    -#  define PNG_ARM_NEON   0 /* HARDWARE: ARM Neon SIMD instructions supported */
    -#endif
    -#define PNG_MAXIMUM_INFLATE_WINDOW 2 /* SOFTWARE: force maximum window */
    -#define PNG_SKIP_sRGB_CHECK_PROFILE 4 /* SOFTWARE: Check ICC profile for sRGB */
    -#ifdef PNG_MIPS_MSA_API_SUPPORTED
    -#  define PNG_MIPS_MSA   6 /* HARDWARE: MIPS Msa SIMD instructions supported */
    -#endif
    -#ifdef PNG_DISABLE_ADLER32_CHECK_SUPPORTED
    -#  define PNG_IGNORE_ADLER32 8 /* SOFTWARE: disable Adler32 check on IDAT */
    -#endif
    -#ifdef PNG_POWERPC_VSX_API_SUPPORTED
    -#  define PNG_POWERPC_VSX   10 /* HARDWARE: PowerPC VSX SIMD instructions
    -                                * supported */
    -#endif
    -#ifdef PNG_MIPS_MMI_API_SUPPORTED
    -#  define PNG_MIPS_MMI   12 /* HARDWARE: MIPS MMI SIMD instructions supported */
    +#  define PNG_ARM_NEON 0
     #endif
     
    -#define PNG_OPTION_NEXT  14 /* Next option - numbers must be even */
    +/* SOFTWARE: Force maximum window */
    +#define PNG_MAXIMUM_INFLATE_WINDOW 2
    +
    +/* SOFTWARE: Check ICC profile for sRGB */
    +#define PNG_SKIP_sRGB_CHECK_PROFILE 4
    +
    +/* HARDWARE: MIPS MSA SIMD instructions supported */
    +#ifdef PNG_MIPS_MSA_API_SUPPORTED
    +#  define PNG_MIPS_MSA 6
    +#endif
    +
    +/* SOFTWARE: Disable Adler32 check on IDAT */
    +#ifdef PNG_DISABLE_ADLER32_CHECK_SUPPORTED
    +#  define PNG_IGNORE_ADLER32 8
    +#endif
    +
    +/* HARDWARE: PowerPC VSX SIMD instructions supported */
    +#ifdef PNG_POWERPC_VSX_API_SUPPORTED
    +#  define PNG_POWERPC_VSX 10
    +#endif
    +
    +/* HARDWARE: MIPS MMI SIMD instructions supported */
    +#ifdef PNG_MIPS_MMI_API_SUPPORTED
    +#  define PNG_MIPS_MMI 12
    +#endif
    +
    +/* HARDWARE: RISC-V RVV SIMD instructions supported */
    +#ifdef PNG_RISCV_RVV_API_SUPPORTED
    +#  define PNG_RISCV_RVV 14
    +#endif
    +
    +/* Next option - numbers must be even */
    +#define PNG_OPTION_NEXT 16
     
     /* Return values: NOTE: there are four values and 'off' is *not* zero */
     #define PNG_OPTION_UNSET   0 /* Unset - defaults to off */
    diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngconf.h b/src/java.desktop/share/native/libsplashscreen/libpng/pngconf.h
    index 70bca6fa1c9..4bc5f7bb468 100644
    --- a/src/java.desktop/share/native/libsplashscreen/libpng/pngconf.h
    +++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngconf.h
    @@ -29,7 +29,7 @@
      * However, the following notice accompanied the original version of this
      * file and, per its terms, should not be removed:
      *
    - * libpng version 1.6.47
    + * libpng version 1.6.51
      *
      * Copyright (c) 2018-2025 Cosmin Truta
      * Copyright (c) 1998-2002,2004,2006-2016,2018 Glenn Randers-Pehrson
    @@ -248,25 +248,13 @@
       /* NOTE: PNGCBAPI always defaults to PNGCAPI. */
     
     #  if defined(PNGAPI) && !defined(PNG_USER_PRIVATEBUILD)
    -#     error "PNG_USER_PRIVATEBUILD must be defined if PNGAPI is changed"
    +#     error PNG_USER_PRIVATEBUILD must be defined if PNGAPI is changed
     #  endif
     
    -#  if (defined(_MSC_VER) && _MSC_VER < 800) ||\
    -      (defined(__BORLANDC__) && __BORLANDC__ < 0x500)
    -   /* older Borland and MSC
    -    * compilers used '__export' and required this to be after
    -    * the type.
    -    */
    -#    ifndef PNG_EXPORT_TYPE
    -#      define PNG_EXPORT_TYPE(type) type PNG_IMPEXP
    -#    endif
    -#    define PNG_DLL_EXPORT __export
    -#  else /* newer compiler */
    -#    define PNG_DLL_EXPORT __declspec(dllexport)
    -#    ifndef PNG_DLL_IMPORT
    -#      define PNG_DLL_IMPORT __declspec(dllimport)
    -#    endif
    -#  endif /* compiler */
    +#  define PNG_DLL_EXPORT __declspec(dllexport)
    +#  ifndef PNG_DLL_IMPORT
    +#    define PNG_DLL_IMPORT __declspec(dllimport)
    +#  endif
     
     #else /* !Windows */
     #  if (defined(__IBMC__) || defined(__IBMCPP__)) && defined(__OS2__)
    @@ -508,7 +496,7 @@
     #if CHAR_BIT == 8 && UCHAR_MAX == 255
        typedef unsigned char png_byte;
     #else
    -#  error "libpng requires 8-bit bytes"
    +#  error libpng requires 8-bit bytes
     #endif
     
     #if INT_MIN == -32768 && INT_MAX == 32767
    @@ -516,7 +504,7 @@
     #elif SHRT_MIN == -32768 && SHRT_MAX == 32767
        typedef short png_int_16;
     #else
    -#  error "libpng requires a signed 16-bit type"
    +#  error libpng requires a signed 16-bit integer type
     #endif
     
     #if UINT_MAX == 65535
    @@ -524,7 +512,7 @@
     #elif USHRT_MAX == 65535
        typedef unsigned short png_uint_16;
     #else
    -#  error "libpng requires an unsigned 16-bit type"
    +#  error libpng requires an unsigned 16-bit integer type
     #endif
     
     #if INT_MIN < -2147483646 && INT_MAX > 2147483646
    @@ -532,7 +520,7 @@
     #elif LONG_MIN < -2147483646 && LONG_MAX > 2147483646
        typedef long int png_int_32;
     #else
    -#  error "libpng requires a signed 32-bit (or more) type"
    +#  error libpng requires a signed 32-bit (or longer) integer type
     #endif
     
     #if UINT_MAX > 4294967294U
    @@ -540,7 +528,7 @@
     #elif ULONG_MAX > 4294967294U
        typedef unsigned long int png_uint_32;
     #else
    -#  error "libpng requires an unsigned 32-bit (or more) type"
    +#  error libpng requires an unsigned 32-bit (or longer) integer type
     #endif
     
     /* Prior to 1.6.0, it was possible to disable the use of size_t and ptrdiff_t.
    @@ -621,10 +609,6 @@ typedef const png_fixed_point * png_const_fixed_point_p;
     typedef size_t                * png_size_tp;
     typedef const size_t          * png_const_size_tp;
     
    -#ifdef PNG_STDIO_SUPPORTED
    -typedef FILE            * png_FILE_p;
    -#endif
    -
     #ifdef PNG_FLOATING_POINT_SUPPORTED
     typedef double       * png_doublep;
     typedef const double * png_const_doublep;
    @@ -646,6 +630,15 @@ typedef double          * * png_doublepp;
     /* Pointers to pointers to pointers; i.e., pointer to array */
     typedef char            * * * png_charppp;
     
    +#ifdef PNG_STDIO_SUPPORTED
    +/* With PNG_STDIO_SUPPORTED it was possible to use I/O streams that were
    + * not necessarily stdio FILE streams, to allow building Windows applications
    + * before Win32 and Windows CE applications before WinCE 3.0, but that kind
    + * of support has long been discontinued.
    + */
    +typedef FILE            * png_FILE_p; /* [Deprecated] */
    +#endif
    +
     #endif /* PNG_BUILDING_SYMBOL_TABLE */
     
     #endif /* PNGCONF_H */
    diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngdebug.h b/src/java.desktop/share/native/libsplashscreen/libpng/pngdebug.h
    index 8eb5400ea9a..6ea2644dfcd 100644
    --- a/src/java.desktop/share/native/libsplashscreen/libpng/pngdebug.h
    +++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngdebug.h
    @@ -22,14 +22,14 @@
      * questions.
      */
     
    -/* pngdebug.h - Debugging macros for libpng, also used in pngtest.c
    +/* pngdebug.h - internal debugging macros for libpng
      *
      * This file is available under and governed by the GNU General Public
      * License version 2 only, as published by the Free Software Foundation.
      * However, the following notice accompanied the original version of this
      * file and, per its terms, should not be removed:
      *
    - * Copyright (c) 2018 Cosmin Truta
    + * Copyright (c) 2018-2025 Cosmin Truta
      * Copyright (c) 1998-2002,2004,2006-2013 Glenn Randers-Pehrson
      * Copyright (c) 1996-1997 Andreas Dilger
      * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
    @@ -39,6 +39,10 @@
      * and license in png.h
      */
     
    +#ifndef PNGPRIV_H
    +#  error This file must not be included by applications; please include 
    +#endif
    +
     /* Define PNG_DEBUG at compile time for debugging information.  Higher
      * numbers for PNG_DEBUG mean more debugging information.  This has
      * only been added since version 0.95 so it is not implemented throughout
    @@ -63,9 +67,6 @@
     #define PNGDEBUG_H
     /* These settings control the formatting of messages in png.c and pngerror.c */
     /* Moved to pngdebug.h at 1.5.0 */
    -#  ifndef PNG_LITERAL_SHARP
    -#    define PNG_LITERAL_SHARP 0x23
    -#  endif
     #  ifndef PNG_LITERAL_LEFT_SQUARE_BRACKET
     #    define PNG_LITERAL_LEFT_SQUARE_BRACKET 0x5b
     #  endif
    diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngerror.c b/src/java.desktop/share/native/libsplashscreen/libpng/pngerror.c
    index ea0103331d3..44c86ebfef9 100644
    --- a/src/java.desktop/share/native/libsplashscreen/libpng/pngerror.c
    +++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngerror.c
    @@ -29,7 +29,7 @@
      * However, the following notice accompanied the original version of this
      * file and, per its terms, should not be removed:
      *
    - * Copyright (c) 2018-2024 Cosmin Truta
    + * Copyright (c) 2018-2025 Cosmin Truta
      * Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson
      * Copyright (c) 1996-1997 Andreas Dilger
      * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
    @@ -68,46 +68,6 @@ PNG_FUNCTION(void,PNGAPI
     png_error,(png_const_structrp png_ptr, png_const_charp error_message),
         PNG_NORETURN)
     {
    -#ifdef PNG_ERROR_NUMBERS_SUPPORTED
    -   char msg[16];
    -   if (png_ptr != NULL)
    -   {
    -      if ((png_ptr->flags &
    -         (PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT)) != 0)
    -      {
    -         if (*error_message == PNG_LITERAL_SHARP)
    -         {
    -            /* Strip "#nnnn " from beginning of error message. */
    -            int offset;
    -            for (offset = 1; offset<15; offset++)
    -               if (error_message[offset] == ' ')
    -                  break;
    -
    -            if ((png_ptr->flags & PNG_FLAG_STRIP_ERROR_TEXT) != 0)
    -            {
    -               int i;
    -               for (i = 0; i < offset - 1; i++)
    -                  msg[i] = error_message[i + 1];
    -               msg[i - 1] = '\0';
    -               error_message = msg;
    -            }
    -
    -            else
    -               error_message += offset;
    -         }
    -
    -         else
    -         {
    -            if ((png_ptr->flags & PNG_FLAG_STRIP_ERROR_TEXT) != 0)
    -            {
    -               msg[0] = '0';
    -               msg[1] = '\0';
    -               error_message = msg;
    -            }
    -         }
    -      }
    -   }
    -#endif
        if (png_ptr != NULL && png_ptr->error_fn != NULL)
           (*(png_ptr->error_fn))(png_constcast(png_structrp,png_ptr),
               error_message);
    @@ -245,21 +205,6 @@ void PNGAPI
     png_warning(png_const_structrp png_ptr, png_const_charp warning_message)
     {
        int offset = 0;
    -   if (png_ptr != NULL)
    -   {
    -#ifdef PNG_ERROR_NUMBERS_SUPPORTED
    -   if ((png_ptr->flags &
    -       (PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT)) != 0)
    -#endif
    -      {
    -         if (*warning_message == PNG_LITERAL_SHARP)
    -         {
    -            for (offset = 1; offset < 15; offset++)
    -               if (warning_message[offset] == ' ')
    -                  break;
    -         }
    -      }
    -   }
        if (png_ptr != NULL && png_ptr->warning_fn != NULL)
           (*(png_ptr->warning_fn))(png_constcast(png_structrp,png_ptr),
               warning_message + offset);
    @@ -741,42 +686,9 @@ png_default_error,(png_const_structrp png_ptr, png_const_charp error_message),
         PNG_NORETURN)
     {
     #ifdef PNG_CONSOLE_IO_SUPPORTED
    -#ifdef PNG_ERROR_NUMBERS_SUPPORTED
    -   /* Check on NULL only added in 1.5.4 */
    -   if (error_message != NULL && *error_message == PNG_LITERAL_SHARP)
    -   {
    -      /* Strip "#nnnn " from beginning of error message. */
    -      int offset;
    -      char error_number[16];
    -      for (offset = 0; offset<15; offset++)
    -      {
    -         error_number[offset] = error_message[offset + 1];
    -         if (error_message[offset] == ' ')
    -            break;
    -      }
    -
    -      if ((offset > 1) && (offset < 15))
    -      {
    -         error_number[offset - 1] = '\0';
    -         fprintf(stderr, "libpng error no. %s: %s",
    -             error_number, error_message + offset + 1);
    -         fprintf(stderr, PNG_STRING_NEWLINE);
    -      }
    -
    -      else
    -      {
    -         fprintf(stderr, "libpng error: %s, offset=%d",
    -             error_message, offset);
    -         fprintf(stderr, PNG_STRING_NEWLINE);
    -      }
    -   }
    -   else
    -#endif
    -   {
    -      fprintf(stderr, "libpng error: %s", error_message ? error_message :
    -         "undefined");
    -      fprintf(stderr, PNG_STRING_NEWLINE);
    -   }
    +   fprintf(stderr, "libpng error: %s", error_message ? error_message :
    +      "undefined");
    +   fprintf(stderr, PNG_STRING_NEWLINE);
     #else
        PNG_UNUSED(error_message) /* Make compiler happy */
     #endif
    @@ -814,40 +726,8 @@ static void /* PRIVATE */
     png_default_warning(png_const_structrp png_ptr, png_const_charp warning_message)
     {
     #ifdef PNG_CONSOLE_IO_SUPPORTED
    -#  ifdef PNG_ERROR_NUMBERS_SUPPORTED
    -   if (*warning_message == PNG_LITERAL_SHARP)
    -   {
    -      int offset;
    -      char warning_number[16];
    -      for (offset = 0; offset < 15; offset++)
    -      {
    -         warning_number[offset] = warning_message[offset + 1];
    -         if (warning_message[offset] == ' ')
    -            break;
    -      }
    -
    -      if ((offset > 1) && (offset < 15))
    -      {
    -         warning_number[offset + 1] = '\0';
    -         fprintf(stderr, "libpng warning no. %s: %s",
    -             warning_number, warning_message + offset);
    -         fprintf(stderr, PNG_STRING_NEWLINE);
    -      }
    -
    -      else
    -      {
    -         fprintf(stderr, "libpng warning: %s",
    -             warning_message);
    -         fprintf(stderr, PNG_STRING_NEWLINE);
    -      }
    -   }
    -   else
    -#  endif
    -
    -   {
    -      fprintf(stderr, "libpng warning: %s", warning_message);
    -      fprintf(stderr, PNG_STRING_NEWLINE);
    -   }
    +   fprintf(stderr, "libpng warning: %s", warning_message);
    +   fprintf(stderr, PNG_STRING_NEWLINE);
     #else
        PNG_UNUSED(warning_message) /* Make compiler happy */
     #endif
    @@ -895,12 +775,8 @@ png_get_error_ptr(png_const_structrp png_ptr)
     void PNGAPI
     png_set_strip_error_numbers(png_structrp png_ptr, png_uint_32 strip_mode)
     {
    -   if (png_ptr != NULL)
    -   {
    -      png_ptr->flags &=
    -         ((~(PNG_FLAG_STRIP_ERROR_NUMBERS |
    -         PNG_FLAG_STRIP_ERROR_TEXT))&strip_mode);
    -   }
    +   PNG_UNUSED(png_ptr)
    +   PNG_UNUSED(strip_mode)
     }
     #endif
     
    diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngget.c b/src/java.desktop/share/native/libsplashscreen/libpng/pngget.c
    index d67adbae247..ed2e7f886f5 100644
    --- a/src/java.desktop/share/native/libsplashscreen/libpng/pngget.c
    +++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngget.c
    @@ -29,7 +29,7 @@
      * However, the following notice accompanied the original version of this
      * file and, per its terms, should not be removed:
      *
    - * Copyright (c) 2018-2024 Cosmin Truta
    + * Copyright (c) 2018-2025 Cosmin Truta
      * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
      * Copyright (c) 1996-1997 Andreas Dilger
      * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
    diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pnginfo.h b/src/java.desktop/share/native/libsplashscreen/libpng/pnginfo.h
    index bc6ed3d09c9..c79c6cc780f 100644
    --- a/src/java.desktop/share/native/libsplashscreen/libpng/pnginfo.h
    +++ b/src/java.desktop/share/native/libsplashscreen/libpng/pnginfo.h
    @@ -22,14 +22,14 @@
      * questions.
      */
     
    -/* pnginfo.h - header file for PNG reference library
    +/* pnginfo.h - internal structures for libpng
      *
      * This file is available under and governed by the GNU General Public
      * License version 2 only, as published by the Free Software Foundation.
      * However, the following notice accompanied the original version of this
      * file and, per its terms, should not be removed:
      *
    - * Copyright (c) 2018 Cosmin Truta
    + * Copyright (c) 2018-2025 Cosmin Truta
      * Copyright (c) 1998-2002,2004,2006-2013,2018 Glenn Randers-Pehrson
      * Copyright (c) 1996-1997 Andreas Dilger
      * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
    @@ -39,43 +39,20 @@
      * and license in png.h
      */
     
    - /* png_info is a structure that holds the information in a PNG file so
    - * that the application can find out the characteristics of the image.
    - * If you are reading the file, this structure will tell you what is
    - * in the PNG file.  If you are writing the file, fill in the information
    - * you want to put into the PNG file, using png_set_*() functions, then
    - * call png_write_info().
    +#ifndef PNGPRIV_H
    +#  error This file must not be included by applications; please include 
    +#endif
    +
    +/* INTERNAL, PRIVATE definition of a PNG.
      *
    - * The names chosen should be very close to the PNG specification, so
    - * consult that document for information about the meaning of each field.
    + * png_info is a modifiable description of a PNG datastream.  The fields inside
    + * this structure are accessed through png_get_() functions and modified
    + * using png_set_() functions.
      *
    - * With libpng < 0.95, it was only possible to directly set and read the
    - * the values in the png_info_struct, which meant that the contents and
    - * order of the values had to remain fixed.  With libpng 0.95 and later,
    - * however, there are now functions that abstract the contents of
    - * png_info_struct from the application, so this makes it easier to use
    - * libpng with dynamic libraries, and even makes it possible to use
    - * libraries that don't have all of the libpng ancillary chunk-handing
    - * functionality.  In libpng-1.5.0 this was moved into a separate private
    - * file that is not visible to applications.
    - *
    - * The following members may have allocated storage attached that should be
    - * cleaned up before the structure is discarded: palette, trans, text,
    - * pcal_purpose, pcal_units, pcal_params, hist, iccp_name, iccp_profile,
    - * splt_palettes, scal_unit, row_pointers, and unknowns.   By default, these
    - * are automatically freed when the info structure is deallocated, if they were
    - * allocated internally by libpng.  This behavior can be changed by means
    - * of the png_data_freer() function.
    - *
    - * More allocation details: all the chunk-reading functions that
    - * change these members go through the corresponding png_set_*
    - * functions.  A function to clear these members is available: see
    - * png_free_data().  The png_set_* functions do not depend on being
    - * able to point info structure members to any of the storage they are
    - * passed (they make their own copies), EXCEPT that the png_set_text
    - * functions use the same storage passed to them in the text_ptr or
    - * itxt_ptr structure argument, and the png_set_rows and png_set_unknowns
    - * functions do not make their own copies.
    + * Some functions in libpng do directly access members of png_info.  However,
    + * this should be avoided.  png_struct objects contain members which hold
    + * caches, sometimes optimised, of the values from png_info objects, and
    + * png_info is not passed to the functions which read and write image data.
      */
     #ifndef PNGINFO_H
     #define PNGINFO_H
    diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pnglibconf.h b/src/java.desktop/share/native/libsplashscreen/libpng/pnglibconf.h
    index 906f855db0e..4cfae474751 100644
    --- a/src/java.desktop/share/native/libsplashscreen/libpng/pnglibconf.h
    +++ b/src/java.desktop/share/native/libsplashscreen/libpng/pnglibconf.h
    @@ -31,7 +31,7 @@
      * However, the following notice accompanied the original version of this
      * file and, per its terms, should not be removed:
      */
    -/* libpng version 1.6.47 */
    +/* libpng version 1.6.51 */
     
     /* Copyright (c) 2018-2025 Cosmin Truta */
     /* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson */
    diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngmem.c b/src/java.desktop/share/native/libsplashscreen/libpng/pngmem.c
    index ba9eb4df402..12b71bcbc02 100644
    --- a/src/java.desktop/share/native/libsplashscreen/libpng/pngmem.c
    +++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngmem.c
    @@ -29,7 +29,7 @@
      * However, the following notice accompanied the original version of this
      * file and, per its terms, should not be removed:
      *
    - * Copyright (c) 2018 Cosmin Truta
    + * Copyright (c) 2018-2025 Cosmin Truta
      * Copyright (c) 1998-2002,2004,2006-2014,2016 Glenn Randers-Pehrson
      * Copyright (c) 1996-1997 Andreas Dilger
      * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
    diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngpread.c b/src/java.desktop/share/native/libsplashscreen/libpng/pngpread.c
    index 86d0c7aaa64..3bfa913000f 100644
    --- a/src/java.desktop/share/native/libsplashscreen/libpng/pngpread.c
    +++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngpread.c
    @@ -29,7 +29,7 @@
      * However, the following notice accompanied the original version of this
      * file and, per its terms, should not be removed:
      *
    - * Copyright (c) 2018-2024 Cosmin Truta
    + * Copyright (c) 2018-2025 Cosmin Truta
      * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
      * Copyright (c) 1996-1997 Andreas Dilger
      * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
    @@ -258,6 +258,14 @@ png_push_read_chunk(png_structrp png_ptr, png_inforp info_ptr)
              png_benign_error(png_ptr, "Too many IDATs found");
        }
     
    +   else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0)
    +   {
    +      /* These flags must be set consistently for all non-IDAT chunks,
    +       * including the unknown chunks.
    +       */
    +      png_ptr->mode |= PNG_HAVE_CHUNK_AFTER_IDAT | PNG_AFTER_IDAT;
    +   }
    +
        if (chunk_name == png_IHDR)
        {
           if (png_ptr->push_length != 13)
    diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngpriv.h b/src/java.desktop/share/native/libsplashscreen/libpng/pngpriv.h
    index 25bac4b9e69..dcd005efb34 100644
    --- a/src/java.desktop/share/native/libsplashscreen/libpng/pngpriv.h
    +++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngpriv.h
    @@ -29,7 +29,7 @@
      * However, the following notice accompanied the original version of this
      * file and, per its terms, should not be removed:
      *
    - * Copyright (c) 2018-2024 Cosmin Truta
    + * Copyright (c) 2018-2025 Cosmin Truta
      * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
      * Copyright (c) 1996-1997 Andreas Dilger
      * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
    @@ -48,8 +48,20 @@
      * they should be well aware of the issues that may arise from doing so.
      */
     
    +
    +/* pngpriv.h must be included first in each translation unit inside libpng.
    + * On the other hand, it must not be included at all, directly or indirectly,
    + * by any application code that uses the libpng API.
    + */
     #ifndef PNGPRIV_H
    -#define PNGPRIV_H
    +#  define PNGPRIV_H
    +#else
    +#  error Duplicate inclusion of pngpriv.h; please check the libpng source files
    +#endif
    +
    +#if defined(PNG_H) || defined(PNGCONF_H) || defined(PNGLCONF_H)
    +#  error This file must not be included by applications; please include 
    +#endif
     
     /* Feature Test Macros.  The following are defined here to ensure that correctly
      * implemented libraries reveal the APIs libpng needs to build and hide those
    @@ -86,7 +98,6 @@
      */
     #if defined(HAVE_CONFIG_H) && !defined(PNG_NO_CONFIG_H)
     #  include 
    -
        /* Pick up the definition of 'restrict' from config.h if it was read: */
     #  define PNG_RESTRICT restrict
     #endif
    @@ -96,9 +107,7 @@
      * are not internal definitions may be required.  This is handled below just
      * before png.h is included, but load the configuration now if it is available.
      */
    -#ifndef PNGLCONF_H
    -#  include "pnglibconf.h"
    -#endif
    +#include "pnglibconf.h"
     
     /* Local renames may change non-exported API functions from png.h */
     #if defined(PNG_PREFIX) && !defined(PNGPREFIX_H)
    @@ -163,6 +172,20 @@
     #  endif
     #endif
     
    +#ifndef PNG_RISCV_RVV_OPT
    +   /* RISCV_RVV optimizations are being controlled by the compiler settings,
    +    * typically the target compiler will define __riscv but the rvv extension
    +    * availability has to be explicitly stated. This is why if no
    +    * PNG_RISCV_RVV_OPT was defined then a runtime check will be executed.
    +    *
    +    * To enable RISCV_RVV optimizations unconditionally, and compile the
    +    * associated code, pass --enable-riscv-rvv=yes or --enable-riscv-rvv=on
    +    * to configure or put -DPNG_RISCV_RVV_OPT=2 in CPPFLAGS.
    +    */
    +
    +#  define PNG_RISCV_RVV_OPT 0
    +#endif
    +
     #if PNG_ARM_NEON_OPT > 0
        /* NEON optimizations are to be at least considered by libpng, so enable the
         * callbacks to do this.
    @@ -308,6 +331,16 @@
     #   define PNG_LOONGARCH_LSX_IMPLEMENTATION 0
     #endif
     
    +#if PNG_RISCV_RVV_OPT > 0 && __riscv_v >= 1000000
    +#  define PNG_FILTER_OPTIMIZATIONS png_init_filter_functions_rvv
    +#  ifndef PNG_RISCV_RVV_IMPLEMENTATION
    +      /* Use the intrinsics code by default. */
    +#     define PNG_RISCV_RVV_IMPLEMENTATION 1
    +#  endif
    +#else
    +#  define PNG_RISCV_RVV_IMPLEMENTATION 0
    +#endif /* PNG_RISCV_RVV_OPT > 0 && __riscv_v >= 1000000 */
    +
     /* Is this a build of a DLL where compilation of the object modules requires
      * different preprocessor settings to those required for a simple library?  If
      * so PNG_BUILD_DLL must be set.
    @@ -706,7 +739,7 @@
     /* #define PNG_FLAG_KEEP_UNKNOWN_CHUNKS      0x8000U */
     /* #define PNG_FLAG_KEEP_UNSAFE_CHUNKS      0x10000U */
     #define PNG_FLAG_LIBRARY_MISMATCH        0x20000U
    -#define PNG_FLAG_STRIP_ERROR_NUMBERS     0x40000U
    +                                  /*     0x40000U    unused */
     #define PNG_FLAG_STRIP_ERROR_TEXT        0x80000U
     #define PNG_FLAG_BENIGN_ERRORS_WARN     0x100000U /* Added to libpng-1.4.0 */
     #define PNG_FLAG_APP_WARNINGS_WARN      0x200000U /* Added to libpng-1.6.0 */
    @@ -1020,17 +1053,15 @@
      * must match that used in the build, or we must be using pnglibconf.h.prebuilt:
      */
     #if PNG_ZLIB_VERNUM != 0 && PNG_ZLIB_VERNUM != ZLIB_VERNUM
    -#  error ZLIB_VERNUM != PNG_ZLIB_VERNUM \
    -      "-I (include path) error: see the notes in pngpriv.h"
    -   /* This means that when pnglibconf.h was built the copy of zlib.h that it
    -    * used is not the same as the one being used here.  Because the build of
    -    * libpng makes decisions to use inflateInit2 and inflateReset2 based on the
    -    * zlib version number and because this affects handling of certain broken
    -    * PNG files the -I directives must match.
    +#  error The include path of  is incorrect
    +   /* When pnglibconf.h was built, the copy of zlib.h that it used was not the
    +    * same as the one being used here.  Considering how libpng makes decisions
    +    * to use the zlib API based on the zlib version number, the -I options must
    +    * match.
         *
    -    * The most likely explanation is that you passed a -I in CFLAGS. This will
    -    * not work; all the preprocessor directives and in particular all the -I
    -    * directives must be in CPPFLAGS.
    +    * A possible cause of this mismatch is that you passed an -I option in
    +    * CFLAGS, which is unlikely to work.  All the preprocessor options, and all
    +    * the -I options in particular, should be in CPPFLAGS.
         */
     #endif
     
    @@ -1544,6 +1575,23 @@ PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth4_lsx,(png_row_infop
         row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
     #endif
     
    +#if PNG_RISCV_RVV_IMPLEMENTATION == 1
    +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_up_rvv,(png_row_infop
    +    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
    +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub3_rvv,(png_row_infop
    +    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
    +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub4_rvv,(png_row_infop
    +    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
    +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg3_rvv,(png_row_infop
    +    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
    +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg4_rvv,(png_row_infop
    +    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
    +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth3_rvv,(png_row_infop
    +    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
    +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth4_rvv,(png_row_infop
    +    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
    +#endif
    +
     /* Choose the best filter to use and filter the row data */
     PNG_INTERNAL_FUNCTION(void,png_write_find_filter,(png_structrp png_ptr,
         png_row_infop row_info),PNG_EMPTY);
    @@ -2156,6 +2204,11 @@ PNG_INTERNAL_FUNCTION(void, png_init_filter_functions_lsx,
         (png_structp png_ptr, unsigned int bpp), PNG_EMPTY);
     #endif
     
    +#  if PNG_RISCV_RVV_IMPLEMENTATION == 1
    +PNG_INTERNAL_FUNCTION(void, png_init_filter_functions_rvv,
    +   (png_structp png_ptr, unsigned int bpp), PNG_EMPTY);
    +#endif
    +
     PNG_INTERNAL_FUNCTION(png_uint_32, png_check_keyword, (png_structrp png_ptr,
        png_const_charp key, png_bytep new_key), PNG_EMPTY);
     
    @@ -2191,4 +2244,3 @@ PNG_INTERNAL_FUNCTION(int,
     #endif
     
     #endif /* PNG_VERSION_INFO_ONLY */
    -#endif /* PNGPRIV_H */
    diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngread.c b/src/java.desktop/share/native/libsplashscreen/libpng/pngread.c
    index 8a6381e1b3e..b53668a09ce 100644
    --- a/src/java.desktop/share/native/libsplashscreen/libpng/pngread.c
    +++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngread.c
    @@ -731,7 +731,12 @@ png_read_end(png_structrp png_ptr, png_inforp info_ptr)
           png_uint_32 chunk_name = png_ptr->chunk_name;
     
           if (chunk_name != png_IDAT)
    -         png_ptr->mode |= PNG_HAVE_CHUNK_AFTER_IDAT;
    +      {
    +         /* These flags must be set consistently for all non-IDAT chunks,
    +          * including the unknown chunks.
    +          */
    +         png_ptr->mode |= PNG_HAVE_CHUNK_AFTER_IDAT | PNG_AFTER_IDAT;
    +      }
     
           if (chunk_name == png_IEND)
              png_handle_chunk(png_ptr, info_ptr, length);
    @@ -838,7 +843,8 @@ png_read_destroy(png_structrp png_ptr)
     #endif
     
     #if defined(PNG_READ_EXPAND_SUPPORTED) && \
    -    defined(PNG_ARM_NEON_IMPLEMENTATION)
    +    (defined(PNG_ARM_NEON_IMPLEMENTATION) || \
    +     defined(PNG_RISCV_RVV_IMPLEMENTATION))
        png_free(png_ptr, png_ptr->riffled_palette);
        png_ptr->riffled_palette = NULL;
     #endif
    @@ -1357,7 +1363,7 @@ png_image_read_header(png_voidp argument)
     
     #ifdef PNG_STDIO_SUPPORTED
     int PNGAPI
    -png_image_begin_read_from_stdio(png_imagep image, FILE* file)
    +png_image_begin_read_from_stdio(png_imagep image, FILE *file)
     {
        if (image != NULL && image->version == PNG_IMAGE_VERSION)
        {
    @@ -3152,6 +3158,54 @@ png_image_read_colormapped(png_voidp argument)
        }
     }
     
    +/* Row reading for interlaced 16-to-8 bit depth conversion with local buffer. */
    +static int
    +png_image_read_direct_scaled(png_voidp argument)
    +{
    +   png_image_read_control *display = png_voidcast(png_image_read_control*,
    +       argument);
    +   png_imagep image = display->image;
    +   png_structrp png_ptr = image->opaque->png_ptr;
    +   png_bytep local_row = png_voidcast(png_bytep, display->local_row);
    +   png_bytep first_row = png_voidcast(png_bytep, display->first_row);
    +   ptrdiff_t row_bytes = display->row_bytes;
    +   int passes;
    +
    +   /* Handle interlacing. */
    +   switch (png_ptr->interlaced)
    +   {
    +      case PNG_INTERLACE_NONE:
    +         passes = 1;
    +         break;
    +
    +      case PNG_INTERLACE_ADAM7:
    +         passes = PNG_INTERLACE_ADAM7_PASSES;
    +         break;
    +
    +      default:
    +         png_error(png_ptr, "unknown interlace type");
    +   }
    +
    +   /* Read each pass using local_row as intermediate buffer. */
    +   while (--passes >= 0)
    +   {
    +      png_uint_32 y = image->height;
    +      png_bytep output_row = first_row;
    +
    +      for (; y > 0; --y)
    +      {
    +         /* Read into local_row (gets transformed 8-bit data). */
    +         png_read_row(png_ptr, local_row, NULL);
    +
    +         /* Copy from local_row to user buffer. */
    +         memcpy(output_row, local_row, (size_t)row_bytes);
    +         output_row += row_bytes;
    +      }
    +   }
    +
    +   return 1;
    +}
    +
     /* Just the row reading part of png_image_read. */
     static int
     png_image_read_composite(png_voidp argument)
    @@ -3570,6 +3624,7 @@ png_image_read_direct(png_voidp argument)
        int linear = (format & PNG_FORMAT_FLAG_LINEAR) != 0;
        int do_local_compose = 0;
        int do_local_background = 0; /* to avoid double gamma correction bug */
    +   int do_local_scale = 0; /* for interlaced 16-to-8 bit conversion */
        int passes = 0;
     
        /* Add transforms to ensure the correct output format is produced then check
    @@ -3703,8 +3758,16 @@ png_image_read_direct(png_voidp argument)
                 png_set_expand_16(png_ptr);
     
              else /* 8-bit output */
    +         {
                 png_set_scale_16(png_ptr);
     
    +            /* For interlaced images, use local_row buffer to avoid overflow
    +             * in png_combine_row() which writes using IHDR bit-depth.
    +             */
    +            if (png_ptr->interlaced != 0)
    +               do_local_scale = 1;
    +         }
    +
              change &= ~PNG_FORMAT_FLAG_LINEAR;
           }
     
    @@ -3980,6 +4043,24 @@ png_image_read_direct(png_voidp argument)
           return result;
        }
     
    +   else if (do_local_scale != 0)
    +   {
    +      /* For interlaced 16-to-8 conversion, use an intermediate row buffer
    +       * to avoid buffer overflows in png_combine_row. The local_row is sized
    +       * for the transformed (8-bit) output, preventing the overflow that would
    +       * occur if png_combine_row wrote 16-bit data directly to the user buffer.
    +       */
    +      int result;
    +      png_voidp row = png_malloc(png_ptr, png_get_rowbytes(png_ptr, info_ptr));
    +
    +      display->local_row = row;
    +      result = png_safe_execute(image, png_image_read_direct_scaled, display);
    +      display->local_row = NULL;
    +      png_free(png_ptr, row);
    +
    +      return result;
    +   }
    +
        else
        {
           png_alloc_size_t row_bytes = (png_alloc_size_t)display->row_bytes;
    diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngrio.c b/src/java.desktop/share/native/libsplashscreen/libpng/pngrio.c
    index 961d010df42..50a424d0912 100644
    --- a/src/java.desktop/share/native/libsplashscreen/libpng/pngrio.c
    +++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngrio.c
    @@ -29,7 +29,7 @@
      * However, the following notice accompanied the original version of this
      * file and, per its terms, should not be removed:
      *
    - * Copyright (c) 2018 Cosmin Truta
    + * Copyright (c) 2018-2025 Cosmin Truta
      * Copyright (c) 1998-2002,2004,2006-2016,2018 Glenn Randers-Pehrson
      * Copyright (c) 1996-1997 Andreas Dilger
      * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
    @@ -85,7 +85,7 @@ png_default_read_data(png_structp png_ptr, png_bytep data, size_t length)
        /* fread() returns 0 on error, so it is OK to store this in a size_t
         * instead of an int, which is what fread() actually returns.
         */
    -   check = fread(data, 1, length, png_voidcast(png_FILE_p, png_ptr->io_ptr));
    +   check = fread(data, 1, length, png_voidcast(FILE *, png_ptr->io_ptr));
     
        if (check != length)
           png_error(png_ptr, "Read Error");
    diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngrtran.c b/src/java.desktop/share/native/libsplashscreen/libpng/pngrtran.c
    index 4f31f8f07bc..a19615f49fe 100644
    --- a/src/java.desktop/share/native/libsplashscreen/libpng/pngrtran.c
    +++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngrtran.c
    @@ -29,7 +29,7 @@
      * However, the following notice accompanied the original version of this
      * file and, per its terms, should not be removed:
      *
    - * Copyright (c) 2018-2024 Cosmin Truta
    + * Copyright (c) 2018-2025 Cosmin Truta
      * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
      * Copyright (c) 1996-1997 Andreas Dilger
      * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
    @@ -57,6 +57,12 @@
     #  endif
     #endif
     
    +#ifdef PNG_RISCV_RVV_IMPLEMENTATION
    +#  if PNG_RISCV_RVV_IMPLEMENTATION == 1
    +#    define PNG_RISCV_RVV_INTRINSICS_AVAILABLE
    +#  endif
    +#endif
    +
     #ifdef PNG_READ_SUPPORTED
     
     /* Set the action on getting a CRC error for an ancillary or critical chunk. */
    @@ -524,9 +530,19 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette,
        {
           int i;
     
    +      /* Initialize the array to index colors.
    +       *
    +       * Ensure quantize_index can fit 256 elements (PNG_MAX_PALETTE_LENGTH)
    +       * rather than num_palette elements. This is to prevent buffer overflows
    +       * caused by malformed PNG files with out-of-range palette indices.
    +       *
    +       * Be careful to avoid leaking memory. Applications are allowed to call
    +       * this function more than once per png_struct.
    +       */
    +      png_free(png_ptr, png_ptr->quantize_index);
           png_ptr->quantize_index = (png_bytep)png_malloc(png_ptr,
    -          (png_alloc_size_t)num_palette);
    -      for (i = 0; i < num_palette; i++)
    +          PNG_MAX_PALETTE_LENGTH);
    +      for (i = 0; i < PNG_MAX_PALETTE_LENGTH; i++)
              png_ptr->quantize_index[i] = (png_byte)i;
        }
     
    @@ -538,15 +554,14 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette,
               * Perhaps not the best solution, but good enough.
               */
     
    -         int i;
    +         png_bytep quantize_sort;
    +         int i, j;
     
    -         /* Initialize an array to sort colors */
    -         png_ptr->quantize_sort = (png_bytep)png_malloc(png_ptr,
    +         /* Initialize the local array to sort colors. */
    +         quantize_sort = (png_bytep)png_malloc(png_ptr,
                  (png_alloc_size_t)num_palette);
    -
    -         /* Initialize the quantize_sort array */
              for (i = 0; i < num_palette; i++)
    -            png_ptr->quantize_sort[i] = (png_byte)i;
    +            quantize_sort[i] = (png_byte)i;
     
              /* Find the least used palette entries by starting a
               * bubble sort, and running it until we have sorted
    @@ -558,19 +573,18 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette,
              for (i = num_palette - 1; i >= maximum_colors; i--)
              {
                 int done; /* To stop early if the list is pre-sorted */
    -            int j;
     
                 done = 1;
                 for (j = 0; j < i; j++)
                 {
    -               if (histogram[png_ptr->quantize_sort[j]]
    -                   < histogram[png_ptr->quantize_sort[j + 1]])
    +               if (histogram[quantize_sort[j]]
    +                   < histogram[quantize_sort[j + 1]])
                    {
                       png_byte t;
     
    -                  t = png_ptr->quantize_sort[j];
    -                  png_ptr->quantize_sort[j] = png_ptr->quantize_sort[j + 1];
    -                  png_ptr->quantize_sort[j + 1] = t;
    +                  t = quantize_sort[j];
    +                  quantize_sort[j] = quantize_sort[j + 1];
    +                  quantize_sort[j + 1] = t;
                       done = 0;
                    }
                 }
    @@ -582,18 +596,18 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette,
              /* Swap the palette around, and set up a table, if necessary */
              if (full_quantize != 0)
              {
    -            int j = num_palette;
    +            j = num_palette;
     
                 /* Put all the useful colors within the max, but don't
                  * move the others.
                  */
                 for (i = 0; i < maximum_colors; i++)
                 {
    -               if ((int)png_ptr->quantize_sort[i] >= maximum_colors)
    +               if ((int)quantize_sort[i] >= maximum_colors)
                    {
                       do
                          j--;
    -                  while ((int)png_ptr->quantize_sort[j] >= maximum_colors);
    +                  while ((int)quantize_sort[j] >= maximum_colors);
     
                       palette[i] = palette[j];
                    }
    @@ -601,7 +615,7 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette,
              }
              else
              {
    -            int j = num_palette;
    +            j = num_palette;
     
                 /* Move all the used colors inside the max limit, and
                  * develop a translation table.
    @@ -609,13 +623,13 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette,
                 for (i = 0; i < maximum_colors; i++)
                 {
                    /* Only move the colors we need to */
    -               if ((int)png_ptr->quantize_sort[i] >= maximum_colors)
    +               if ((int)quantize_sort[i] >= maximum_colors)
                    {
                       png_color tmp_color;
     
                       do
                          j--;
    -                  while ((int)png_ptr->quantize_sort[j] >= maximum_colors);
    +                  while ((int)quantize_sort[j] >= maximum_colors);
     
                       tmp_color = palette[j];
                       palette[j] = palette[i];
    @@ -653,8 +667,7 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette,
                    }
                 }
              }
    -         png_free(png_ptr, png_ptr->quantize_sort);
    -         png_ptr->quantize_sort = NULL;
    +         png_free(png_ptr, quantize_sort);
           }
           else
           {
    @@ -1797,19 +1810,51 @@ png_init_read_transformations(png_structrp png_ptr)
                       }
                       else /* if (png_ptr->trans_alpha[i] != 0xff) */
                       {
    -                     png_byte v, w;
    +                     if ((png_ptr->flags & PNG_FLAG_OPTIMIZE_ALPHA) != 0)
    +                     {
    +                        /* Premultiply only:
    +                         * component = round((component * alpha) / 255)
    +                         */
    +                        png_uint_32 component;
     
    -                     v = png_ptr->gamma_to_1[palette[i].red];
    -                     png_composite(w, v, png_ptr->trans_alpha[i], back_1.red);
    -                     palette[i].red = png_ptr->gamma_from_1[w];
    +                        component = png_ptr->gamma_to_1[palette[i].red];
    +                        component =
    +                            (component * png_ptr->trans_alpha[i] + 128) / 255;
    +                        palette[i].red = png_ptr->gamma_from_1[component];
     
    -                     v = png_ptr->gamma_to_1[palette[i].green];
    -                     png_composite(w, v, png_ptr->trans_alpha[i], back_1.green);
    -                     palette[i].green = png_ptr->gamma_from_1[w];
    +                        component = png_ptr->gamma_to_1[palette[i].green];
    +                        component =
    +                            (component * png_ptr->trans_alpha[i] + 128) / 255;
    +                        palette[i].green = png_ptr->gamma_from_1[component];
     
    -                     v = png_ptr->gamma_to_1[palette[i].blue];
    -                     png_composite(w, v, png_ptr->trans_alpha[i], back_1.blue);
    -                     palette[i].blue = png_ptr->gamma_from_1[w];
    +                        component = png_ptr->gamma_to_1[palette[i].blue];
    +                        component =
    +                            (component * png_ptr->trans_alpha[i] + 128) / 255;
    +                        palette[i].blue = png_ptr->gamma_from_1[component];
    +                     }
    +                     else
    +                     {
    +                        /* Composite with background color:
    +                         * component =
    +                         *    alpha * component + (1 - alpha) * background
    +                         */
    +                        png_byte v, w;
    +
    +                        v = png_ptr->gamma_to_1[palette[i].red];
    +                        png_composite(w, v,
    +                            png_ptr->trans_alpha[i], back_1.red);
    +                        palette[i].red = png_ptr->gamma_from_1[w];
    +
    +                        v = png_ptr->gamma_to_1[palette[i].green];
    +                        png_composite(w, v,
    +                            png_ptr->trans_alpha[i], back_1.green);
    +                        palette[i].green = png_ptr->gamma_from_1[w];
    +
    +                        v = png_ptr->gamma_to_1[palette[i].blue];
    +                        png_composite(w, v,
    +                            png_ptr->trans_alpha[i], back_1.blue);
    +                        palette[i].blue = png_ptr->gamma_from_1[w];
    +                     }
                       }
                    }
                    else
    @@ -5032,13 +5077,8 @@ png_do_read_transformations(png_structrp png_ptr, png_row_infop row_info)
     
     #ifdef PNG_READ_QUANTIZE_SUPPORTED
        if ((png_ptr->transformations & PNG_QUANTIZE) != 0)
    -   {
           png_do_quantize(row_info, png_ptr->row_buf + 1,
               png_ptr->palette_lookup, png_ptr->quantize_index);
    -
    -      if (row_info->rowbytes == 0)
    -         png_error(png_ptr, "png_do_quantize returned rowbytes=0");
    -   }
     #endif /* READ_QUANTIZE */
     
     #ifdef PNG_READ_EXPAND_16_SUPPORTED
    diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngrutil.c b/src/java.desktop/share/native/libsplashscreen/libpng/pngrutil.c
    index 6cf466d182a..07d53cb2c76 100644
    --- a/src/java.desktop/share/native/libsplashscreen/libpng/pngrutil.c
    +++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngrutil.c
    @@ -29,7 +29,7 @@
      * However, the following notice accompanied the original version of this
      * file and, per its terms, should not be removed:
      *
    - * Copyright (c) 2018-2024 Cosmin Truta
    + * Copyright (c) 2018-2025 Cosmin Truta
      * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
      * Copyright (c) 1996-1997 Andreas Dilger
      * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
    @@ -2441,10 +2441,6 @@ png_handle_tEXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
        }
     #endif
     
    -   /* TODO: this doesn't work and shouldn't be necessary. */
    -   if ((png_ptr->mode & PNG_HAVE_IDAT) != 0)
    -      png_ptr->mode |= PNG_AFTER_IDAT;
    -
        buffer = png_read_buffer(png_ptr, length+1);
     
        if (buffer == NULL)
    @@ -2515,10 +2511,6 @@ png_handle_zTXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
        }
     #endif
     
    -   /* TODO: should not be necessary. */
    -   if ((png_ptr->mode & PNG_HAVE_IDAT) != 0)
    -      png_ptr->mode |= PNG_AFTER_IDAT;
    -
        /* Note, "length" is sufficient here; we won't be adding
         * a null terminator later.  The limit check in png_handle_chunk should be
         * sufficient.
    @@ -2635,10 +2627,6 @@ png_handle_iTXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
        }
     #endif
     
    -   /* TODO: should not be necessary. */
    -   if ((png_ptr->mode & PNG_HAVE_IDAT) != 0)
    -      png_ptr->mode |= PNG_AFTER_IDAT;
    -
        buffer = png_read_buffer(png_ptr, length+1);
     
        if (buffer == NULL)
    diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngset.c b/src/java.desktop/share/native/libsplashscreen/libpng/pngset.c
    index 1bfd292bd46..0b2844f1864 100644
    --- a/src/java.desktop/share/native/libsplashscreen/libpng/pngset.c
    +++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngset.c
    @@ -329,17 +329,14 @@ png_set_mDCV(png_const_structrp png_ptr, png_inforp info_ptr,
         double maxDL, double minDL)
     {
        png_set_mDCV_fixed(png_ptr, info_ptr,
    -      /* The ITU approach is to scale by 50,000, not 100,000 so just divide
    -       * the input values by 2 and use png_fixed:
    -       */
    -      png_fixed(png_ptr, white_x / 2, "png_set_mDCV(white(x))"),
    -      png_fixed(png_ptr, white_y / 2, "png_set_mDCV(white(y))"),
    -      png_fixed(png_ptr, red_x / 2, "png_set_mDCV(red(x))"),
    -      png_fixed(png_ptr, red_y / 2, "png_set_mDCV(red(y))"),
    -      png_fixed(png_ptr, green_x / 2, "png_set_mDCV(green(x))"),
    -      png_fixed(png_ptr, green_y / 2, "png_set_mDCV(green(y))"),
    -      png_fixed(png_ptr, blue_x / 2, "png_set_mDCV(blue(x))"),
    -      png_fixed(png_ptr, blue_y / 2, "png_set_mDCV(blue(y))"),
    +      png_fixed(png_ptr, white_x, "png_set_mDCV(white(x))"),
    +      png_fixed(png_ptr, white_y, "png_set_mDCV(white(y))"),
    +      png_fixed(png_ptr, red_x, "png_set_mDCV(red(x))"),
    +      png_fixed(png_ptr, red_y, "png_set_mDCV(red(y))"),
    +      png_fixed(png_ptr, green_x, "png_set_mDCV(green(x))"),
    +      png_fixed(png_ptr, green_y, "png_set_mDCV(green(y))"),
    +      png_fixed(png_ptr, blue_x, "png_set_mDCV(blue(x))"),
    +      png_fixed(png_ptr, blue_y, "png_set_mDCV(blue(y))"),
           png_fixed_ITU(png_ptr, maxDL, "png_set_mDCV(maxDL)"),
           png_fixed_ITU(png_ptr, minDL, "png_set_mDCV(minDL)"));
     }
    diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngstruct.h b/src/java.desktop/share/native/libsplashscreen/libpng/pngstruct.h
    index d6c446564d1..8edb4bc393a 100644
    --- a/src/java.desktop/share/native/libsplashscreen/libpng/pngstruct.h
    +++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngstruct.h
    @@ -22,14 +22,14 @@
      * questions.
      */
     
    -/* pngstruct.h - header file for PNG reference library
    +/* pngstruct.h - internal structures for libpng
      *
      * This file is available under and governed by the GNU General Public
      * License version 2 only, as published by the Free Software Foundation.
      * However, the following notice accompanied the original version of this
      * file and, per its terms, should not be removed:
      *
    - * Copyright (c) 2018-2022 Cosmin Truta
    + * Copyright (c) 2018-2025 Cosmin Truta
      * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
      * Copyright (c) 1996-1997 Andreas Dilger
      * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
    @@ -39,11 +39,9 @@
      * and license in png.h
      */
     
    -/* The structure that holds the information to read and write PNG files.
    - * The only people who need to care about what is inside of this are the
    - * people who will be modifying the library for their own special needs.
    - * It should NOT be accessed directly by an application.
    - */
    +#ifndef PNGPRIV_H
    +#  error This file must not be included by applications; please include 
    +#endif
     
     #ifndef PNGSTRUCT_H
     #define PNGSTRUCT_H
    @@ -406,7 +404,8 @@ struct png_struct_def
     
     /* New member added in libpng-1.6.36 */
     #if defined(PNG_READ_EXPAND_SUPPORTED) && \
    -    defined(PNG_ARM_NEON_IMPLEMENTATION)
    +    (defined(PNG_ARM_NEON_IMPLEMENTATION) || \
    +     defined(PNG_RISCV_RVV_IMPLEMENTATION))
        png_bytep riffled_palette; /* buffer for accelerated palette expansion */
     #endif
     
    @@ -435,7 +434,6 @@ struct png_struct_def
     
     #ifdef PNG_READ_QUANTIZE_SUPPORTED
     /* The following three members were added at version 1.0.14 and 1.2.4 */
    -   png_bytep quantize_sort;          /* working sort array */
        png_bytep index_to_palette;       /* where the original index currently is
                                             in the palette */
        png_bytep palette_to_index;       /* which original index points to this
    
    From e0311ecb85b78b6d97387c17102a8b6759eefc36 Mon Sep 17 00:00:00 2001
    From: Jatin Bhateja 
    Date: Mon, 1 Dec 2025 06:04:23 +0000
    Subject: [PATCH 060/706] 8351016: RA support for EVEX to REX/REX2 demotion to
     optimize NDD instructions
    
    Reviewed-by: sviswanathan, dlunden, vlivanov, qamai
    ---
     src/hotspot/cpu/aarch64/aarch64.ad           |   4 +
     src/hotspot/cpu/arm/arm.ad                   |   4 +
     src/hotspot/cpu/ppc/ppc.ad                   |   4 +
     src/hotspot/cpu/riscv/riscv.ad               |   4 +
     src/hotspot/cpu/s390/s390.ad                 |   4 +
     src/hotspot/cpu/x86/x86.ad                   | 167 ++++++++++++++-----
     src/hotspot/share/opto/chaitin.cpp           | 105 +++++++++---
     src/hotspot/share/opto/chaitin.hpp           |   3 +
     src/hotspot/share/opto/idealGraphPrinter.cpp |   1 +
     src/hotspot/share/opto/machnode.cpp          |   7 +
     src/hotspot/share/opto/machnode.hpp          |   1 +
     src/hotspot/share/opto/matcher.hpp           |   2 +
     src/hotspot/share/opto/node.hpp              |  40 ++---
     13 files changed, 268 insertions(+), 78 deletions(-)
    
    diff --git a/src/hotspot/cpu/aarch64/aarch64.ad b/src/hotspot/cpu/aarch64/aarch64.ad
    index 364db407bd3..fc53c10311b 100644
    --- a/src/hotspot/cpu/aarch64/aarch64.ad
    +++ b/src/hotspot/cpu/aarch64/aarch64.ad
    @@ -2456,6 +2456,10 @@ bool Matcher::is_reg2reg_move(MachNode* m) {
       return false;
     }
     
    +bool Matcher::is_register_biasing_candidate(const MachNode* mdef, int oper_index) {
    +  return false;
    +}
    +
     bool Matcher::is_generic_vector(MachOper* opnd)  {
       return opnd->opcode() == VREG;
     }
    diff --git a/src/hotspot/cpu/arm/arm.ad b/src/hotspot/cpu/arm/arm.ad
    index af010caf616..606275d7666 100644
    --- a/src/hotspot/cpu/arm/arm.ad
    +++ b/src/hotspot/cpu/arm/arm.ad
    @@ -1063,6 +1063,10 @@ bool Matcher::is_reg2reg_move(MachNode* m) {
       return false;
     }
     
    +bool Matcher::is_register_biasing_candidate(const MachNode* mdef, int oper_index) {
    +  return false;
    +}
    +
     bool Matcher::is_generic_vector(MachOper* opnd)  {
       ShouldNotReachHere();  // generic vector operands not supported
       return false;
    diff --git a/src/hotspot/cpu/ppc/ppc.ad b/src/hotspot/cpu/ppc/ppc.ad
    index 762536df07f..87fcf112756 100644
    --- a/src/hotspot/cpu/ppc/ppc.ad
    +++ b/src/hotspot/cpu/ppc/ppc.ad
    @@ -2383,6 +2383,10 @@ bool Matcher::is_reg2reg_move(MachNode* m) {
       return false;
     }
     
    +bool Matcher::is_register_biasing_candidate(const MachNode* mdef, int oper_index) {
    +  return false;
    +}
    +
     bool Matcher::is_generic_vector(MachOper* opnd)  {
       ShouldNotReachHere();  // generic vector operands not supported
       return false;
    diff --git a/src/hotspot/cpu/riscv/riscv.ad b/src/hotspot/cpu/riscv/riscv.ad
    index bb2ed57ef82..3f5dd4ad0ee 100644
    --- a/src/hotspot/cpu/riscv/riscv.ad
    +++ b/src/hotspot/cpu/riscv/riscv.ad
    @@ -2053,6 +2053,10 @@ bool Matcher::is_reg2reg_move(MachNode* m) {
       return false;
     }
     
    +bool Matcher::is_register_biasing_candidate(const MachNode* mdef, int oper_index) {
    +  return false;
    +}
    +
     bool Matcher::is_generic_vector(MachOper* opnd) {
       ShouldNotReachHere(); // generic vector operands not supported
       return false;
    diff --git a/src/hotspot/cpu/s390/s390.ad b/src/hotspot/cpu/s390/s390.ad
    index 6fe051b55c7..7d3e963a108 100644
    --- a/src/hotspot/cpu/s390/s390.ad
    +++ b/src/hotspot/cpu/s390/s390.ad
    @@ -1865,6 +1865,10 @@ bool Matcher::is_reg2reg_move(MachNode* m) {
       return false;
     }
     
    +bool Matcher::is_register_biasing_candidate(const MachNode* mdef, int oper_index) {
    +  return false;
    +}
    +
     bool Matcher::is_generic_vector(MachOper* opnd)  {
       ShouldNotReachHere();  // generic vector operands not supported
       return false;
    diff --git a/src/hotspot/cpu/x86/x86.ad b/src/hotspot/cpu/x86/x86.ad
    index be9889b0a99..1d393897bca 100644
    --- a/src/hotspot/cpu/x86/x86.ad
    +++ b/src/hotspot/cpu/x86/x86.ad
    @@ -2633,6 +2633,70 @@ bool Matcher::supports_vector_calling_convention(void) {
       return EnableVectorSupport;
     }
     
    +static bool is_ndd_demotable(const MachNode* mdef) {
    +  return ((mdef->flags() & Node::PD::Flag_ndd_demotable) != 0);
    +}
    +
    +static bool is_ndd_demotable_commutative(const MachNode* mdef) {
    +  return ((mdef->flags() & Node::PD::Flag_ndd_demotable_commutative) != 0);
    +}
    +
    +static bool is_demotion_candidate(const MachNode* mdef) {
    +  return (is_ndd_demotable(mdef) || is_ndd_demotable_commutative(mdef));
    +}
    +
    +bool Matcher::is_register_biasing_candidate(const MachNode* mdef,
    +                                            int oper_index) {
    +  if (mdef == nullptr) {
    +    return false;
    +  }
    +
    +  if (mdef->num_opnds() <= oper_index || mdef->operand_index(oper_index) < 0 ||
    +      mdef->in(mdef->operand_index(oper_index)) == nullptr) {
    +    assert(oper_index != 1 || !is_demotion_candidate(mdef), "%s", mdef->Name());
    +    assert(oper_index != 2 || !is_ndd_demotable_commutative(mdef), "%s", mdef->Name());
    +    return false;
    +  }
    +
    +  // Complex memory operand covers multiple incoming edges needed for
    +  // address computation. Biasing def towards any address component will not
    +  // result in NDD demotion by assembler.
    +  if (mdef->operand_num_edges(oper_index) != 1) {
    +    assert(!is_ndd_demotable(mdef), "%s", mdef->Name());
    +    return false;
    +  }
    +
    +  // Demotion candidate must be register mask compatible with definition.
    +  const RegMask& oper_mask = mdef->in_RegMask(mdef->operand_index(oper_index));
    +  if (!oper_mask.overlap(mdef->out_RegMask())) {
    +    assert(!is_demotion_candidate(mdef), "%s", mdef->Name());
    +    return false;
    +  }
    +
    +  switch (oper_index) {
    +  // First operand of MachNode corresponding to Intel APX NDD selection
    +  // pattern can share its assigned register with definition operand if
    +  // their live ranges do not overlap. In such a scenario we can demote
    +  // it to legacy map0/map1 instruction by replacing its 4-byte extended
    +  // EVEX prefix with shorter REX/REX2 encoding. Demotion candidates
    +  // are decorated with a special flag by instruction selector.
    +  case 1:
    +    return is_demotion_candidate(mdef);
    +
    +  // Definition operand of commutative operation can be biased towards second
    +  // operand.
    +  case 2:
    +    return is_ndd_demotable_commutative(mdef);
    +
    +  // Current scheme only selects up to two biasing candidates
    +  default:
    +    assert(false, "unhandled operand index: %s", mdef->Name());
    +    break;
    +  }
    +
    +  return false;
    +}
    +
     OptoRegPair Matcher::vector_return_value(uint ideal_reg) {
       assert(EnableVectorSupport, "sanity");
       int lo = XMM0_num;
    @@ -2812,7 +2876,7 @@ static inline bool is_clz_non_subword_predicate_evex(BasicType bt, int vlen_byte
     
     class Node::PD {
     public:
    -  enum NodeFlags {
    +  enum NodeFlags : uint64_t {
         Flag_intel_jcc_erratum    = Node::_last_flag << 1,
         Flag_sets_carry_flag      = Node::_last_flag << 2,
         Flag_sets_parity_flag     = Node::_last_flag << 3,
    @@ -2824,7 +2888,9 @@ public:
         Flag_clears_zero_flag     = Node::_last_flag << 9,
         Flag_clears_overflow_flag = Node::_last_flag << 10,
         Flag_clears_sign_flag     = Node::_last_flag << 11,
    -    _last_flag                = Flag_clears_sign_flag
    +    Flag_ndd_demotable        = Node::_last_flag << 12,
    +    Flag_ndd_demotable_commutative = Node::_last_flag << 13,
    +    _last_flag                = Flag_ndd_demotable_commutative
       };
     };
     
    @@ -9801,7 +9867,7 @@ instruct addI_rReg_ndd(rRegI dst, rRegI src1, rRegI src2, rFlagsReg cr)
       predicate(UseAPX);
       match(Set dst (AddI src1 src2));
       effect(KILL cr);
    -  flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag);
    +  flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag, PD::Flag_ndd_demotable_commutative);
     
       format %{ "eaddl    $dst, $src1, $src2\t# int ndd" %}
       ins_encode %{
    @@ -9829,7 +9895,7 @@ instruct addI_rReg_rReg_imm_ndd(rRegI dst, rRegI src1, immI src2, rFlagsReg cr)
       predicate(UseAPX);
       match(Set dst (AddI src1 src2));
       effect(KILL cr);
    -  flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag);
    +  flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag, PD::Flag_ndd_demotable);
     
       format %{ "eaddl    $dst, $src1, $src2\t# int ndd" %}
       ins_encode %{
    @@ -9872,7 +9938,7 @@ instruct addI_rReg_rReg_mem_ndd(rRegI dst, rRegI src1, memory src2, rFlagsReg cr
       predicate(UseAPX);
       match(Set dst (AddI src1 (LoadI src2)));
       effect(KILL cr);
    -  flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag);
    +  flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag, PD::Flag_ndd_demotable_commutative);
     
       ins_cost(150);
       format %{ "eaddl    $dst, $src1, $src2\t# int ndd" %}
    @@ -9929,6 +9995,7 @@ instruct incI_rReg_ndd(rRegI dst, rRegI src, immI_1 val, rFlagsReg cr)
       predicate(UseAPX && UseIncDec);
       match(Set dst (AddI src val));
       effect(KILL cr);
    +  flag(PD::Flag_ndd_demotable);
     
       format %{ "eincl    $dst, $src\t# int ndd" %}
       ins_encode %{
    @@ -9983,6 +10050,7 @@ instruct decI_rReg_ndd(rRegI dst, rRegI src, immI_M1 val, rFlagsReg cr)
       predicate(UseAPX && UseIncDec);
       match(Set dst (AddI src val));
       effect(KILL cr);
    +  flag(PD::Flag_ndd_demotable);
     
       format %{ "edecl    $dst, $src\t# int ndd" %}
       ins_encode %{
    @@ -10089,7 +10157,7 @@ instruct addL_rReg_ndd(rRegL dst, rRegL src1, rRegL src2, rFlagsReg cr)
       predicate(UseAPX);
       match(Set dst (AddL src1 src2));
       effect(KILL cr);
    -  flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag);
    +  flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag, PD::Flag_ndd_demotable_commutative);
     
       format %{ "eaddq    $dst, $src1, $src2\t# long ndd" %}
       ins_encode %{
    @@ -10117,7 +10185,7 @@ instruct addL_rReg_rReg_imm_ndd(rRegL dst, rRegL src1, immL32 src2, rFlagsReg cr
       predicate(UseAPX);
       match(Set dst (AddL src1 src2));
       effect(KILL cr);
    -  flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag);
    +  flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag, PD::Flag_ndd_demotable);
     
       format %{ "eaddq    $dst, $src1, $src2\t# long ndd" %}
       ins_encode %{
    @@ -10160,7 +10228,7 @@ instruct addL_rReg_rReg_mem_ndd(rRegL dst, rRegL src1, memory src2, rFlagsReg cr
       predicate(UseAPX);
       match(Set dst (AddL src1 (LoadL src2)));
       effect(KILL cr);
    -  flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag);
    +  flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag, PD::Flag_ndd_demotable_commutative);
     
       ins_cost(150);
       format %{ "eaddq    $dst, $src1, $src2\t# long ndd" %}
    @@ -10216,6 +10284,7 @@ instruct incL_rReg_ndd(rRegL dst, rRegI src, immL1 val, rFlagsReg cr)
       predicate(UseAPX && UseIncDec);
       match(Set dst (AddL src val));
       effect(KILL cr);
    +  flag(PD::Flag_ndd_demotable);
     
       format %{ "eincq    $dst, $src\t# long ndd" %}
       ins_encode %{
    @@ -10270,6 +10339,7 @@ instruct decL_rReg_ndd(rRegL dst, rRegL src, immL_M1 val, rFlagsReg cr)
       predicate(UseAPX && UseIncDec);
       match(Set dst (AddL src val));
       effect(KILL cr);
    +  flag(PD::Flag_ndd_demotable);
     
       format %{ "edecq    $dst, $src\t# long ndd" %}
       ins_encode %{
    @@ -10984,7 +11054,7 @@ instruct subI_rReg_ndd(rRegI dst, rRegI src1, rRegI src2, rFlagsReg cr)
       predicate(UseAPX);
       match(Set dst (SubI src1 src2));
       effect(KILL cr);
    -  flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag);
    +  flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag, PD::Flag_ndd_demotable);
     
       format %{ "esubl    $dst, $src1, $src2\t# int ndd" %}
       ins_encode %{
    @@ -10998,7 +11068,7 @@ instruct subI_rReg_rReg_imm_ndd(rRegI dst, rRegI src1, immI src2, rFlagsReg cr)
       predicate(UseAPX);
       match(Set dst (SubI src1 src2));
       effect(KILL cr);
    -  flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag);
    +  flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag, PD::Flag_ndd_demotable);
     
       format %{ "esubl    $dst, $src1, $src2\t# int ndd" %}
       ins_encode %{
    @@ -11041,7 +11111,7 @@ instruct subI_rReg_rReg_mem_ndd(rRegI dst, rRegI src1, memory src2, rFlagsReg cr
       predicate(UseAPX);
       match(Set dst (SubI src1 (LoadI src2)));
       effect(KILL cr);
    -  flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag);
    +  flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag, PD::Flag_ndd_demotable);
     
       ins_cost(150);
       format %{ "esubl    $dst, $src1, $src2\t# int ndd" %}
    @@ -11099,7 +11169,7 @@ instruct subL_rReg_ndd(rRegL dst, rRegL src1, rRegL src2, rFlagsReg cr)
       predicate(UseAPX);
       match(Set dst (SubL src1 src2));
       effect(KILL cr);
    -  flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag);
    +  flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag, PD::Flag_ndd_demotable);
     
       format %{ "esubq    $dst, $src1, $src2\t# long ndd" %}
       ins_encode %{
    @@ -11113,7 +11183,7 @@ instruct subL_rReg_rReg_imm_ndd(rRegL dst, rRegL src1, immL32 src2, rFlagsReg cr
       predicate(UseAPX);
       match(Set dst (SubL src1 src2));
       effect(KILL cr);
    -  flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag);
    +  flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag, PD::Flag_ndd_demotable);
     
       format %{ "esubq    $dst, $src1, $src2\t# long ndd" %}
       ins_encode %{
    @@ -11156,7 +11226,7 @@ instruct subL_rReg_rReg_mem_ndd(rRegL dst, rRegL src1, memory src2, rFlagsReg cr
       predicate(UseAPX);
       match(Set dst (SubL src1 (LoadL src2)));
       effect(KILL cr);
    -  flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag);
    +  flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag, PD::Flag_ndd_demotable);
     
       ins_cost(150);
       format %{ "esubq    $dst, $src1, $src2\t# long ndd" %}
    @@ -11228,7 +11298,7 @@ instruct negI_rReg_ndd(rRegI dst, rRegI src, immI_0 zero, rFlagsReg cr)
       predicate(UseAPX);
       match(Set dst (SubI zero src));
       effect(KILL cr);
    -  flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag);
    +  flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_ndd_demotable);
     
       format %{ "enegl    $dst, $src\t# int ndd" %}
       ins_encode %{
    @@ -11256,7 +11326,7 @@ instruct negI_rReg_2_ndd(rRegI dst, rRegI src, rFlagsReg cr)
       predicate(UseAPX);
       match(Set dst (NegI src));
       effect(KILL cr);
    -  flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag);
    +  flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_ndd_demotable);
     
       format %{ "enegl    $dst, $src\t# int ndd" %}
       ins_encode %{
    @@ -11297,7 +11367,7 @@ instruct negL_rReg_ndd(rRegL dst, rRegL src, immL0 zero, rFlagsReg cr)
       predicate(UseAPX);
       match(Set dst (SubL zero src));
       effect(KILL cr);
    -  flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag);
    +  flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_ndd_demotable);
     
       format %{ "enegq    $dst, $src\t# long ndd" %}
       ins_encode %{
    @@ -11325,7 +11395,7 @@ instruct negL_rReg_2_ndd(rRegL dst, rRegL src, rFlagsReg cr)
       predicate(UseAPX);
       match(Set dst (NegL src));
       effect(KILL cr);
    -  flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag);
    +  flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_ndd_demotable);
     
       format %{ "enegq    $dst, $src\t# long ndd" %}
       ins_encode %{
    @@ -11370,6 +11440,7 @@ instruct mulI_rReg_ndd(rRegI dst, rRegI src1, rRegI src2, rFlagsReg cr)
       predicate(UseAPX);
       match(Set dst (MulI src1 src2));
       effect(KILL cr);
    +  flag(PD::Flag_ndd_demotable_commutative);
     
       ins_cost(300);
       format %{ "eimull   $dst, $src1, $src2\t# int ndd" %}
    @@ -11411,6 +11482,7 @@ instruct mulI_rReg_rReg_mem_ndd(rRegI dst, rRegI src1, memory src2, rFlagsReg cr
       predicate(UseAPX);
       match(Set dst (MulI src1 (LoadI src2)));
       effect(KILL cr);
    +  flag(PD::Flag_ndd_demotable);
     
       ins_cost(350);
       format %{ "eimull   $dst, $src1, $src2\t# int ndd" %}
    @@ -11462,6 +11534,7 @@ instruct mulL_rReg_ndd(rRegL dst, rRegL src1, rRegL src2, rFlagsReg cr)
       predicate(UseAPX);
       match(Set dst (MulL src1 src2));
       effect(KILL cr);
    +  flag(PD::Flag_ndd_demotable_commutative);
     
       ins_cost(300);
       format %{ "eimulq   $dst, $src1, $src2\t# long ndd" %}
    @@ -11503,6 +11576,7 @@ instruct mulL_rReg_rReg_mem_ndd(rRegL dst, rRegL src1, memory src2, rFlagsReg cr
       predicate(UseAPX);
       match(Set dst (MulL src1 (LoadL src2)));
       effect(KILL cr);
    +  flag(PD::Flag_ndd_demotable_commutative);
     
       ins_cost(350);
       format %{ "eimulq   $dst, $src1, $src2 \t# long" %}
    @@ -11777,6 +11851,7 @@ instruct salI_rReg_immI2_ndd(rRegI dst, rRegI src, immI2 shift, rFlagsReg cr)
       predicate(UseAPX);
       match(Set dst (LShiftI src shift));
       effect(KILL cr);
    +  flag(PD::Flag_ndd_demotable);
     
       format %{ "esall    $dst, $src, $shift\t# int(ndd)" %}
       ins_encode %{
    @@ -11805,6 +11880,7 @@ instruct salI_rReg_imm_ndd(rRegI dst, rRegI src, immI8 shift, rFlagsReg cr)
       predicate(UseAPX);
       match(Set dst (LShiftI src shift));
       effect(KILL cr);
    +  flag(PD::Flag_ndd_demotable);
     
       format %{ "esall    $dst, $src, $shift\t# int (ndd)" %}
       ins_encode %{
    @@ -11911,6 +11987,7 @@ instruct sarI_rReg_imm_ndd(rRegI dst, rRegI src, immI8 shift, rFlagsReg cr)
       predicate(UseAPX);
       match(Set dst (RShiftI src shift));
       effect(KILL cr);
    +  flag(PD::Flag_ndd_demotable);
     
       format %{ "esarl    $dst, $src, $shift\t# int (ndd)" %}
       ins_encode %{
    @@ -12017,6 +12094,7 @@ instruct shrI_rReg_imm_ndd(rRegI dst, rRegI src, immI8 shift, rFlagsReg cr)
       predicate(UseAPX);
       match(Set dst (URShiftI src shift));
       effect(KILL cr);
    +  flag(PD::Flag_ndd_demotable);
     
       format %{ "eshrl    $dst, $src, $shift\t # int (ndd)" %}
       ins_encode %{
    @@ -12124,6 +12202,7 @@ instruct salL_rReg_immI2_ndd(rRegL dst, rRegL src, immI2 shift, rFlagsReg cr)
       predicate(UseAPX);
       match(Set dst (LShiftL src shift));
       effect(KILL cr);
    +  flag(PD::Flag_ndd_demotable);
     
       format %{ "esalq    $dst, $src, $shift\t# long (ndd)" %}
       ins_encode %{
    @@ -12152,6 +12231,7 @@ instruct salL_rReg_imm_ndd(rRegL dst, rRegL src, immI8 shift, rFlagsReg cr)
       predicate(UseAPX);
       match(Set dst (LShiftL src shift));
       effect(KILL cr);
    +  flag(PD::Flag_ndd_demotable);
     
       format %{ "esalq    $dst, $src, $shift\t# long (ndd)" %}
       ins_encode %{
    @@ -12258,6 +12338,7 @@ instruct sarL_rReg_imm_ndd(rRegL dst, rRegL src, immI shift, rFlagsReg cr)
       predicate(UseAPX);
       match(Set dst (RShiftL src shift));
       effect(KILL cr);
    +  flag(PD::Flag_ndd_demotable);
     
       format %{ "esarq    $dst, $src, $shift\t# long (ndd)" %}
       ins_encode %{
    @@ -12364,6 +12445,7 @@ instruct shrL_rReg_imm_ndd(rRegL dst, rRegL src, immI8 shift, rFlagsReg cr)
       predicate(UseAPX);
       match(Set dst (URShiftL src shift));
       effect(KILL cr);
    +  flag(PD::Flag_ndd_demotable);
     
       format %{ "eshrq    $dst, $src, $shift\t# long (ndd)" %}
       ins_encode %{
    @@ -12535,6 +12617,7 @@ instruct rolI_rReg_Var_ndd(rRegI dst, rRegI src, rcx_RegI shift, rFlagsReg cr)
       predicate(UseAPX && n->bottom_type()->basic_type() == T_INT);
       match(Set dst (RotateLeft src shift));
       effect(KILL cr);
    +  flag(PD::Flag_ndd_demotable);
     
       format %{ "eroll    $dst, $src, $shift\t# rotate left (int ndd)" %}
       ins_encode %{
    @@ -12599,6 +12682,7 @@ instruct rorI_rReg_Var_ndd(rRegI dst, rRegI src, rcx_RegI shift, rFlagsReg cr)
       predicate(UseAPX && n->bottom_type()->basic_type() == T_INT);
       match(Set dst (RotateRight src shift));
       effect(KILL cr);
    +  flag(PD::Flag_ndd_demotable);
     
       format %{ "erorl    $dst, $src, $shift\t# rotate right(int ndd)" %}
       ins_encode %{
    @@ -12651,6 +12735,7 @@ instruct rolL_rReg_Var(rRegL dst, rcx_RegI shift, rFlagsReg cr)
       predicate(!UseAPX && n->bottom_type()->basic_type() == T_LONG);
       match(Set dst (RotateLeft dst shift));
       effect(KILL cr);
    +
       format %{ "rolq    $dst, $shift" %}
       ins_encode %{
         __ rolq($dst$$Register);
    @@ -12664,6 +12749,7 @@ instruct rolL_rReg_Var_ndd(rRegL dst, rRegL src, rcx_RegI shift, rFlagsReg cr)
       predicate(UseAPX && n->bottom_type()->basic_type() == T_LONG);
       match(Set dst (RotateLeft src shift));
       effect(KILL cr);
    +  flag(PD::Flag_ndd_demotable);
     
       format %{ "erolq    $dst, $src, $shift\t# rotate left(long ndd)" %}
       ins_encode %{
    @@ -12728,6 +12814,7 @@ instruct rorL_rReg_Var_ndd(rRegL dst, rRegL src, rcx_RegI shift, rFlagsReg cr)
       predicate(UseAPX && n->bottom_type()->basic_type() == T_LONG);
       match(Set dst (RotateRight src shift));
       effect(KILL cr);
    +  flag(PD::Flag_ndd_demotable);
     
       format %{ "erorq    $dst, $src, $shift\t# rotate right(long ndd)" %}
       ins_encode %{
    @@ -12805,7 +12892,7 @@ instruct andI_rReg_ndd(rRegI dst, rRegI src1, rRegI src2, rFlagsReg cr)
       predicate(UseAPX);
       match(Set dst (AndI src1 src2));
       effect(KILL cr);
    -  flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag);
    +  flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag, PD::Flag_ndd_demotable_commutative);
     
       format %{ "eandl     $dst, $src1, $src2\t# int ndd" %}
       ins_encode %{
    @@ -12898,7 +12985,7 @@ instruct andI_rReg_rReg_imm_ndd(rRegI dst, rRegI src1, immI src2, rFlagsReg cr)
       predicate(UseAPX);
       match(Set dst (AndI src1 src2));
       effect(KILL cr);
    -  flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag);
    +  flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag, PD::Flag_ndd_demotable);
     
       format %{ "eandl    $dst, $src1, $src2\t# int ndd" %}
       ins_encode %{
    @@ -12942,7 +13029,7 @@ instruct andI_rReg_rReg_mem_ndd(rRegI dst, rRegI src1, memory src2, rFlagsReg cr
       predicate(UseAPX);
       match(Set dst (AndI src1 (LoadI src2)));
       effect(KILL cr);
    -  flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag);
    +  flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag, PD::Flag_ndd_demotable_commutative);
     
       ins_cost(150);
       format %{ "eandl    $dst, $src1, $src2\t# int ndd" %}
    @@ -13142,7 +13229,7 @@ instruct orI_rReg_ndd(rRegI dst, rRegI src1, rRegI src2, rFlagsReg cr)
       predicate(UseAPX);
       match(Set dst (OrI src1 src2));
       effect(KILL cr);
    -  flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag);
    +  flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag, PD::Flag_ndd_demotable_commutative);
     
       format %{ "eorl     $dst, $src1, $src2\t# int ndd" %}
       ins_encode %{
    @@ -13171,7 +13258,7 @@ instruct orI_rReg_rReg_imm_ndd(rRegI dst, rRegI src1, immI src2, rFlagsReg cr)
       predicate(UseAPX);
       match(Set dst (OrI src1 src2));
       effect(KILL cr);
    -  flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag);
    +  flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag, PD::Flag_ndd_demotable);
     
       format %{ "eorl     $dst, $src1, $src2\t# int ndd" %}
       ins_encode %{
    @@ -13185,7 +13272,7 @@ instruct orI_rReg_imm_rReg_ndd(rRegI dst, immI src1, rRegI src2, rFlagsReg cr)
       predicate(UseAPX);
       match(Set dst (OrI src1 src2));
       effect(KILL cr);
    -  flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag);
    +  flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag, PD::Flag_ndd_demotable);
     
       format %{ "eorl     $dst, $src2, $src1\t# int ndd" %}
       ins_encode %{
    @@ -13229,7 +13316,7 @@ instruct orI_rReg_rReg_mem_ndd(rRegI dst, rRegI src1, memory src2, rFlagsReg cr)
       predicate(UseAPX);
       match(Set dst (OrI src1 (LoadI src2)));
       effect(KILL cr);
    -  flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag);
    +  flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag, PD::Flag_ndd_demotable);
     
       ins_cost(150);
       format %{ "eorl     $dst, $src1, $src2\t# int ndd" %}
    @@ -13305,7 +13392,7 @@ instruct xorI_rReg_ndd(rRegI dst, rRegI src1, rRegI src2, rFlagsReg cr)
       predicate(UseAPX);
       match(Set dst (XorI src1 src2));
       effect(KILL cr);
    -  flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag);
    +  flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag, PD::Flag_ndd_demotable_commutative);
     
       format %{ "exorl    $dst, $src1, $src2\t# int ndd" %}
       ins_encode %{
    @@ -13331,6 +13418,7 @@ instruct xorI_rReg_im1_ndd(rRegI dst, rRegI src, immI_M1 imm)
     %{
       match(Set dst (XorI src imm));
       predicate(UseAPX);
    +  flag(PD::Flag_ndd_demotable);
     
       format %{ "enotl    $dst, $src" %}
       ins_encode %{
    @@ -13361,7 +13449,7 @@ instruct xorI_rReg_rReg_imm_ndd(rRegI dst, rRegI src1, immI src2, rFlagsReg cr)
       predicate(UseAPX && n->in(2)->bottom_type()->is_int()->get_con() != -1);
       match(Set dst (XorI src1 src2));
       effect(KILL cr);
    -  flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag);
    +  flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag, PD::Flag_ndd_demotable);
     
       format %{ "exorl    $dst, $src1, $src2\t# int ndd" %}
       ins_encode %{
    @@ -13407,7 +13495,7 @@ instruct xorI_rReg_rReg_mem_ndd(rRegI dst, rRegI src1, memory src2, rFlagsReg cr
       predicate(UseAPX);
       match(Set dst (XorI src1 (LoadI src2)));
       effect(KILL cr);
    -  flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag);
    +  flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag, PD::Flag_ndd_demotable);
     
       ins_cost(150);
       format %{ "exorl    $dst, $src1, $src2\t# int ndd" %}
    @@ -13486,7 +13574,7 @@ instruct andL_rReg_ndd(rRegL dst, rRegL src1, rRegL src2, rFlagsReg cr)
       predicate(UseAPX);
       match(Set dst (AndL src1 src2));
       effect(KILL cr);
    -  flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag);
    +  flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag, PD::Flag_ndd_demotable_commutative);
     
       format %{ "eandq     $dst, $src1, $src2\t# long ndd" %}
       ins_encode %{
    @@ -13542,7 +13630,7 @@ instruct andL_rReg_rReg_imm_ndd(rRegL dst, rRegL src1, immL32 src2, rFlagsReg cr
       predicate(UseAPX);
       match(Set dst (AndL src1 src2));
       effect(KILL cr);
    -  flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag);
    +  flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag, PD::Flag_ndd_demotable);
     
       format %{ "eandq    $dst, $src1, $src2\t# long ndd" %}
       ins_encode %{
    @@ -13586,7 +13674,7 @@ instruct andL_rReg_rReg_mem_ndd(rRegL dst, rRegL src1, memory src2, rFlagsReg cr
       predicate(UseAPX);
       match(Set dst (AndL src1 (LoadL src2)));
       effect(KILL cr);
    -  flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag);
    +  flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag, PD::Flag_ndd_demotable_commutative);
     
       ins_cost(150);
       format %{ "eandq    $dst, $src1, $src2\t# long ndd" %}
    @@ -13789,7 +13877,7 @@ instruct orL_rReg_ndd(rRegL dst, rRegL src1, rRegL src2, rFlagsReg cr)
       predicate(UseAPX);
       match(Set dst (OrL src1 src2));
       effect(KILL cr);
    -  flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag);
    +  flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag, PD::Flag_ndd_demotable_commutative);
     
       format %{ "eorq     $dst, $src1, $src2\t# long ndd" %}
       ins_encode %{
    @@ -13844,7 +13932,7 @@ instruct orL_rReg_rReg_imm_ndd(rRegL dst, rRegL src1, immL32 src2, rFlagsReg cr)
       predicate(UseAPX);
       match(Set dst (OrL src1 src2));
       effect(KILL cr);
    -  flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag);
    +  flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag, PD::Flag_ndd_demotable);
     
       format %{ "eorq     $dst, $src1, $src2\t# long ndd" %}
       ins_encode %{
    @@ -13858,7 +13946,7 @@ instruct orL_rReg_imm_rReg_ndd(rRegL dst, immL32 src1, rRegL src2, rFlagsReg cr)
       predicate(UseAPX);
       match(Set dst (OrL src1 src2));
       effect(KILL cr);
    -  flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag);
    +  flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag, PD::Flag_ndd_demotable);
     
       format %{ "eorq     $dst, $src2, $src1\t# long ndd" %}
       ins_encode %{
    @@ -13903,7 +13991,7 @@ instruct orL_rReg_rReg_mem_ndd(rRegL dst, rRegL src1, memory src2, rFlagsReg cr)
       predicate(UseAPX);
       match(Set dst (OrL src1 (LoadL src2)));
       effect(KILL cr);
    -  flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag);
    +  flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag, PD::Flag_ndd_demotable_commutative);
     
       ins_cost(150);
       format %{ "eorq     $dst, $src1, $src2\t# long ndd" %}
    @@ -13982,7 +14070,7 @@ instruct xorL_rReg_ndd(rRegL dst, rRegL src1, rRegL src2, rFlagsReg cr)
       predicate(UseAPX);
       match(Set dst (XorL src1 src2));
       effect(KILL cr);
    -  flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag);
    +  flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag, PD::Flag_ndd_demotable_commutative);
     
       format %{ "exorq    $dst, $src1, $src2\t# long ndd" %}
       ins_encode %{
    @@ -14008,6 +14096,7 @@ instruct xorL_rReg_im1_ndd(rRegL dst,rRegL src, immL_M1 imm)
     %{
       predicate(UseAPX);
       match(Set dst (XorL src imm));
    +  flag(PD::Flag_ndd_demotable);
     
       format %{ "enotq   $dst, $src" %}
       ins_encode %{
    @@ -14038,7 +14127,7 @@ instruct xorL_rReg_rReg_imm(rRegL dst, rRegL src1, immL32 src2, rFlagsReg cr)
       predicate(UseAPX && n->in(2)->bottom_type()->is_long()->get_con() != -1L);
       match(Set dst (XorL src1 src2));
       effect(KILL cr);
    -  flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag);
    +  flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag, PD::Flag_ndd_demotable);
     
       format %{ "exorq    $dst, $src1, $src2\t# long ndd" %}
       ins_encode %{
    @@ -14084,7 +14173,7 @@ instruct xorL_rReg_rReg_mem_ndd(rRegL dst, rRegL src1, memory src2, rFlagsReg cr
       predicate(UseAPX);
       match(Set dst (XorL src1 (LoadL src2)));
       effect(KILL cr);
    -  flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag);
    +  flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag, PD::Flag_ndd_demotable_commutative);
     
       ins_cost(150);
       format %{ "exorq    $dst, $src1, $src2\t# long ndd" %}
    @@ -16539,6 +16628,7 @@ instruct minI_rReg_ndd(rRegI dst, rRegI src1, rRegI src2)
       predicate(UseAPX);
       match(Set dst (MinI src1 src2));
       effect(DEF dst, USE src1, USE src2);
    +  flag(PD::Flag_ndd_demotable);
     
       ins_cost(200);
       expand %{
    @@ -16590,6 +16680,7 @@ instruct maxI_rReg_ndd(rRegI dst, rRegI src1, rRegI src2)
       predicate(UseAPX);
       match(Set dst (MaxI src1 src2));
       effect(DEF dst, USE src1, USE src2);
    +  flag(PD::Flag_ndd_demotable);
     
       ins_cost(200);
       expand %{
    diff --git a/src/hotspot/share/opto/chaitin.cpp b/src/hotspot/share/opto/chaitin.cpp
    index 524dee6e06a..667270d96b4 100644
    --- a/src/hotspot/share/opto/chaitin.cpp
    +++ b/src/hotspot/share/opto/chaitin.cpp
    @@ -1471,6 +1471,65 @@ static OptoReg::Name find_first_set(LRG& lrg, RegMask& mask) {
       return assigned;
     }
     
    +OptoReg::Name PhaseChaitin::select_bias_lrg_color(LRG& lrg) {
    +  uint bias_lrg1_idx = _lrg_map.find(lrg._copy_bias);
    +  uint bias_lrg2_idx = _lrg_map.find(lrg._copy_bias2);
    +
    +  // If bias_lrg1 has a color
    +  if (bias_lrg1_idx != 0 && !_ifg->_yanked->test(bias_lrg1_idx)) {
    +    OptoReg::Name reg = lrgs(bias_lrg1_idx).reg();
    +    //  and it is legal for lrg
    +    if (is_legal_reg(lrg, reg)) {
    +      return reg;
    +    }
    +  }
    +
    +  // If bias_lrg2 has a color
    +  if (bias_lrg2_idx != 0 && !_ifg->_yanked->test(bias_lrg2_idx)) {
    +    OptoReg::Name reg = lrgs(bias_lrg2_idx).reg();
    +    //  and it is legal for lrg
    +    if (is_legal_reg(lrg, reg)) {
    +      return reg;
    +    }
    +  }
    +
    +  uint bias_lrg_idx = 0;
    +  if (bias_lrg1_idx != 0 && bias_lrg2_idx != 0) {
    +    // Since none of the bias live ranges are part of the IFG yet, constrain the
    +    // definition mask with the bias live range with the least degrees of
    +    // freedom. This will increase the chances of register sharing once the bias
    +    // live range becomes part of the IFG.
    +    lrgs(bias_lrg1_idx).compute_set_mask_size();
    +    lrgs(bias_lrg2_idx).compute_set_mask_size();
    +    bias_lrg_idx = lrgs(bias_lrg1_idx).degrees_of_freedom() >
    +                           lrgs(bias_lrg2_idx).degrees_of_freedom()
    +                       ? bias_lrg2_idx
    +                       : bias_lrg1_idx;
    +  } else if (bias_lrg1_idx != 0) {
    +    bias_lrg_idx = bias_lrg1_idx;
    +  } else if (bias_lrg2_idx != 0) {
    +    bias_lrg_idx = bias_lrg2_idx;
    +  }
    +
    +  // Register masks with offset excludes all mask bits before the offset.
    +  // Such masks are mainly used for allocation from stack slots. Constrain the
    +  // register mask of definition live range using bias mask only if
    +  // both masks have zero offset.
    +  if (bias_lrg_idx != 0 && !lrg.mask().is_offset() &&
    +      !lrgs(bias_lrg_idx).mask().is_offset()) {
    +    // Choose a color which is legal for bias_lrg
    +    ResourceMark rm(C->regmask_arena());
    +    RegMask tempmask(lrg.mask(), C->regmask_arena());
    +    tempmask.and_with(lrgs(bias_lrg_idx).mask());
    +    tempmask.clear_to_sets(lrg.num_regs());
    +    OptoReg::Name reg = find_first_set(lrg, tempmask);
    +    if (OptoReg::is_valid(reg)) {
    +      return reg;
    +    }
    +  }
    +  return OptoReg::Bad;
    +}
    +
     // Choose a color using the biasing heuristic
     OptoReg::Name PhaseChaitin::bias_color(LRG& lrg) {
     
    @@ -1492,25 +1551,10 @@ OptoReg::Name PhaseChaitin::bias_color(LRG& lrg) {
         }
       }
     
    -  uint copy_lrg = _lrg_map.find(lrg._copy_bias);
    -  if (copy_lrg != 0) {
    -    // If he has a color,
    -    if(!_ifg->_yanked->test(copy_lrg)) {
    -      OptoReg::Name reg = lrgs(copy_lrg).reg();
    -      //  And it is legal for you,
    -      if (is_legal_reg(lrg, reg)) {
    -        return reg;
    -      }
    -    } else if (!lrg.mask().is_offset()) {
    -      // Choose a color which is legal for him
    -      ResourceMark rm(C->regmask_arena());
    -      RegMask tempmask(lrg.mask(), C->regmask_arena());
    -      tempmask.and_with(lrgs(copy_lrg).mask());
    -      tempmask.clear_to_sets(lrg.num_regs());
    -      OptoReg::Name reg = find_first_set(lrg, tempmask);
    -      if (OptoReg::is_valid(reg))
    -        return reg;
    -    }
    +  // Try biasing the color with non-interfering bias live range[s].
    +  OptoReg::Name reg = select_bias_lrg_color(lrg);
    +  if (OptoReg::is_valid(reg)) {
    +    return reg;
       }
     
       // If no bias info exists, just go with the register selection ordering
    @@ -1524,7 +1568,7 @@ OptoReg::Name PhaseChaitin::bias_color(LRG& lrg) {
       // CNC - Fun hack.  Alternate 1st and 2nd selection.  Enables post-allocate
       // copy removal to remove many more copies, by preventing a just-assigned
       // register from being repeatedly assigned.
    -  OptoReg::Name reg = lrg.mask().find_first_elem();
    +  reg = lrg.mask().find_first_elem();
       if( (++_alternate & 1) && OptoReg::is_valid(reg) ) {
         // This 'Remove; find; Insert' idiom is an expensive way to find the
         // SECOND element in the mask.
    @@ -1640,6 +1684,27 @@ uint PhaseChaitin::Select( ) {
             }
           }
         }
    +
    +    Node* def = lrg->_def;
    +    if (lrg->is_singledef() && !lrg->_is_bound && def->is_Mach()) {
    +      MachNode* mdef = def->as_Mach();
    +      if (Matcher::is_register_biasing_candidate(mdef, 1)) {
    +        Node* in1 = mdef->in(mdef->operand_index(1));
    +        if (in1 != nullptr && lrg->_copy_bias == 0) {
    +          lrg->_copy_bias = _lrg_map.find(in1);
    +        }
    +      }
    +
    +      // For commutative operations, def allocation can also be
    +      // biased towards LRG of second input's def.
    +      if (Matcher::is_register_biasing_candidate(mdef, 2)) {
    +        Node* in2 = mdef->in(mdef->operand_index(2));
    +        if (in2 != nullptr && lrg->_copy_bias2 == 0) {
    +          lrg->_copy_bias2 = _lrg_map.find(in2);
    +        }
    +      }
    +    }
    +
         //assert(is_infinite_stack == lrg->mask().is_infinite_stack(), "nbrs must not change InfiniteStackedness");
         // Aligned pairs need aligned masks
         assert(!lrg->_is_vector || !lrg->_fat_proj, "sanity");
    diff --git a/src/hotspot/share/opto/chaitin.hpp b/src/hotspot/share/opto/chaitin.hpp
    index b477c54fcae..ac072e94e2b 100644
    --- a/src/hotspot/share/opto/chaitin.hpp
    +++ b/src/hotspot/share/opto/chaitin.hpp
    @@ -63,6 +63,7 @@ public:
     
       uint _risk_bias;              // Index of LRG which we want to avoid color
       uint _copy_bias;              // Index of LRG which we want to share color
    +  uint _copy_bias2;             // Index of second LRG which we want to share color
     
       uint _next;                   // Index of next LRG in linked list
       uint _prev;                   // Index of prev LRG in linked list
    @@ -703,6 +704,8 @@ private:
       OptoReg::Name choose_color(LRG& lrg);
       // Helper function which implements biasing heuristic
       OptoReg::Name bias_color(LRG& lrg);
    +  // Helper function which implements color biasing
    +  OptoReg::Name select_bias_lrg_color(LRG& lrg);
     
       // Split uncolorable live ranges
       // Return new number of live ranges
    diff --git a/src/hotspot/share/opto/idealGraphPrinter.cpp b/src/hotspot/share/opto/idealGraphPrinter.cpp
    index b28949e27c2..5070a9f00e1 100644
    --- a/src/hotspot/share/opto/idealGraphPrinter.cpp
    +++ b/src/hotspot/share/opto/idealGraphPrinter.cpp
    @@ -88,6 +88,7 @@ void PrintProperties::print_lrg_properties(const LRG &lrg, const char *buffer) {
       print_property(true, "score", lrg.score());
       print_property((lrg._risk_bias != 0), "risk_bias", lrg._risk_bias);
       print_property((lrg._copy_bias != 0), "copy_bias", lrg._copy_bias);
    +  print_property((lrg._copy_bias2 != 0), "copy_bias2", lrg._copy_bias2);
       print_property(lrg.is_singledef(), "is_singledef");
       print_property(lrg.is_multidef(), "is_multidef");
       print_property(lrg._is_oop, "is_oop");
    diff --git a/src/hotspot/share/opto/machnode.cpp b/src/hotspot/share/opto/machnode.cpp
    index e58befd8032..ec861865ff5 100644
    --- a/src/hotspot/share/opto/machnode.cpp
    +++ b/src/hotspot/share/opto/machnode.cpp
    @@ -460,6 +460,13 @@ int MachNode::operand_index(Node* def) const {
       return -1;
     }
     
    +int MachNode::operand_num_edges(uint oper_index) const {
    +  if (num_opnds() > oper_index) {
    +    return _opnds[oper_index]->num_edges();
    +  }
    +  return 0;
    +}
    +
     //------------------------------peephole---------------------------------------
     // Apply peephole rule(s) to this instruction
     int MachNode::peephole(Block *block, int block_index, PhaseCFG* cfg_, PhaseRegAlloc *ra_) {
    diff --git a/src/hotspot/share/opto/machnode.hpp b/src/hotspot/share/opto/machnode.hpp
    index 093f466678c..b60313b7f75 100644
    --- a/src/hotspot/share/opto/machnode.hpp
    +++ b/src/hotspot/share/opto/machnode.hpp
    @@ -266,6 +266,7 @@ public:
       int  operand_index(uint operand) const;
       int  operand_index(const MachOper *oper) const;
       int  operand_index(Node* m) const;
    +  int  operand_num_edges(uint operand) const;
     
       // Register class input is expected in
       virtual const RegMask &in_RegMask(uint) const;
    diff --git a/src/hotspot/share/opto/matcher.hpp b/src/hotspot/share/opto/matcher.hpp
    index 01f11b1fdc9..ca13d0166a1 100644
    --- a/src/hotspot/share/opto/matcher.hpp
    +++ b/src/hotspot/share/opto/matcher.hpp
    @@ -512,6 +512,8 @@ public:
       DEBUG_ONLY( bool verify_after_postselect_cleanup(); )
     
      public:
    +  static bool is_register_biasing_candidate(const MachNode* mdef, int oper_index);
    +
       // This routine is run whenever a graph fails to match.
       // If it returns, the compiler should bailout to interpreter without error.
       // In non-product mode, SoftMatchFailure is false to detect non-canonical
    diff --git a/src/hotspot/share/opto/node.hpp b/src/hotspot/share/opto/node.hpp
    index ec80fb6a0ab..2e19d1d247b 100644
    --- a/src/hotspot/share/opto/node.hpp
    +++ b/src/hotspot/share/opto/node.hpp
    @@ -828,26 +828,26 @@ public:
       #undef DEFINE_CLASS_ID
     
       // Flags are sorted by usage frequency.
    -  enum NodeFlags {
    -    Flag_is_Copy                     = 1 << 0, // should be first bit to avoid shift
    -    Flag_rematerialize               = 1 << 1,
    -    Flag_needs_anti_dependence_check = 1 << 2,
    -    Flag_is_macro                    = 1 << 3,
    -    Flag_is_Con                      = 1 << 4,
    -    Flag_is_cisc_alternate           = 1 << 5,
    -    Flag_is_dead_loop_safe           = 1 << 6,
    -    Flag_may_be_short_branch         = 1 << 7,
    -    Flag_avoid_back_to_back_before   = 1 << 8,
    -    Flag_avoid_back_to_back_after    = 1 << 9,
    -    Flag_has_call                    = 1 << 10,
    -    Flag_has_swapped_edges           = 1 << 11,
    -    Flag_is_scheduled                = 1 << 12,
    -    Flag_is_expensive                = 1 << 13,
    -    Flag_is_predicated_vector        = 1 << 14,
    -    Flag_for_post_loop_opts_igvn     = 1 << 15,
    -    Flag_for_merge_stores_igvn       = 1 << 16,
    -    Flag_is_removed_by_peephole      = 1 << 17,
    -    Flag_is_predicated_using_blend   = 1 << 18,
    +  enum NodeFlags : uint64_t {
    +    Flag_is_Copy                     = 1ULL << 0, // should be first bit to avoid shift
    +    Flag_rematerialize               = 1ULL << 1,
    +    Flag_needs_anti_dependence_check = 1ULL << 2,
    +    Flag_is_macro                    = 1ULL << 3,
    +    Flag_is_Con                      = 1ULL << 4,
    +    Flag_is_cisc_alternate           = 1ULL << 5,
    +    Flag_is_dead_loop_safe           = 1ULL << 6,
    +    Flag_may_be_short_branch         = 1ULL << 7,
    +    Flag_avoid_back_to_back_before   = 1ULL << 8,
    +    Flag_avoid_back_to_back_after    = 1ULL << 9,
    +    Flag_has_call                    = 1ULL << 10,
    +    Flag_has_swapped_edges           = 1ULL << 11,
    +    Flag_is_scheduled                = 1ULL << 12,
    +    Flag_is_expensive                = 1ULL << 13,
    +    Flag_is_predicated_vector        = 1ULL << 14,
    +    Flag_for_post_loop_opts_igvn     = 1ULL << 15,
    +    Flag_for_merge_stores_igvn       = 1ULL << 16,
    +    Flag_is_removed_by_peephole      = 1ULL << 17,
    +    Flag_is_predicated_using_blend   = 1ULL << 18,
         _last_flag                       = Flag_is_predicated_using_blend
       };
     
    
    From 81b26ba8131b74a7bb4309bd3608dda2ba99a6ca Mon Sep 17 00:00:00 2001
    From: Emanuel Peter 
    Date: Mon, 1 Dec 2025 06:42:53 +0000
    Subject: [PATCH 061/706] 8372685: C2 SuperWord: wrong requires in test after
     JDK-8371146
    
    Reviewed-by: chagedorn, mbaesken
    ---
     .../superword/TestAliasingCheckPreLimitNotAvailable.java      | 4 ++--
     1 file changed, 2 insertions(+), 2 deletions(-)
    
    diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestAliasingCheckPreLimitNotAvailable.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestAliasingCheckPreLimitNotAvailable.java
    index e7009e87ae2..e86d6ec2314 100644
    --- a/test/hotspot/jtreg/compiler/loopopts/superword/TestAliasingCheckPreLimitNotAvailable.java
    +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestAliasingCheckPreLimitNotAvailable.java
    @@ -27,7 +27,7 @@
      * @summary Test where the pre_init was pinned before the pre-loop but after the
      *          Auto_Vectorization_Check, and so it should not be used for the auto
      *          vectorization aliasing check, to avoid a bad (circular) graph.
    - * @requires vm.gc == "ZGC" | vm.gc == "null"
    + * @requires vm.gc.Z
      * @run main/othervm
      *      -XX:+IgnoreUnrecognizedVMOptions
      *      -XX:CompileCommand=compileonly,*TestAliasingCheckPreLimitNotAvailable::test
    @@ -42,7 +42,7 @@
     /*
      * @test id=all-flags-no-stress-seed
      * @bug 8371146
    - * @requires vm.gc == "ZGC" | vm.gc == "null"
    + * @requires vm.gc.Z
      * @run main/othervm
      *      -XX:+IgnoreUnrecognizedVMOptions
      *      -XX:CompileCommand=compileonly,*TestAliasingCheckPreLimitNotAvailable::test
    
    From ca96366c03b89fa90a015e6c2d5912a9f2554c92 Mon Sep 17 00:00:00 2001
    From: Axel Boldt-Christmas 
    Date: Mon, 1 Dec 2025 06:51:03 +0000
    Subject: [PATCH 062/706] 8372528: Unify atomic exchange and compare exchange
    
    Reviewed-by: kbarrett, stefank
    ---
     src/hotspot/cpu/ppc/atomicAccess_ppc.hpp      |   3 +
     .../bsd_aarch64/atomicAccess_bsd_aarch64.hpp  |   4 +
     .../os_cpu/bsd_x86/atomicAccess_bsd_x86.hpp   |   3 +
     .../os_cpu/bsd_zero/atomicAccess_bsd_zero.hpp |   3 +
     .../atomicAccess_linux_aarch64.hpp            |   3 +
     .../linux_arm/atomicAccess_linux_arm.hpp      |   2 +
     .../linux_riscv/atomicAccess_linux_riscv.hpp  |   4 +
     .../linux_s390/atomicAccess_linux_s390.hpp    |   3 +
     .../linux_x86/atomicAccess_linux_x86.hpp      |   3 +
     .../linux_zero/atomicAccess_linux_zero.hpp    |   3 +
     .../atomicAccess_windows_aarch64.hpp          |   5 +
     .../windows_x86/atomicAccess_windows_x86.hpp  |   5 +
     src/hotspot/share/runtime/atomic.hpp          |  86 +----------
     src/hotspot/share/runtime/atomicAccess.hpp    |   4 +-
     test/hotspot/gtest/runtime/test_atomic.cpp    | 145 ++++++++++--------
     .../gtest/runtime/test_atomicAccess.cpp       |   8 +-
     16 files changed, 137 insertions(+), 147 deletions(-)
    
    diff --git a/src/hotspot/cpu/ppc/atomicAccess_ppc.hpp b/src/hotspot/cpu/ppc/atomicAccess_ppc.hpp
    index a0ff19e6171..c4529b0eb1a 100644
    --- a/src/hotspot/cpu/ppc/atomicAccess_ppc.hpp
    +++ b/src/hotspot/cpu/ppc/atomicAccess_ppc.hpp
    @@ -157,6 +157,9 @@ inline D AtomicAccess::PlatformAdd<8>::add_then_fetch(D volatile* dest, I add_va
       return result;
     }
     
    +template<>
    +struct AtomicAccess::PlatformXchg<1> : AtomicAccess::XchgUsingCmpxchg<1> {};
    +
     template<>
     template
     inline T AtomicAccess::PlatformXchg<4>::operator()(T volatile* dest,
    diff --git a/src/hotspot/os_cpu/bsd_aarch64/atomicAccess_bsd_aarch64.hpp b/src/hotspot/os_cpu/bsd_aarch64/atomicAccess_bsd_aarch64.hpp
    index 3d2c632ace8..67701775f94 100644
    --- a/src/hotspot/os_cpu/bsd_aarch64/atomicAccess_bsd_aarch64.hpp
    +++ b/src/hotspot/os_cpu/bsd_aarch64/atomicAccess_bsd_aarch64.hpp
    @@ -52,12 +52,16 @@ struct AtomicAccess::PlatformAdd {
       }
     };
     
    +template<>
    +struct AtomicAccess::PlatformXchg<1> : AtomicAccess::XchgUsingCmpxchg<1> {};
    +
     template
     template
     inline T AtomicAccess::PlatformXchg::operator()(T volatile* dest,
                                                                T exchange_value,
                                                                atomic_memory_order order) const {
       STATIC_ASSERT(byte_size == sizeof(T));
    +  STATIC_ASSERT(byte_size == 4 || byte_size == 8);
       T res = __atomic_exchange_n(dest, exchange_value, __ATOMIC_RELEASE);
       FULL_MEM_BARRIER;
       return res;
    diff --git a/src/hotspot/os_cpu/bsd_x86/atomicAccess_bsd_x86.hpp b/src/hotspot/os_cpu/bsd_x86/atomicAccess_bsd_x86.hpp
    index 1024c6b1418..29471300f3d 100644
    --- a/src/hotspot/os_cpu/bsd_x86/atomicAccess_bsd_x86.hpp
    +++ b/src/hotspot/os_cpu/bsd_x86/atomicAccess_bsd_x86.hpp
    @@ -52,6 +52,9 @@ inline D AtomicAccess::PlatformAdd<4>::fetch_then_add(D volatile* dest, I add_va
       return old_value;
     }
     
    +template<>
    +struct AtomicAccess::PlatformXchg<1> : AtomicAccess::XchgUsingCmpxchg<1> {};
    +
     template<>
     template
     inline T AtomicAccess::PlatformXchg<4>::operator()(T volatile* dest,
    diff --git a/src/hotspot/os_cpu/bsd_zero/atomicAccess_bsd_zero.hpp b/src/hotspot/os_cpu/bsd_zero/atomicAccess_bsd_zero.hpp
    index 6a720dac54e..6c8684718fc 100644
    --- a/src/hotspot/os_cpu/bsd_zero/atomicAccess_bsd_zero.hpp
    +++ b/src/hotspot/os_cpu/bsd_zero/atomicAccess_bsd_zero.hpp
    @@ -66,6 +66,9 @@ inline D AtomicAccess::PlatformAdd<8>::add_then_fetch(D volatile* dest, I add_va
       return res;
     }
     
    +template<>
    +struct AtomicAccess::PlatformXchg<1> : AtomicAccess::XchgUsingCmpxchg<1> {};
    +
     template<>
     template
     inline T AtomicAccess::PlatformXchg<4>::operator()(T volatile* dest,
    diff --git a/src/hotspot/os_cpu/linux_aarch64/atomicAccess_linux_aarch64.hpp b/src/hotspot/os_cpu/linux_aarch64/atomicAccess_linux_aarch64.hpp
    index 6e5f53edfa3..4ddb2b758b4 100644
    --- a/src/hotspot/os_cpu/linux_aarch64/atomicAccess_linux_aarch64.hpp
    +++ b/src/hotspot/os_cpu/linux_aarch64/atomicAccess_linux_aarch64.hpp
    @@ -113,6 +113,9 @@ inline D AtomicAccess::PlatformAdd<8>::fetch_then_add(D volatile* dest, I add_va
       return atomic_fastcall(stub, dest, add_value);
     }
     
    +template<>
    +struct AtomicAccess::PlatformXchg<1> : AtomicAccess::XchgUsingCmpxchg<1> {};
    +
     template<>
     template
     inline T AtomicAccess::PlatformXchg<4>::operator()(T volatile* dest,
    diff --git a/src/hotspot/os_cpu/linux_arm/atomicAccess_linux_arm.hpp b/src/hotspot/os_cpu/linux_arm/atomicAccess_linux_arm.hpp
    index 5b5f9da51a6..390207f9e5e 100644
    --- a/src/hotspot/os_cpu/linux_arm/atomicAccess_linux_arm.hpp
    +++ b/src/hotspot/os_cpu/linux_arm/atomicAccess_linux_arm.hpp
    @@ -118,6 +118,8 @@ inline D AtomicAccess::PlatformAdd<4>::add_then_fetch(D volatile* dest, I add_va
       return add_using_helper(ARMAtomicFuncs::_add_func, dest, add_value);
     }
     
    +template<>
    +struct AtomicAccess::PlatformXchg<1> : AtomicAccess::XchgUsingCmpxchg<1> {};
     
     template<>
     template
    diff --git a/src/hotspot/os_cpu/linux_riscv/atomicAccess_linux_riscv.hpp b/src/hotspot/os_cpu/linux_riscv/atomicAccess_linux_riscv.hpp
    index 6d57ea55a83..bdbc0b8ac7f 100644
    --- a/src/hotspot/os_cpu/linux_riscv/atomicAccess_linux_riscv.hpp
    +++ b/src/hotspot/os_cpu/linux_riscv/atomicAccess_linux_riscv.hpp
    @@ -152,6 +152,9 @@ inline T AtomicAccess::PlatformCmpxchg<4>::operator()(T volatile* dest __attribu
     }
     #endif
     
    +template<>
    +struct AtomicAccess::PlatformXchg<1> : AtomicAccess::XchgUsingCmpxchg<1> {};
    +
     template
     template
     inline T AtomicAccess::PlatformXchg::operator()(T volatile* dest,
    @@ -164,6 +167,7 @@ inline T AtomicAccess::PlatformXchg::operator()(T volatile* dest,
     #endif
     
       STATIC_ASSERT(byte_size == sizeof(T));
    +  STATIC_ASSERT(byte_size == 4 || byte_size == 8);
     
       if (order != memory_order_relaxed) {
         FULL_MEM_BARRIER;
    diff --git a/src/hotspot/os_cpu/linux_s390/atomicAccess_linux_s390.hpp b/src/hotspot/os_cpu/linux_s390/atomicAccess_linux_s390.hpp
    index 5849d69ae2f..f3c1e8f1a2c 100644
    --- a/src/hotspot/os_cpu/linux_s390/atomicAccess_linux_s390.hpp
    +++ b/src/hotspot/os_cpu/linux_s390/atomicAccess_linux_s390.hpp
    @@ -209,6 +209,9 @@ inline D AtomicAccess::PlatformAdd<8>::add_then_fetch(D volatile* dest, I inc,
     //
     // The return value is the (unchanged) value from memory as it was when the
     // replacement succeeded.
    +template<>
    +struct AtomicAccess::PlatformXchg<1> : AtomicAccess::XchgUsingCmpxchg<1> {};
    +
     template<>
     template
     inline T AtomicAccess::PlatformXchg<4>::operator()(T volatile* dest,
    diff --git a/src/hotspot/os_cpu/linux_x86/atomicAccess_linux_x86.hpp b/src/hotspot/os_cpu/linux_x86/atomicAccess_linux_x86.hpp
    index dd91444d0a3..6b43b5e8e09 100644
    --- a/src/hotspot/os_cpu/linux_x86/atomicAccess_linux_x86.hpp
    +++ b/src/hotspot/os_cpu/linux_x86/atomicAccess_linux_x86.hpp
    @@ -52,6 +52,9 @@ inline D AtomicAccess::PlatformAdd<4>::fetch_then_add(D volatile* dest, I add_va
       return old_value;
     }
     
    +template<>
    +struct AtomicAccess::PlatformXchg<1> : AtomicAccess::XchgUsingCmpxchg<1> {};
    +
     template<>
     template
     inline T AtomicAccess::PlatformXchg<4>::operator()(T volatile* dest,
    diff --git a/src/hotspot/os_cpu/linux_zero/atomicAccess_linux_zero.hpp b/src/hotspot/os_cpu/linux_zero/atomicAccess_linux_zero.hpp
    index 376ef7a9dc9..96c46c6f59a 100644
    --- a/src/hotspot/os_cpu/linux_zero/atomicAccess_linux_zero.hpp
    +++ b/src/hotspot/os_cpu/linux_zero/atomicAccess_linux_zero.hpp
    @@ -65,6 +65,9 @@ inline D AtomicAccess::PlatformAdd<8>::add_then_fetch(D volatile* dest, I add_va
       return res;
     }
     
    +template<>
    +struct AtomicAccess::PlatformXchg<1> : AtomicAccess::XchgUsingCmpxchg<1> {};
    +
     template<>
     template
     inline T AtomicAccess::PlatformXchg<4>::operator()(T volatile* dest,
    diff --git a/src/hotspot/os_cpu/windows_aarch64/atomicAccess_windows_aarch64.hpp b/src/hotspot/os_cpu/windows_aarch64/atomicAccess_windows_aarch64.hpp
    index 62b6e3f87ec..f8119654c50 100644
    --- a/src/hotspot/os_cpu/windows_aarch64/atomicAccess_windows_aarch64.hpp
    +++ b/src/hotspot/os_cpu/windows_aarch64/atomicAccess_windows_aarch64.hpp
    @@ -68,6 +68,9 @@ DEFINE_INTRINSIC_ADD(InterlockedAdd64, __int64)
     
     #undef DEFINE_INTRINSIC_ADD
     
    +template<>
    +struct AtomicAccess::PlatformXchg<1> : AtomicAccess::XchgUsingCmpxchg<1> {};
    +
     #define DEFINE_INTRINSIC_XCHG(IntrinsicName, IntrinsicType)               \
       template<>                                                              \
       template                                                    \
    @@ -75,6 +78,8 @@ DEFINE_INTRINSIC_ADD(InterlockedAdd64, __int64)
                                                                              T exchange_value, \
                                                                              atomic_memory_order order) const { \
         STATIC_ASSERT(sizeof(IntrinsicType) == sizeof(T));                    \
    +    STATIC_ASSERT(sizeof(IntrinsicType) == 4 ||                           \
    +                  sizeof(IntrinsicType) == 8);                            \
         return PrimitiveConversions::cast(                                 \
           IntrinsicName(reinterpret_cast(dest),     \
                         PrimitiveConversions::cast(exchange_value))); \
    diff --git a/src/hotspot/os_cpu/windows_x86/atomicAccess_windows_x86.hpp b/src/hotspot/os_cpu/windows_x86/atomicAccess_windows_x86.hpp
    index a95da151688..aa78a401235 100644
    --- a/src/hotspot/os_cpu/windows_x86/atomicAccess_windows_x86.hpp
    +++ b/src/hotspot/os_cpu/windows_x86/atomicAccess_windows_x86.hpp
    @@ -70,6 +70,9 @@ DEFINE_INTRINSIC_ADD(InterlockedAdd64, __int64)
     
     #undef DEFINE_INTRINSIC_ADD
     
    +template<>
    +struct AtomicAccess::PlatformXchg<1> : AtomicAccess::XchgUsingCmpxchg<1> {};
    +
     #define DEFINE_INTRINSIC_XCHG(IntrinsicName, IntrinsicType)               \
       template<>                                                              \
       template                                                    \
    @@ -77,6 +80,8 @@ DEFINE_INTRINSIC_ADD(InterlockedAdd64, __int64)
                                                                              T exchange_value, \
                                                                              atomic_memory_order order) const { \
         STATIC_ASSERT(sizeof(IntrinsicType) == sizeof(T));                    \
    +    STATIC_ASSERT(sizeof(IntrinsicType) == 4 ||                           \
    +                  sizeof(IntrinsicType) == 8);                            \
         return PrimitiveConversions::cast(                                 \
           IntrinsicName(reinterpret_cast(dest),     \
                         PrimitiveConversions::cast(exchange_value))); \
    diff --git a/src/hotspot/share/runtime/atomic.hpp b/src/hotspot/share/runtime/atomic.hpp
    index 5b4d7d8659f..b8960fd796b 100644
    --- a/src/hotspot/share/runtime/atomic.hpp
    +++ b/src/hotspot/share/runtime/atomic.hpp
    @@ -75,6 +75,7 @@
     //     v.release_store(x) -> void
     //     v.release_store_fence(x) -> void
     //     v.compare_exchange(x, y [, o]) -> T
    +//     v.exchange(x [, o]) -> T
     //
     // (2) All atomic types are default constructible.
     //
    @@ -92,7 +93,6 @@
     // (3) Atomic pointers and atomic integers additionally provide
     //
     //   member functions:
    -//     v.exchange(x [, o]) -> T
     //     v.add_then_fetch(i [, o]) -> T
     //     v.sub_then_fetch(i [, o]) -> T
     //     v.fetch_then_add(i [, o]) -> T
    @@ -102,10 +102,7 @@
     // type of i must be signed, or both must be unsigned. Atomic pointers perform
     // element arithmetic.
     //
    -// (4) An atomic translated type additionally provides the exchange
    -// function if its associated atomic decayed type provides that function.
    -//
    -// (5) Atomic integers additionally provide
    +// (4) Atomic integers additionally provide
     //
     //   member functions:
     //     v.and_then_fetch(x [, o]) -> T
    @@ -115,7 +112,7 @@
     //     v.fetch_then_or(x [, o]) -> T
     //     v.fetch_then_xor(x [, o]) -> T
     //
    -// (6) Atomic pointers additionally provide
    +// (5) Atomic pointers additionally provide
     //
     //   nested types:
     //     ElementType -> std::remove_pointer_t
    @@ -127,9 +124,6 @@
     // stand out a little more when used in surrounding non-atomic code. Without
     // the "AtomicAccess::" qualifier, some of those names are easily overlooked.
     //
    -// Atomic bytes don't provide exchange(). This is because that operation
    -// hasn't been implemented for 1 byte values. That could be changed if needed.
    -//
     // Atomic for 2 byte integers is not supported. This is because atomic
     // operations of that size have not been implemented. There haven't been
     // required use-cases. Many platforms don't provide hardware support.
    @@ -184,15 +178,8 @@ private:
     
       // Helper base classes, providing various parts of the APIs.
       template class CommonCore;
    -  template class SupportsExchange;
       template class SupportsArithmetic;
     
    -  // Support conditional exchange() for atomic translated types.
    -  template class HasExchange;
    -  template class DecayedHasExchange;
    -  template::value>
    -  class TranslatedExchange;
    -
     public:
       template()>
       class Atomic;
    @@ -275,15 +262,7 @@ public:
                          atomic_memory_order order = memory_order_conservative) {
         return AtomicAccess::cmpxchg(value_ptr(), compare_value, new_value, order);
       }
    -};
     
    -template
    -class AtomicImpl::SupportsExchange : public CommonCore {
    -protected:
    -  explicit SupportsExchange(T value) : CommonCore(value) {}
    -  ~SupportsExchange() = default;
    -
    -public:
       T exchange(T new_value,
                  atomic_memory_order order = memory_order_conservative) {
         return AtomicAccess::xchg(this->value_ptr(), new_value, order);
    @@ -291,7 +270,7 @@ public:
     };
     
     template
    -class AtomicImpl::SupportsArithmetic : public SupportsExchange {
    +class AtomicImpl::SupportsArithmetic : public CommonCore {
       // Guarding the AtomicAccess calls with constexpr checking of Offset produces
       // better compile-time error messages.
       template
    @@ -311,7 +290,7 @@ class AtomicImpl::SupportsArithmetic : public SupportsExchange {
       }
     
     protected:
    -  explicit SupportsArithmetic(T value) : SupportsExchange(value) {}
    +  explicit SupportsArithmetic(T value) : CommonCore(value) {}
       ~SupportsArithmetic() = default;
     
     public:
    @@ -424,54 +403,8 @@ public:
     
     // Atomic translated type
     
    -// Test whether Atomic has exchange().
     template
    -class AtomicImpl::HasExchange {
    -  template static void* test(decltype(&Check::exchange));
    -  template static int test(...);
    -  using test_type = decltype(test>(nullptr));
    -public:
    -  static constexpr bool value = std::is_pointer_v;
    -};
    -
    -// Test whether the atomic decayed type associated with T has exchange().
    -template
    -class AtomicImpl::DecayedHasExchange {
    -  using Translator = PrimitiveConversions::Translate;
    -  using Decayed = typename Translator::Decayed;
    -
    -  // "Unit test" HasExchange<>.
    -  static_assert(HasExchange::value);
    -  static_assert(HasExchange::value);
    -  static_assert(!HasExchange::value);
    -
    -public:
    -  static constexpr bool value = HasExchange::value;
    -};
    -
    -// Base class for atomic translated type if atomic decayed type doesn't have
    -// exchange().
    -template
    -class AtomicImpl::TranslatedExchange {};
    -
    -// Base class for atomic translated type if atomic decayed type does have
    -// exchange().
    -template
    -class AtomicImpl::TranslatedExchange {
    -public:
    -  T exchange(T new_value,
    -             atomic_memory_order order = memory_order_conservative) {
    -    return static_cast(this)->exchange_impl(new_value, order);
    -  }
    -};
    -
    -template
    -class AtomicImpl::Atomic
    -  : public TranslatedExchange, T>
    -{
    -  // Give TranslatedExchange<> access to exchange_impl() if needed.
    -  friend class TranslatedExchange, T>;
    -
    +class AtomicImpl::Atomic {
       using Translator = PrimitiveConversions::Translate;
       using Decayed = typename Translator::Decayed;
     
    @@ -533,12 +466,7 @@ public:
                                                order));
       }
     
    -private:
    -  // Implementation of exchange() if needed.
    -  // Exclude when not needed, to prevent reference to non-existent function
    -  // of atomic decayed type if someone explicitly instantiates Atomic.
    -  template::value)>
    -  T exchange_impl(T new_value, atomic_memory_order order) {
    +  T exchange(T new_value, atomic_memory_order order = memory_order_conservative) {
         return recover(_value.exchange(decay(new_value), order));
       }
     };
    diff --git a/src/hotspot/share/runtime/atomicAccess.hpp b/src/hotspot/share/runtime/atomicAccess.hpp
    index 72b7f92cf04..fb06f084366 100644
    --- a/src/hotspot/share/runtime/atomicAccess.hpp
    +++ b/src/hotspot/share/runtime/atomicAccess.hpp
    @@ -419,8 +419,8 @@ private:
       struct XchgImpl;
     
       // Platform-specific implementation of xchg.  Support for sizes
    -  // of 4, and sizeof(intptr_t) are required.  The class is a function
    -  // object that must be default constructable, with these requirements:
    +  // of 1, 4, and 8 are required.  The class is a function object
    +  // that must be default constructable, with these requirements:
       //
       // - dest is of type T*.
       // - exchange_value is of type T.
    diff --git a/test/hotspot/gtest/runtime/test_atomic.cpp b/test/hotspot/gtest/runtime/test_atomic.cpp
    index dc492e523d1..b37c14d41a7 100644
    --- a/test/hotspot/gtest/runtime/test_atomic.cpp
    +++ b/test/hotspot/gtest/runtime/test_atomic.cpp
    @@ -101,10 +101,10 @@ TEST_VM(AtomicIntegerTest, arith_uint64) {
     }
     
     template
    -struct AtomicIntegerXchgTestSupport {
    +struct AtomicByteAndIntegerXchgTestSupport {
       Atomic _test_value;
     
    -  AtomicIntegerXchgTestSupport() : _test_value{} {}
    +  AtomicByteAndIntegerXchgTestSupport() : _test_value{} {}
     
       void test() {
         T zero = 0;
    @@ -116,13 +116,18 @@ struct AtomicIntegerXchgTestSupport {
       }
     };
     
    +TEST_VM(AtomicIntegerTest, xchg_char) {
    +  using Support = AtomicByteAndIntegerXchgTestSupport;
    +  Support().test();
    +}
    +
     TEST_VM(AtomicIntegerTest, xchg_int32) {
    -  using Support = AtomicIntegerXchgTestSupport;
    +  using Support = AtomicByteAndIntegerXchgTestSupport;
       Support().test();
     }
     
     TEST_VM(AtomicIntegerTest, xchg_int64) {
    -  using Support = AtomicIntegerXchgTestSupport;
    +  using Support = AtomicByteAndIntegerXchgTestSupport;
       Support().test();
     }
     
    @@ -153,18 +158,16 @@ TEST_VM(AtomicIntegerTest, cmpxchg_int32) {
     
     TEST_VM(AtomicIntegerTest, cmpxchg_int64) {
       // Check if 64-bit atomics are available on the machine.
    -  if (!VM_Version::supports_cx8()) return;
    -
       using Support = AtomicIntegerCmpxchgTestSupport;
       Support().test();
     }
     
    -struct AtomicCmpxchg1ByteStressSupport {
    +struct AtomicXchgAndCmpxchg1ByteStressSupport {
       char _default_val;
       int  _base;
       Atomic _array[7+32+7];
     
    -  AtomicCmpxchg1ByteStressSupport() : _default_val(0x7a), _base(7) {}
    +  AtomicXchgAndCmpxchg1ByteStressSupport() : _default_val(0x7a), _base(7) {}
     
       void validate(char val, char val2, int index) {
         for (int i = 0; i < 7; i++) {
    @@ -182,35 +185,60 @@ struct AtomicCmpxchg1ByteStressSupport {
         }
       }
     
    +  template 
       void test_index(int index) {
    +    Exchange exchange;
         char one = 1;
    -    _array[index].compare_exchange(_default_val, one);
    +    exchange(_array[index], _default_val, one);
         validate(_default_val, one, index);
     
    -    _array[index].compare_exchange(one, _default_val);
    +    exchange(_array[index], one, _default_val);
         validate(_default_val, _default_val, index);
       }
     
    +  template 
       void test() {
         for (size_t i = 0; i < ARRAY_SIZE(_array); ++i) {
           _array[i].store_relaxed(_default_val);
         }
         for (int i = _base; i < (_base+32); i++) {
    -      test_index(i);
    +      test_index(i);
         }
       }
    +  void test_exchange() {
    +    struct StressWithExchange {
    +      void operator()(Atomic& atomic, char compare_value, char new_value) {
    +        EXPECT_EQ(compare_value, atomic.exchange(new_value));
    +      }
    +    };
    +    test();
    +  }
    +
    +  void test_compare_exchange() {
    +    struct StressWithCompareExchange {
    +      void operator()(Atomic& atomic, char compare_value, char new_value) {
    +        EXPECT_EQ(compare_value, atomic.compare_exchange(compare_value, new_value));
    +      }
    +    };
    +    test();
    +  }
     };
     
    -TEST_VM(AtomicCmpxchg1Byte, stress) {
    -  AtomicCmpxchg1ByteStressSupport support;
    -  support.test();
    +TEST_VM(AtomicByteTest, stress_xchg) {
    +  AtomicXchgAndCmpxchg1ByteStressSupport support;
    +  support.test_exchange();
    +}
    +
    +TEST_VM(AtomicByteTest, stress_cmpxchg) {
    +  AtomicXchgAndCmpxchg1ByteStressSupport support;
    +  support.test_compare_exchange();
     }
     
     template
    -struct AtomicEnumTestSupport {
    +struct AtomicTestSupport {
       Atomic _test_value;
     
    -  AtomicEnumTestSupport() : _test_value{} {}
    +  AtomicTestSupport() : _test_value{} {}
     
       void test_store_load(T value) {
         EXPECT_NE(value, _test_value.load_relaxed());
    @@ -233,6 +261,13 @@ struct AtomicEnumTestSupport {
         EXPECT_EQ(value1, _test_value.exchange(value2));
         EXPECT_EQ(value2, _test_value.load_relaxed());
       }
    +
    +  template 
    +  static void test() {
    +    AtomicTestSupport().test_store_load(B);
    +    AtomicTestSupport().test_cmpxchg(B, C);
    +    AtomicTestSupport().test_xchg(B, C);
    +  }
     };
     
     namespace AtomicEnumTestUnscoped {       // Scope the enumerators.
    @@ -241,11 +276,7 @@ namespace AtomicEnumTestUnscoped {       // Scope the enumerators.
     
     TEST_VM(AtomicEnumTest, unscoped_enum) {
       using namespace AtomicEnumTestUnscoped;
    -  using Support = AtomicEnumTestSupport;
    -
    -  Support().test_store_load(B);
    -  Support().test_cmpxchg(B, C);
    -  Support().test_xchg(B, C);
    +  AtomicTestSupport::test();
     }
     
     enum class AtomicEnumTestScoped { A, B, C };
    @@ -253,11 +284,35 @@ enum class AtomicEnumTestScoped { A, B, C };
     TEST_VM(AtomicEnumTest, scoped_enum) {
       const AtomicEnumTestScoped B = AtomicEnumTestScoped::B;
       const AtomicEnumTestScoped C = AtomicEnumTestScoped::C;
    -  using Support = AtomicEnumTestSupport;
    +  AtomicTestSupport::test();
    +}
     
    -  Support().test_store_load(B);
    -  Support().test_cmpxchg(B, C);
    -  Support().test_xchg(B, C);
    +enum class AtomicEnumTestScoped64Bit : uint64_t { A, B, C };
    +
    +TEST_VM(AtomicEnumTest, scoped_enum_64_bit) {
    +  const AtomicEnumTestScoped64Bit B = AtomicEnumTestScoped64Bit::B;
    +  const AtomicEnumTestScoped64Bit C = AtomicEnumTestScoped64Bit::C;
    +  AtomicTestSupport::test();
    +}
    +
    +enum class AtomicEnumTestScoped8Bit : uint8_t { A, B, C };
    +
    +TEST_VM(AtomicEnumTest, scoped_enum_8_bit) {
    +  const AtomicEnumTestScoped8Bit B = AtomicEnumTestScoped8Bit::B;
    +  const AtomicEnumTestScoped8Bit C = AtomicEnumTestScoped8Bit::C;
    +  AtomicTestSupport::test();
    +}
    +
    +TEST_VM(AtomicByteTest, char_test) {
    +  const char B = 0xB;
    +  const char C = 0xC;
    +  AtomicTestSupport::test();
    +}
    +
    +TEST_VM(AtomicByteTest, bool_test) {
    +  const bool B = true;
    +  const bool C = false;
    +  AtomicTestSupport::test();
     }
     
     template
    @@ -514,40 +569,6 @@ struct PrimitiveConversions::Translate
       static Value recover(Decayed x) { return Value(x); }
     };
     
    -// Test whether Atomic has exchange().
    -// Note: This is intentionally a different implementation from what is used
    -// by the atomic translated type to decide whether to provide exchange().
    -// The intent is to make related testing non-tautological.
    -// The two implementations must agree; it's a bug if they don't.
    -template
    -class AtomicTypeHasExchange {
    -  template,
    -           typename = decltype(declval().exchange(declval()))>
    -  static char* test(int);
    -
    -  template static char test(...);
    -
    -  using test_type = decltype(test(0));
    -
    -public:
    -  static constexpr bool value = std::is_pointer_v;
    -};
    -
    -// Unit tests for AtomicTypeHasExchange.
    -static_assert(AtomicTypeHasExchange::value);
    -static_assert(AtomicTypeHasExchange::value);
    -static_assert(AtomicTypeHasExchange::value);
    -static_assert(AtomicTypeHasExchange::value);
    -static_assert(!AtomicTypeHasExchange::value);
    -
    -// Verify translated byte type *doesn't* have exchange.
    -static_assert(!AtomicTypeHasExchange::value);
    -
    -// Verify that explicit instantiation doesn't attempt to reference the
    -// non-existent exchange of the atomic decayed type.
    -template class AtomicImpl::Atomic;
    -
     template
     static void test_atomic_translated_type() {
       // This works even if T is not default constructible.
    @@ -562,10 +583,8 @@ static void test_atomic_translated_type() {
                                                                   Translated::recover(10))));
       EXPECT_EQ(10, Translated::decay(_test_value.load_relaxed()));
     
    -  if constexpr (AtomicTypeHasExchange::value) {
    -    EXPECT_EQ(10, Translated::decay(_test_value.exchange(Translated::recover(20))));
    -    EXPECT_EQ(20, Translated::decay(_test_value.load_relaxed()));
    -  }
    +  EXPECT_EQ(10, Translated::decay(_test_value.exchange(Translated::recover(20))));
    +  EXPECT_EQ(20, Translated::decay(_test_value.load_relaxed()));
     }
     
     TEST_VM(AtomicTranslatedTypeTest, int_test) {
    diff --git a/test/hotspot/gtest/runtime/test_atomicAccess.cpp b/test/hotspot/gtest/runtime/test_atomicAccess.cpp
    index 6e05f429970..a489be71b19 100644
    --- a/test/hotspot/gtest/runtime/test_atomicAccess.cpp
    +++ b/test/hotspot/gtest/runtime/test_atomicAccess.cpp
    @@ -100,6 +100,11 @@ struct AtomicAccessXchgTestSupport {
       }
     };
     
    +TEST_VM(AtomicAccessXchgTest, int8) {
    +  using Support = AtomicAccessXchgTestSupport;
    +  Support().test();
    +}
    +
     TEST_VM(AtomicAccessXchgTest, int32) {
       using Support = AtomicAccessXchgTestSupport;
       Support().test();
    @@ -136,9 +141,6 @@ TEST_VM(AtomicAccessCmpxchgTest, int32) {
     }
     
     TEST_VM(AtomicAccessCmpxchgTest, int64) {
    -  // Check if 64-bit atomics are available on the machine.
    -  if (!VM_Version::supports_cx8()) return;
    -
       using Support = AtomicAccessCmpxchgTestSupport;
       Support().test();
     }
    
    From 293fec7e28ed06f0942e94b1c21affdf6aabe9ca Mon Sep 17 00:00:00 2001
    From: Christian Hagedorn 
    Date: Mon, 1 Dec 2025 07:06:46 +0000
    Subject: [PATCH 063/706] 8372461: [IR Framework] Multiple test failures after
     JDK-8371789
    
    Reviewed-by: epeter, syan, dfenacci
    ---
     test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java | 9 ++++-----
     .../ir_framework/tests/TestIRMatching.java               | 6 +++---
     2 files changed, 7 insertions(+), 8 deletions(-)
    
    diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java
    index a730fcb30cf..787dedba9c6 100644
    --- a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java
    +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java
    @@ -523,13 +523,13 @@ public class IRNode {
     
         public static final String CHECKCAST_ARRAY = PREFIX + "CHECKCAST_ARRAY" + POSTFIX;
         static {
    -        String regex = "(((?i:cmp|CLFI|CLR).*precise \\[.*:|.*(?i:mov|mv|or).*precise \\[.*:.*\\R.*(cmp|CMP|CLR))" + END;
    +        String regex = "(((?i:cmp|CLFI|CLR).*aryklassptr:\\[.*:Constant|.*(?i:mov|mv|or).*aryklassptr:\\[.*:Constant.*\\R.*(cmp|CMP|CLR))" + END;
             optoOnly(CHECKCAST_ARRAY, regex);
         }
     
         public static final String CHECKCAST_ARRAY_OF = COMPOSITE_PREFIX + "CHECKCAST_ARRAY_OF" + POSTFIX;
         static {
    -        String regex = "(((?i:cmp|CLFI|CLR).*precise \\[.*" + IS_REPLACED + ":|.*(?i:mov|mv|or).*precise \\[.*" + IS_REPLACED + ":.*\\R.*(cmp|CMP|CLR))" + END;
    +        String regex = "(((?i:cmp|CLFI|CLR).*aryklassptr:\\[.*" + IS_REPLACED + ":.*:Constant|.*(?i:mov|mv|or).*aryklassptr:\\[.*" + IS_REPLACED + ":.*:Constant.*\\R.*(cmp|CMP|CLR))" + END;
             optoOnly(CHECKCAST_ARRAY_OF, regex);
         }
     
    @@ -3220,10 +3220,9 @@ public class IRNode {
     
         // @ matches the start character of the pattern
         // (\w+: ?)+ tries to match the pattern 'ptrtype:' or 'stable:' with optional trailing whitespaces
    -    // (\w/)* tries to match the pattern 'a/b/`
    -    // (\w$)* tries to match the pattern 'c$d$'
    +    // [\\w/\\$] tries to match the pattern such as 'a/b/', 'a/b', or '/b' but also nested class such as '$c' or '$c$d'
         // \b asserts that the next character is a word character
    -    private static final String LOAD_STORE_PREFIX = "@(\\w+: ?)+(\\w/)*(\\w$)*\\b";
    +    private static final String LOAD_STORE_PREFIX = "@(\\w+: ?)+[\\w/\\$]*\\b";
         // ( \([^\)]+\))? tries to match the pattern ' (f/g,h/i/j)'
         // :\w+ tries to match the pattern ':NotNull'
         // .* tries to match the remaining of the pattern
    diff --git a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestIRMatching.java b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestIRMatching.java
    index 5615cce983a..142a30f34a9 100644
    --- a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestIRMatching.java
    +++ b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestIRMatching.java
    @@ -255,9 +255,9 @@ public class TestIRMatching {
             } else {
                 cmp = "cmp";
             }
    -        runCheck(BadFailOnConstraint.create(CheckCastArray.class, "array(java.lang.Object[])", 1, cmp, "precise"),
    -                 BadFailOnConstraint.create(CheckCastArray.class, "array(java.lang.Object[])", 2, 1,cmp, "precise", "MyClass"),
    -                 BadFailOnConstraint.create(CheckCastArray.class, "array(java.lang.Object[])", 2, 2,cmp, "precise", "ir_framework/tests/MyClass"),
    +        runCheck(BadFailOnConstraint.create(CheckCastArray.class, "array(java.lang.Object[])", 1, cmp, "Constant"),
    +                 BadFailOnConstraint.create(CheckCastArray.class, "array(java.lang.Object[])", 2, 1,cmp, "Constant", "MyClass"),
    +                 BadFailOnConstraint.create(CheckCastArray.class, "array(java.lang.Object[])", 2, 2,cmp, "Constant", "ir_framework/tests/MyClass"),
                      GoodFailOnConstraint.create(CheckCastArray.class, "array(java.lang.Object[])", 3),
                      Platform.isS390x() ? // There is no checkcast_arraycopy stub for C2 on s390
                          GoodFailOnConstraint.create(CheckCastArray.class, "arrayCopy(java.lang.Object[],java.lang.Class)", 1)
    
    From a6bc9b3ba50c5d669213f082a32e30c9ab2f923d Mon Sep 17 00:00:00 2001
    From: Matthias Baesken 
    Date: Mon, 1 Dec 2025 07:44:54 +0000
    Subject: [PATCH 064/706] 8372588: [asan] serviceability/sa/TestJmapCore.java
     and TestJmapCoreMetaspace.java fail after recent improvements
    
    Reviewed-by: stuefe, azeller, lucy
    ---
     test/hotspot/jtreg/serviceability/sa/TestJmapCore.java          | 1 +
     test/hotspot/jtreg/serviceability/sa/TestJmapCoreMetaspace.java | 1 +
     2 files changed, 2 insertions(+)
    
    diff --git a/test/hotspot/jtreg/serviceability/sa/TestJmapCore.java b/test/hotspot/jtreg/serviceability/sa/TestJmapCore.java
    index 9119ac45cc3..9e266e67119 100644
    --- a/test/hotspot/jtreg/serviceability/sa/TestJmapCore.java
    +++ b/test/hotspot/jtreg/serviceability/sa/TestJmapCore.java
    @@ -25,6 +25,7 @@
      * @test TestJmapCore
      * @summary Test verifies that jhsdb jmap could generate heap dump from core when heap is full
      * @requires vm.hasSA
    + * @requires !vm.asan
      * @library /test/lib
      * @run driver/timeout=480 TestJmapCore run heap
      */
    diff --git a/test/hotspot/jtreg/serviceability/sa/TestJmapCoreMetaspace.java b/test/hotspot/jtreg/serviceability/sa/TestJmapCoreMetaspace.java
    index b8e00e53848..6fc04c8de74 100644
    --- a/test/hotspot/jtreg/serviceability/sa/TestJmapCoreMetaspace.java
    +++ b/test/hotspot/jtreg/serviceability/sa/TestJmapCoreMetaspace.java
    @@ -25,6 +25,7 @@
      * @test TestJmapCoreMetaspace
      * @summary Test verifies that jhsdb jmap could generate heap dump from core when metaspace is full
      * @requires vm.hasSA
    + * @requires !vm.asan
      * @library /test/lib
      * @run driver/timeout=480 TestJmapCore run metaspace
      */
    
    From 969eb1ce2419324582ee8d8108031323f82e125e Mon Sep 17 00:00:00 2001
    From: Mikhail Yankelevich 
    Date: Mon, 1 Dec 2025 07:51:39 +0000
    Subject: [PATCH 065/706] 8365861: test/jdk/sun/security/pkcs11/Provider/ tests
     skipped without SkippedException
    
    Reviewed-by: rhalade
    ---
     .../security/pkcs11/Provider/Absolute.java    |  9 +++++----
     .../pkcs11/Provider/ConfigShortPath.java      | 19 ++++++++++++-------
     .../security/pkcs11/Provider/LoginISE.java    | 19 ++++++++++++-------
     3 files changed, 29 insertions(+), 18 deletions(-)
    
    diff --git a/test/jdk/sun/security/pkcs11/Provider/Absolute.java b/test/jdk/sun/security/pkcs11/Provider/Absolute.java
    index c298c076b30..07a934030db 100644
    --- a/test/jdk/sun/security/pkcs11/Provider/Absolute.java
    +++ b/test/jdk/sun/security/pkcs11/Provider/Absolute.java
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 2011, 2025, 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,8 @@
      * @summary load DLLs and launch executables using fully qualified path
      */
     
    +import jtreg.SkippedException;
    +
     import java.security.InvalidParameterException;
     import java.security.Provider;
     
    @@ -40,12 +42,11 @@ public class Absolute {
             try {
                 Provider p = PKCS11Test.getSunPKCS11(config);
                 if (p == null) {
    -                System.out.println("Skipping test - no PKCS11 provider available");
    +                throw new SkippedException("Skipping test - no PKCS11 provider available");
                 }
             } catch (InvalidParameterException ipe) {
                 Throwable ex = ipe.getCause();
    -            if (ex.getMessage().indexOf(
    -                    "Absolute path required for library value:") != -1) {
    +            if (ex.getMessage().contains("Absolute path required for library value:")) {
                     System.out.println("Test Passed: expected exception thrown");
                 } else {
                     // rethrow
    diff --git a/test/jdk/sun/security/pkcs11/Provider/ConfigShortPath.java b/test/jdk/sun/security/pkcs11/Provider/ConfigShortPath.java
    index f229360f1af..120f289d211 100644
    --- a/test/jdk/sun/security/pkcs11/Provider/ConfigShortPath.java
    +++ b/test/jdk/sun/security/pkcs11/Provider/ConfigShortPath.java
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 2010, 2020, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 2010, 2025, 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,11 +25,17 @@
      * @bug 6581254 6986789 7196009 8062170
      * @summary Allow '~', '+', and quoted paths in config file
      * @author Valerie Peng
    + * @library /test/lib
      */
     
    -import java.security.*;
    -import java.io.*;
    -import java.lang.reflect.*;
    +import jtreg.SkippedException;
    +
    +import java.io.File;
    +import java.io.IOException;
    +import java.security.InvalidParameterException;
    +import java.security.Provider;
    +import java.security.ProviderException;
    +import java.security.Security;
     
     public class ConfigShortPath {
     
    @@ -43,8 +49,7 @@ public class ConfigShortPath {
         public static void main(String[] args) throws Exception {
             Provider p = Security.getProvider("SunPKCS11");
             if (p == null) {
    -            System.out.println("Skipping test - no PKCS11 provider available");
    -            return;
    +            throw new SkippedException("Skipping test - no PKCS11 provider available");
             }
     
             String osInfo = System.getProperty("os.name", "");
    @@ -65,7 +70,7 @@ public class ConfigShortPath {
                     if (cause.getClass().getName().equals
                             ("sun.security.pkcs11.ConfigurationException")) {
                         // Error occurred during parsing
    -                    if (cause.getMessage().indexOf("Unexpected") != -1) {
    +                    if (cause.getMessage().contains("Unexpected")) {
                             throw (ProviderException) cause;
                         }
                     }
    diff --git a/test/jdk/sun/security/pkcs11/Provider/LoginISE.java b/test/jdk/sun/security/pkcs11/Provider/LoginISE.java
    index 5027770c5e6..d131a857216 100644
    --- a/test/jdk/sun/security/pkcs11/Provider/LoginISE.java
    +++ b/test/jdk/sun/security/pkcs11/Provider/LoginISE.java
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 2015, 2025, 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
    @@ -21,16 +21,22 @@
      * questions.
      */
     
    -import java.io.*;
    -import java.util.*;
    -import java.security.*;
    -import javax.security.auth.callback.*;
    +import jtreg.SkippedException;
    +
    +import java.io.IOException;
    +import java.security.AuthProvider;
    +import java.security.Provider;
    +import java.security.Security;
    +import javax.security.auth.callback.Callback;
    +import javax.security.auth.callback.CallbackHandler;
    +import javax.security.auth.callback.UnsupportedCallbackException;
     
     /**
      * @test
      * @bug 8130648
      * @summary make sure IllegalStateException is thrown for uninitialized
      * SunPKCS11 provider instance
    + * @library /test/lib
      */
     public class LoginISE {
     
    @@ -38,8 +44,7 @@ public class LoginISE {
     
             Provider p = Security.getProvider("SunPKCS11");
             if (p == null) {
    -            System.out.println("No un-initialized PKCS11 provider available; skip");
    -            return;
    +            throw new SkippedException("No un-initialized PKCS11 provider available; skip");
             }
             if (!(p instanceof AuthProvider)) {
                 throw new RuntimeException("Error: expect AuthProvider!");
    
    From ef5e744a8136c3d983bdf8721a84fd1488b3c7a8 Mon Sep 17 00:00:00 2001
    From: Thomas Schatzl 
    Date: Mon, 1 Dec 2025 08:05:55 +0000
    Subject: [PATCH 066/706] 8372684: G1: Missing load_acquire() in G1 allocation
     path
    
    Reviewed-by: kbarrett, sjohanss
    ---
     src/hotspot/share/gc/g1/g1AllocRegion.cpp     | 67 ++++++++++---------
     src/hotspot/share/gc/g1/g1AllocRegion.hpp     | 13 ++--
     .../share/gc/g1/g1AllocRegion.inline.hpp      | 11 +--
     3 files changed, 47 insertions(+), 44 deletions(-)
    
    diff --git a/src/hotspot/share/gc/g1/g1AllocRegion.cpp b/src/hotspot/share/gc/g1/g1AllocRegion.cpp
    index 7e748cf7e9f..1af7638102a 100644
    --- a/src/hotspot/share/gc/g1/g1AllocRegion.cpp
    +++ b/src/hotspot/share/gc/g1/g1AllocRegion.cpp
    @@ -33,10 +33,10 @@
     #include "utilities/align.hpp"
     
     G1CollectedHeap* G1AllocRegion::_g1h = nullptr;
    -G1HeapRegion* G1AllocRegion::_dummy_region = nullptr;
    +Atomic G1AllocRegion::_dummy_region;
     
     void G1AllocRegion::setup(G1CollectedHeap* g1h, G1HeapRegion* dummy_region) {
    -  assert(_dummy_region == nullptr, "should be set once");
    +  assert(_dummy_region.load_relaxed() == nullptr, "should be set once");
       assert(dummy_region != nullptr, "pre-condition");
       assert(dummy_region->free() == 0, "pre-condition");
     
    @@ -46,11 +46,11 @@ void G1AllocRegion::setup(G1CollectedHeap* g1h, G1HeapRegion* dummy_region) {
       assert(dummy_region->par_allocate(1, 1, &assert_tmp) == nullptr, "should fail");
     
       _g1h = g1h;
    -  _dummy_region = dummy_region;
    +  _dummy_region.release_store(dummy_region);
     }
     
     size_t G1AllocRegion::fill_up_remaining_space(G1HeapRegion* alloc_region) {
    -  assert(alloc_region != nullptr && alloc_region != _dummy_region,
    +  assert(alloc_region != nullptr && alloc_region != _dummy_region.load_relaxed(),
              "pre-condition");
       size_t result = 0;
     
    @@ -111,13 +111,13 @@ size_t G1AllocRegion::retire_internal(G1HeapRegion* alloc_region, bool fill_up)
     }
     
     size_t G1AllocRegion::retire(bool fill_up) {
    -  assert_alloc_region(_alloc_region != nullptr, "not initialized properly");
    +  assert_alloc_region(_alloc_region.load_relaxed() != nullptr, "not initialized properly");
     
       size_t waste = 0;
     
       trace("retiring");
    -  G1HeapRegion* alloc_region = _alloc_region;
    -  if (alloc_region != _dummy_region) {
    +  G1HeapRegion* alloc_region = _alloc_region.load_acquire();
    +  if (alloc_region != _dummy_region.load_relaxed()) {
         waste = retire_internal(alloc_region, fill_up);
         reset_alloc_region();
       }
    @@ -127,7 +127,7 @@ size_t G1AllocRegion::retire(bool fill_up) {
     }
     
     HeapWord* G1AllocRegion::new_alloc_region_and_allocate(size_t word_size) {
    -  assert_alloc_region(_alloc_region == _dummy_region, "pre-condition");
    +  assert_alloc_region(_alloc_region.load_relaxed() == _dummy_region.load_relaxed(), "pre-condition");
     
       trace("attempting region allocation");
       G1HeapRegion* new_alloc_region = allocate_new_region(word_size);
    @@ -138,7 +138,6 @@ HeapWord* G1AllocRegion::new_alloc_region_and_allocate(size_t word_size) {
         HeapWord* result = new_alloc_region->allocate(word_size);
         assert_alloc_region(result != nullptr, "the allocation should succeeded");
     
    -    OrderAccess::storestore();
         // Note that we first perform the allocation and then we store the
         // region in _alloc_region. This is the reason why an active region
         // can never be empty.
    @@ -154,16 +153,16 @@ HeapWord* G1AllocRegion::new_alloc_region_and_allocate(size_t word_size) {
     
     void G1AllocRegion::init() {
       trace("initializing");
    -  assert_alloc_region(_alloc_region == nullptr, "pre-condition");
    -  assert_alloc_region(_dummy_region != nullptr, "should have been set");
    -  _alloc_region = _dummy_region;
    +  assert_alloc_region(_alloc_region.load_relaxed() == nullptr, "pre-condition");
    +  assert_alloc_region(_dummy_region.load_relaxed() != nullptr, "should have been set");
    +  _alloc_region.release_store(_dummy_region.load_relaxed());
       _count = 0;
       trace("initialized");
     }
     
     void G1AllocRegion::set(G1HeapRegion* alloc_region) {
       trace("setting");
    -  assert_alloc_region(_alloc_region == _dummy_region && _count == 0, "pre-condition");
    +  assert_alloc_region(_alloc_region.load_relaxed() == _dummy_region.load_relaxed() && _count == 0, "pre-condition");
     
       update_alloc_region(alloc_region);
       trace("set");
    @@ -175,19 +174,19 @@ void G1AllocRegion::update_alloc_region(G1HeapRegion* alloc_region) {
       // maintain the "the alloc region cannot be empty" invariant.
       assert_alloc_region(alloc_region != nullptr && !alloc_region->is_empty(), "pre-condition");
     
    -  _alloc_region = alloc_region;
    +  _alloc_region.release_store(alloc_region);
       _count += 1;
       trace("updated");
     }
     
     G1HeapRegion* G1AllocRegion::release() {
       trace("releasing");
    -  G1HeapRegion* alloc_region = _alloc_region;
    +  G1HeapRegion* alloc_region = _alloc_region.load_acquire();
       retire(false /* fill_up */);
    -  assert_alloc_region(_alloc_region == _dummy_region, "post-condition of retire()");
    -  _alloc_region = nullptr;
    +  assert_alloc_region(_alloc_region.load_relaxed() == _dummy_region.load_relaxed(), "post-condition of retire()");
    +  _alloc_region.store_relaxed(nullptr);
       trace("released");
    -  return (alloc_region == _dummy_region) ? nullptr : alloc_region;
    +  return (alloc_region == _dummy_region.load_relaxed()) ? nullptr : alloc_region;
     }
     
     #ifndef PRODUCT
    @@ -211,12 +210,13 @@ void G1AllocRegion::trace(const char* str, size_t min_word_size, size_t desired_
     
         out->print("%s: %u ", _name, _count);
     
    -    if (_alloc_region == nullptr) {
    +    G1HeapRegion* alloc_region = _alloc_region.load_acquire();
    +    if (alloc_region == nullptr) {
           out->print("null");
    -    } else if (_alloc_region == _dummy_region) {
    +    } else if (alloc_region == _dummy_region.load_relaxed()) {
           out->print("DUMMY");
         } else {
    -      out->print(HR_FORMAT, HR_FORMAT_PARAMS(_alloc_region));
    +      out->print(HR_FORMAT, HR_FORMAT_PARAMS(alloc_region));
         }
     
         out->print(" : %s", str);
    @@ -235,7 +235,7 @@ void G1AllocRegion::trace(const char* str, size_t min_word_size, size_t desired_
     #endif // PRODUCT
     
     G1AllocRegion::G1AllocRegion(const char* name, uint node_index)
    -  : _alloc_region(nullptr),
    +  : _alloc_region(),
         _count(0),
         _name(name),
         _node_index(node_index)
    @@ -250,7 +250,7 @@ void MutatorAllocRegion::retire_region(G1HeapRegion* alloc_region) {
     }
     
     void MutatorAllocRegion::init() {
    -  assert(_retained_alloc_region == nullptr, "Pre-condition");
    +  assert(_retained_alloc_region.load_relaxed() == nullptr, "Pre-condition");
       G1AllocRegion::init();
       _wasted_bytes = 0;
     }
    @@ -261,8 +261,9 @@ bool MutatorAllocRegion::should_retain(G1HeapRegion* region) {
         return false;
       }
     
    -  if (_retained_alloc_region != nullptr &&
    -      free_bytes < _retained_alloc_region->free()) {
    +  G1HeapRegion* retained_alloc_region = _retained_alloc_region.load_acquire();
    +  if (retained_alloc_region != nullptr &&
    +      free_bytes < retained_alloc_region->free()) {
         return false;
       }
     
    @@ -278,10 +279,11 @@ size_t MutatorAllocRegion::retire(bool fill_up) {
         // free than the currently retained region.
         if (should_retain(current_region)) {
           trace("mutator retained");
    -      if (_retained_alloc_region != nullptr) {
    -        waste = retire_internal(_retained_alloc_region, true);
    +      G1HeapRegion* retained_alloc_region = _retained_alloc_region.load_acquire();
    +      if (retained_alloc_region != nullptr) {
    +        waste = retire_internal(retained_alloc_region, true);
           }
    -      _retained_alloc_region = current_region;
    +      _retained_alloc_region.release_store(current_region);
         } else {
           waste = retire_internal(current_region, fill_up);
         }
    @@ -300,7 +302,7 @@ size_t MutatorAllocRegion::used_in_alloc_regions() {
         used += hr->used();
       }
     
    -  hr = _retained_alloc_region;
    +  hr = _retained_alloc_region.load_acquire();
       if (hr != nullptr) {
         used += hr->used();
       }
    @@ -313,9 +315,10 @@ G1HeapRegion* MutatorAllocRegion::release() {
       // The retained alloc region must be retired and this must be
       // done after the above call to release the mutator alloc region,
       // since it might update the _retained_alloc_region member.
    -  if (_retained_alloc_region != nullptr) {
    -    _wasted_bytes += retire_internal(_retained_alloc_region, false);
    -    _retained_alloc_region = nullptr;
    +  G1HeapRegion* retained_alloc_region = _retained_alloc_region.load_acquire();
    +  if (retained_alloc_region != nullptr) {
    +    _wasted_bytes += retire_internal(retained_alloc_region, false);
    +    _retained_alloc_region.store_relaxed(nullptr);
       }
       log_debug(gc, alloc, region)("Mutator Allocation stats, regions: %u, wasted size: %zu%s (%4.1f%%)",
                                    count(),
    diff --git a/src/hotspot/share/gc/g1/g1AllocRegion.hpp b/src/hotspot/share/gc/g1/g1AllocRegion.hpp
    index 3e38332ee6f..248aa0a9da0 100644
    --- a/src/hotspot/share/gc/g1/g1AllocRegion.hpp
    +++ b/src/hotspot/share/gc/g1/g1AllocRegion.hpp
    @@ -29,6 +29,7 @@
     #include "gc/g1/g1HeapRegion.hpp"
     #include "gc/g1/g1HeapRegionAttr.hpp"
     #include "gc/g1/g1NUMA.hpp"
    +#include "runtime/atomic.hpp"
     
     class G1CollectedHeap;
     
    @@ -40,8 +41,6 @@ class G1CollectedHeap;
     // replaced.
     
     class G1AllocRegion : public CHeapObj {
    -
    -private:
       // The active allocating region we are currently allocating out
       // of. The invariant is that if this object is initialized (i.e.,
       // init() has been called and release() has not) then _alloc_region
    @@ -52,7 +51,7 @@ private:
       // then _alloc_region is null and this object should not be used to
       // satisfy allocation requests (it was done this way to force the
       // correct use of init() and release()).
    -  G1HeapRegion* volatile _alloc_region;
    +  Atomic _alloc_region;
     
       // It keeps track of the distinct number of regions that are used
       // for allocation in the active interval of this object, i.e.,
    @@ -71,7 +70,7 @@ private:
       // == end()). When we don't have a valid active region we make
       // _alloc_region point to this. This allows us to skip checking
       // whether the _alloc_region is null or not.
    -  static G1HeapRegion* _dummy_region;
    +  static Atomic _dummy_region;
     
       // After a region is allocated by alloc_new_region, this
       // method is used to set it as the active alloc_region
    @@ -124,9 +123,9 @@ public:
       static void setup(G1CollectedHeap* g1h, G1HeapRegion* dummy_region);
     
       G1HeapRegion* get() const {
    -    G1HeapRegion * hr = _alloc_region;
    +    G1HeapRegion * hr = _alloc_region.load_acquire();
         // Make sure that the dummy region does not escape this class.
    -    return (hr == _dummy_region) ? nullptr : hr;
    +    return (hr == _dummy_region.load_relaxed()) ? nullptr : hr;
       }
     
       uint count() { return _count; }
    @@ -177,7 +176,7 @@ private:
       // Retained allocation region. Used to lower the waste generated
       // during mutation by having two active regions if the free space
       // in a region about to be retired still could fit a TLAB.
    -  G1HeapRegion* volatile _retained_alloc_region;
    +  Atomic _retained_alloc_region;
     
       // Decide if the region should be retained, based on the free size
       // in it and the free size in the currently retained region, if any.
    diff --git a/src/hotspot/share/gc/g1/g1AllocRegion.inline.hpp b/src/hotspot/share/gc/g1/g1AllocRegion.inline.hpp
    index af9156163ac..e1d23867ea3 100644
    --- a/src/hotspot/share/gc/g1/g1AllocRegion.inline.hpp
    +++ b/src/hotspot/share/gc/g1/g1AllocRegion.inline.hpp
    @@ -32,13 +32,13 @@
     #define assert_alloc_region(p, message)                                  \
       do {                                                                   \
         assert((p), "[%s] %s c: %u r: " PTR_FORMAT,                          \
    -           _name, (message), _count, p2i(_alloc_region)                  \
    +           _name, (message), _count, p2i(_alloc_region.load_relaxed())   \
               );                                                             \
       } while (0)
     
     
     inline void G1AllocRegion::reset_alloc_region() {
    -  _alloc_region = _dummy_region;
    +  _alloc_region.store_relaxed(_dummy_region.load_relaxed());
     }
     
     inline HeapWord* G1AllocRegion::par_allocate(G1HeapRegion* alloc_region, size_t word_size) {
    @@ -51,7 +51,7 @@ inline HeapWord* G1AllocRegion::par_allocate(G1HeapRegion* alloc_region, size_t
     inline HeapWord* G1AllocRegion::attempt_allocation(size_t min_word_size,
                                                        size_t desired_word_size,
                                                        size_t* actual_word_size) {
    -  G1HeapRegion* alloc_region = _alloc_region;
    +  G1HeapRegion* alloc_region = _alloc_region.load_acquire();
       assert_alloc_region(alloc_region != nullptr && !alloc_region->is_empty(), "not initialized properly");
     
       HeapWord* result = alloc_region->par_allocate(min_word_size, desired_word_size, actual_word_size);
    @@ -97,8 +97,9 @@ inline HeapWord* G1AllocRegion::attempt_allocation_using_new_region(size_t min_w
     inline HeapWord* MutatorAllocRegion::attempt_retained_allocation(size_t min_word_size,
                                                                      size_t desired_word_size,
                                                                      size_t* actual_word_size) {
    -  if (_retained_alloc_region != nullptr) {
    -    HeapWord* result = _retained_alloc_region->par_allocate(min_word_size, desired_word_size, actual_word_size);
    +  G1HeapRegion* retained_alloc_region = _retained_alloc_region.load_acquire();
    +  if (retained_alloc_region != nullptr) {
    +    HeapWord* result = retained_alloc_region->par_allocate(min_word_size, desired_word_size, actual_word_size);
         if (result != nullptr) {
           trace("alloc retained", min_word_size, desired_word_size, *actual_word_size, result);
           return result;
    
    From 3481252ced7c06c44154ceccc56b12cfd9a490c3 Mon Sep 17 00:00:00 2001
    From: Aleksey Shipilev 
    Date: Mon, 1 Dec 2025 08:41:18 +0000
    Subject: [PATCH 067/706] 8372188: AArch64: Generate atomic match rules from M4
     stencils
    
    Reviewed-by: aph, haosun
    ---
     make/hotspot/gensrc/GensrcAdlc.gmk           |    1 +
     src/hotspot/cpu/aarch64/aarch64.ad           | 1032 ------------------
     src/hotspot/cpu/aarch64/aarch64_atomic.ad    |  909 +++++++++++++++
     src/hotspot/cpu/aarch64/aarch64_atomic_ad.m4 |  246 +++++
     src/hotspot/cpu/aarch64/cas.m4               |  161 ---
     5 files changed, 1156 insertions(+), 1193 deletions(-)
     create mode 100644 src/hotspot/cpu/aarch64/aarch64_atomic.ad
     create mode 100644 src/hotspot/cpu/aarch64/aarch64_atomic_ad.m4
     delete mode 100644 src/hotspot/cpu/aarch64/cas.m4
    
    diff --git a/make/hotspot/gensrc/GensrcAdlc.gmk b/make/hotspot/gensrc/GensrcAdlc.gmk
    index 4cecc3070e7..14117421d1b 100644
    --- a/make/hotspot/gensrc/GensrcAdlc.gmk
    +++ b/make/hotspot/gensrc/GensrcAdlc.gmk
    @@ -170,6 +170,7 @@ ifeq ($(call check-jvm-feature, compiler2), true)
       ifeq ($(HOTSPOT_TARGET_CPU_ARCH), aarch64)
         AD_SRC_FILES += $(call uniq, $(wildcard $(foreach d, $(AD_SRC_ROOTS), \
             $d/cpu/$(HOTSPOT_TARGET_CPU_ARCH)/$(HOTSPOT_TARGET_CPU_ARCH)_vector.ad \
    +        $d/cpu/$(HOTSPOT_TARGET_CPU_ARCH)/$(HOTSPOT_TARGET_CPU_ARCH)_atomic.ad \
         )))
       endif
     
    diff --git a/src/hotspot/cpu/aarch64/aarch64.ad b/src/hotspot/cpu/aarch64/aarch64.ad
    index fc53c10311b..9c76ed24788 100644
    --- a/src/hotspot/cpu/aarch64/aarch64.ad
    +++ b/src/hotspot/cpu/aarch64/aarch64.ad
    @@ -3342,73 +3342,6 @@ encode %{
         __ cmpw(rscratch1, zr);
       %}
     
    -  enc_class aarch64_enc_cmpxchg(memory mem, iRegLNoSp oldval, iRegLNoSp newval) %{
    -    guarantee($mem$$index == -1 && $mem$$disp == 0, "impossible encoding");
    -    __ cmpxchg($mem$$base$$Register, $oldval$$Register, $newval$$Register,
    -               Assembler::xword, /*acquire*/ false, /*release*/ true,
    -               /*weak*/ false, noreg);
    -  %}
    -
    -  enc_class aarch64_enc_cmpxchgw(memory mem, iRegINoSp oldval, iRegINoSp newval) %{
    -    guarantee($mem$$index == -1 && $mem$$disp == 0, "impossible encoding");
    -    __ cmpxchg($mem$$base$$Register, $oldval$$Register, $newval$$Register,
    -               Assembler::word, /*acquire*/ false, /*release*/ true,
    -               /*weak*/ false, noreg);
    -  %}
    -
    -  enc_class aarch64_enc_cmpxchgs(memory mem, iRegINoSp oldval, iRegINoSp newval) %{
    -    guarantee($mem$$index == -1 && $mem$$disp == 0, "impossible encoding");
    -    __ cmpxchg($mem$$base$$Register, $oldval$$Register, $newval$$Register,
    -               Assembler::halfword, /*acquire*/ false, /*release*/ true,
    -               /*weak*/ false, noreg);
    -  %}
    -
    -  enc_class aarch64_enc_cmpxchgb(memory mem, iRegINoSp oldval, iRegINoSp newval) %{
    -    guarantee($mem$$index == -1 && $mem$$disp == 0, "impossible encoding");
    -    __ cmpxchg($mem$$base$$Register, $oldval$$Register, $newval$$Register,
    -               Assembler::byte, /*acquire*/ false, /*release*/ true,
    -               /*weak*/ false, noreg);
    -  %}
    -
    -
    -  // The only difference between aarch64_enc_cmpxchg and
    -  // aarch64_enc_cmpxchg_acq is that we use load-acquire in the
    -  // CompareAndSwap sequence to serve as a barrier on acquiring a
    -  // lock.
    -  enc_class aarch64_enc_cmpxchg_acq(memory mem, iRegL oldval, iRegL newval) %{
    -    guarantee($mem$$index == -1 && $mem$$disp == 0, "impossible encoding");
    -    __ cmpxchg($mem$$base$$Register, $oldval$$Register, $newval$$Register,
    -               Assembler::xword, /*acquire*/ true, /*release*/ true,
    -               /*weak*/ false, noreg);
    -  %}
    -
    -  enc_class aarch64_enc_cmpxchgw_acq(memory mem, iRegI oldval, iRegI newval) %{
    -    guarantee($mem$$index == -1 && $mem$$disp == 0, "impossible encoding");
    -    __ cmpxchg($mem$$base$$Register, $oldval$$Register, $newval$$Register,
    -               Assembler::word, /*acquire*/ true, /*release*/ true,
    -               /*weak*/ false, noreg);
    -  %}
    -
    -  enc_class aarch64_enc_cmpxchgs_acq(memory mem, iRegI oldval, iRegI newval) %{
    -    guarantee($mem$$index == -1 && $mem$$disp == 0, "impossible encoding");
    -    __ cmpxchg($mem$$base$$Register, $oldval$$Register, $newval$$Register,
    -               Assembler::halfword, /*acquire*/ true, /*release*/ true,
    -               /*weak*/ false, noreg);
    -  %}
    -
    -  enc_class aarch64_enc_cmpxchgb_acq(memory mem, iRegI oldval, iRegI newval) %{
    -    guarantee($mem$$index == -1 && $mem$$disp == 0, "impossible encoding");
    -    __ cmpxchg($mem$$base$$Register, $oldval$$Register, $newval$$Register,
    -               Assembler::byte, /*acquire*/ true, /*release*/ true,
    -               /*weak*/ false, noreg);
    -  %}
    -
    -  // auxiliary used for CompareAndSwapX to set result register
    -  enc_class aarch64_enc_cset_eq(iRegI res) %{
    -    Register res_reg = as_Register($res$$reg);
    -    __ cset(res_reg, Assembler::EQ);
    -  %}
    -
       // prefetch encodings
     
       enc_class aarch64_enc_prefetchw(memory mem) %{
    @@ -8380,971 +8313,6 @@ instruct castVVMask(pRegGov dst)
       ins_pipe(pipe_class_empty);
     %}
     
    -// ============================================================================
    -// Atomic operation instructions
    -//
    -
    -// standard CompareAndSwapX when we are using barriers
    -// these have higher priority than the rules selected by a predicate
    -
    -// XXX No flag versions for CompareAndSwap{I,L,P,N} because matcher
    -// can't match them
    -
    -instruct compareAndSwapB(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{
    -
    -  match(Set res (CompareAndSwapB mem (Binary oldval newval)));
    -  ins_cost(2 * VOLATILE_REF_COST);
    -
    -  effect(KILL cr);
    -
    -  format %{
    -    "cmpxchgb $mem, $oldval, $newval\t# (int) if $mem == $oldval then $mem <-- $newval"
    -    "cset $res, EQ\t# $res <-- (EQ ? 1 : 0)"
    -  %}
    -
    -  ins_encode(aarch64_enc_cmpxchgb(mem, oldval, newval),
    -            aarch64_enc_cset_eq(res));
    -
    -  ins_pipe(pipe_slow);
    -%}
    -
    -instruct compareAndSwapS(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{
    -
    -  match(Set res (CompareAndSwapS mem (Binary oldval newval)));
    -  ins_cost(2 * VOLATILE_REF_COST);
    -
    -  effect(KILL cr);
    -
    -  format %{
    -    "cmpxchgs $mem, $oldval, $newval\t# (int) if $mem == $oldval then $mem <-- $newval"
    -    "cset $res, EQ\t# $res <-- (EQ ? 1 : 0)"
    -  %}
    -
    -  ins_encode(aarch64_enc_cmpxchgs(mem, oldval, newval),
    -            aarch64_enc_cset_eq(res));
    -
    -  ins_pipe(pipe_slow);
    -%}
    -
    -instruct compareAndSwapI(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{
    -
    -  match(Set res (CompareAndSwapI mem (Binary oldval newval)));
    -  ins_cost(2 * VOLATILE_REF_COST);
    -
    -  effect(KILL cr);
    -
    - format %{
    -    "cmpxchgw $mem, $oldval, $newval\t# (int) if $mem == $oldval then $mem <-- $newval"
    -    "cset $res, EQ\t# $res <-- (EQ ? 1 : 0)"
    - %}
    -
    - ins_encode(aarch64_enc_cmpxchgw(mem, oldval, newval),
    -            aarch64_enc_cset_eq(res));
    -
    -  ins_pipe(pipe_slow);
    -%}
    -
    -instruct compareAndSwapL(iRegINoSp res, indirect mem, iRegL oldval, iRegL newval, rFlagsReg cr) %{
    -
    -  match(Set res (CompareAndSwapL mem (Binary oldval newval)));
    -  ins_cost(2 * VOLATILE_REF_COST);
    -
    -  effect(KILL cr);
    -
    - format %{
    -    "cmpxchg $mem, $oldval, $newval\t# (long) if $mem == $oldval then $mem <-- $newval"
    -    "cset $res, EQ\t# $res <-- (EQ ? 1 : 0)"
    - %}
    -
    - ins_encode(aarch64_enc_cmpxchg(mem, oldval, newval),
    -            aarch64_enc_cset_eq(res));
    -
    -  ins_pipe(pipe_slow);
    -%}
    -
    -instruct compareAndSwapP(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval, rFlagsReg cr) %{
    -
    -  match(Set res (CompareAndSwapP mem (Binary oldval newval)));
    -  predicate(n->as_LoadStore()->barrier_data() == 0);
    -  ins_cost(2 * VOLATILE_REF_COST);
    -
    -  effect(KILL cr);
    -
    - format %{
    -    "cmpxchg $mem, $oldval, $newval\t# (ptr) if $mem == $oldval then $mem <-- $newval"
    -    "cset $res, EQ\t# $res <-- (EQ ? 1 : 0)"
    - %}
    -
    - ins_encode(aarch64_enc_cmpxchg(mem, oldval, newval),
    -            aarch64_enc_cset_eq(res));
    -
    -  ins_pipe(pipe_slow);
    -%}
    -
    -instruct compareAndSwapN(iRegINoSp res, indirect mem, iRegN oldval, iRegN newval, rFlagsReg cr) %{
    -
    -  match(Set res (CompareAndSwapN mem (Binary oldval newval)));
    -  predicate(n->as_LoadStore()->barrier_data() == 0);
    -  ins_cost(2 * VOLATILE_REF_COST);
    -
    -  effect(KILL cr);
    -
    - format %{
    -    "cmpxchgw $mem, $oldval, $newval\t# (narrow oop) if $mem == $oldval then $mem <-- $newval"
    -    "cset $res, EQ\t# $res <-- (EQ ? 1 : 0)"
    - %}
    -
    - ins_encode(aarch64_enc_cmpxchgw(mem, oldval, newval),
    -            aarch64_enc_cset_eq(res));
    -
    -  ins_pipe(pipe_slow);
    -%}
    -
    -// alternative CompareAndSwapX when we are eliding barriers
    -
    -instruct compareAndSwapBAcq(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{
    -
    -  predicate(needs_acquiring_load_exclusive(n));
    -  match(Set res (CompareAndSwapB mem (Binary oldval newval)));
    -  ins_cost(VOLATILE_REF_COST);
    -
    -  effect(KILL cr);
    -
    -  format %{
    -    "cmpxchgb_acq $mem, $oldval, $newval\t# (int) if $mem == $oldval then $mem <-- $newval"
    -    "cset $res, EQ\t# $res <-- (EQ ? 1 : 0)"
    -  %}
    -
    -  ins_encode(aarch64_enc_cmpxchgb_acq(mem, oldval, newval),
    -            aarch64_enc_cset_eq(res));
    -
    -  ins_pipe(pipe_slow);
    -%}
    -
    -instruct compareAndSwapSAcq(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{
    -
    -  predicate(needs_acquiring_load_exclusive(n));
    -  match(Set res (CompareAndSwapS mem (Binary oldval newval)));
    -  ins_cost(VOLATILE_REF_COST);
    -
    -  effect(KILL cr);
    -
    -  format %{
    -    "cmpxchgs_acq $mem, $oldval, $newval\t# (int) if $mem == $oldval then $mem <-- $newval"
    -    "cset $res, EQ\t# $res <-- (EQ ? 1 : 0)"
    -  %}
    -
    -  ins_encode(aarch64_enc_cmpxchgs_acq(mem, oldval, newval),
    -            aarch64_enc_cset_eq(res));
    -
    -  ins_pipe(pipe_slow);
    -%}
    -
    -instruct compareAndSwapIAcq(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{
    -
    -  predicate(needs_acquiring_load_exclusive(n));
    -  match(Set res (CompareAndSwapI mem (Binary oldval newval)));
    -  ins_cost(VOLATILE_REF_COST);
    -
    -  effect(KILL cr);
    -
    - format %{
    -    "cmpxchgw_acq $mem, $oldval, $newval\t# (int) if $mem == $oldval then $mem <-- $newval"
    -    "cset $res, EQ\t# $res <-- (EQ ? 1 : 0)"
    - %}
    -
    - ins_encode(aarch64_enc_cmpxchgw_acq(mem, oldval, newval),
    -            aarch64_enc_cset_eq(res));
    -
    -  ins_pipe(pipe_slow);
    -%}
    -
    -instruct compareAndSwapLAcq(iRegINoSp res, indirect mem, iRegL oldval, iRegL newval, rFlagsReg cr) %{
    -
    -  predicate(needs_acquiring_load_exclusive(n));
    -  match(Set res (CompareAndSwapL mem (Binary oldval newval)));
    -  ins_cost(VOLATILE_REF_COST);
    -
    -  effect(KILL cr);
    -
    - format %{
    -    "cmpxchg_acq $mem, $oldval, $newval\t# (long) if $mem == $oldval then $mem <-- $newval"
    -    "cset $res, EQ\t# $res <-- (EQ ? 1 : 0)"
    - %}
    -
    - ins_encode(aarch64_enc_cmpxchg_acq(mem, oldval, newval),
    -            aarch64_enc_cset_eq(res));
    -
    -  ins_pipe(pipe_slow);
    -%}
    -
    -instruct compareAndSwapPAcq(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval, rFlagsReg cr) %{
    -
    -  predicate(needs_acquiring_load_exclusive(n) && (n->as_LoadStore()->barrier_data() == 0));
    -  match(Set res (CompareAndSwapP mem (Binary oldval newval)));
    -  ins_cost(VOLATILE_REF_COST);
    -
    -  effect(KILL cr);
    -
    - format %{
    -    "cmpxchg_acq $mem, $oldval, $newval\t# (ptr) if $mem == $oldval then $mem <-- $newval"
    -    "cset $res, EQ\t# $res <-- (EQ ? 1 : 0)"
    - %}
    -
    - ins_encode(aarch64_enc_cmpxchg_acq(mem, oldval, newval),
    -            aarch64_enc_cset_eq(res));
    -
    -  ins_pipe(pipe_slow);
    -%}
    -
    -instruct compareAndSwapNAcq(iRegINoSp res, indirect mem, iRegN oldval, iRegN newval, rFlagsReg cr) %{
    -
    -  predicate(needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() == 0);
    -  match(Set res (CompareAndSwapN mem (Binary oldval newval)));
    -  ins_cost(VOLATILE_REF_COST);
    -
    -  effect(KILL cr);
    -
    - format %{
    -    "cmpxchgw_acq $mem, $oldval, $newval\t# (narrow oop) if $mem == $oldval then $mem <-- $newval"
    -    "cset $res, EQ\t# $res <-- (EQ ? 1 : 0)"
    - %}
    -
    - ins_encode(aarch64_enc_cmpxchgw_acq(mem, oldval, newval),
    -            aarch64_enc_cset_eq(res));
    -
    -  ins_pipe(pipe_slow);
    -%}
    -
    -
    -// ---------------------------------------------------------------------
    -
    -// BEGIN This section of the file is automatically generated. Do not edit --------------
    -
    -// Sundry CAS operations.  Note that release is always true,
    -// regardless of the memory ordering of the CAS.  This is because we
    -// need the volatile case to be sequentially consistent but there is
    -// no trailing StoreLoad barrier emitted by C2.  Unfortunately we
    -// can't check the type of memory ordering here, so we always emit a
    -// STLXR.
    -
    -// This section is generated from cas.m4
    -
    -
    -// This pattern is generated automatically from cas.m4.
    -// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE
    -instruct compareAndExchangeB(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{
    -  match(Set res (CompareAndExchangeB mem (Binary oldval newval)));
    -  ins_cost(2 * VOLATILE_REF_COST);
    -  effect(TEMP_DEF res, KILL cr);
    -  format %{
    -    "cmpxchgb $res = $mem, $oldval, $newval\t# (byte, weak) if $mem == $oldval then $mem <-- $newval"
    -  %}
    -  ins_encode %{
    -    __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register,
    -               Assembler::byte, /*acquire*/ false, /*release*/ true,
    -               /*weak*/ false, $res$$Register);
    -    __ sxtbw($res$$Register, $res$$Register);
    -  %}
    -  ins_pipe(pipe_slow);
    -%}
    -
    -// This pattern is generated automatically from cas.m4.
    -// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE
    -instruct compareAndExchangeS(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{
    -  match(Set res (CompareAndExchangeS mem (Binary oldval newval)));
    -  ins_cost(2 * VOLATILE_REF_COST);
    -  effect(TEMP_DEF res, KILL cr);
    -  format %{
    -    "cmpxchgs $res = $mem, $oldval, $newval\t# (short, weak) if $mem == $oldval then $mem <-- $newval"
    -  %}
    -  ins_encode %{
    -    __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register,
    -               Assembler::halfword, /*acquire*/ false, /*release*/ true,
    -               /*weak*/ false, $res$$Register);
    -    __ sxthw($res$$Register, $res$$Register);
    -  %}
    -  ins_pipe(pipe_slow);
    -%}
    -
    -// This pattern is generated automatically from cas.m4.
    -// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE
    -instruct compareAndExchangeI(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{
    -  match(Set res (CompareAndExchangeI mem (Binary oldval newval)));
    -  ins_cost(2 * VOLATILE_REF_COST);
    -  effect(TEMP_DEF res, KILL cr);
    -  format %{
    -    "cmpxchgw $res = $mem, $oldval, $newval\t# (int, weak) if $mem == $oldval then $mem <-- $newval"
    -  %}
    -  ins_encode %{
    -    __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register,
    -               Assembler::word, /*acquire*/ false, /*release*/ true,
    -               /*weak*/ false, $res$$Register);
    -  %}
    -  ins_pipe(pipe_slow);
    -%}
    -
    -// This pattern is generated automatically from cas.m4.
    -// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE
    -instruct compareAndExchangeL(iRegLNoSp res, indirect mem, iRegL oldval, iRegL newval, rFlagsReg cr) %{
    -  match(Set res (CompareAndExchangeL mem (Binary oldval newval)));
    -  ins_cost(2 * VOLATILE_REF_COST);
    -  effect(TEMP_DEF res, KILL cr);
    -  format %{
    -    "cmpxchg $res = $mem, $oldval, $newval\t# (long, weak) if $mem == $oldval then $mem <-- $newval"
    -  %}
    -  ins_encode %{
    -    __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register,
    -               Assembler::xword, /*acquire*/ false, /*release*/ true,
    -               /*weak*/ false, $res$$Register);
    -  %}
    -  ins_pipe(pipe_slow);
    -%}
    -
    -// This pattern is generated automatically from cas.m4.
    -// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE
    -instruct compareAndExchangeN(iRegNNoSp res, indirect mem, iRegN oldval, iRegN newval, rFlagsReg cr) %{
    -  predicate(n->as_LoadStore()->barrier_data() == 0);
    -  match(Set res (CompareAndExchangeN mem (Binary oldval newval)));
    -  ins_cost(2 * VOLATILE_REF_COST);
    -  effect(TEMP_DEF res, KILL cr);
    -  format %{
    -    "cmpxchgw $res = $mem, $oldval, $newval\t# (narrow oop, weak) if $mem == $oldval then $mem <-- $newval"
    -  %}
    -  ins_encode %{
    -    __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register,
    -               Assembler::word, /*acquire*/ false, /*release*/ true,
    -               /*weak*/ false, $res$$Register);
    -  %}
    -  ins_pipe(pipe_slow);
    -%}
    -
    -// This pattern is generated automatically from cas.m4.
    -// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE
    -instruct compareAndExchangeP(iRegPNoSp res, indirect mem, iRegP oldval, iRegP newval, rFlagsReg cr) %{
    -  predicate(n->as_LoadStore()->barrier_data() == 0);
    -  match(Set res (CompareAndExchangeP mem (Binary oldval newval)));
    -  ins_cost(2 * VOLATILE_REF_COST);
    -  effect(TEMP_DEF res, KILL cr);
    -  format %{
    -    "cmpxchg $res = $mem, $oldval, $newval\t# (ptr, weak) if $mem == $oldval then $mem <-- $newval"
    -  %}
    -  ins_encode %{
    -    __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register,
    -               Assembler::xword, /*acquire*/ false, /*release*/ true,
    -               /*weak*/ false, $res$$Register);
    -  %}
    -  ins_pipe(pipe_slow);
    -%}
    -
    -// This pattern is generated automatically from cas.m4.
    -// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE
    -instruct compareAndExchangeBAcq(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{
    -  predicate(needs_acquiring_load_exclusive(n));
    -  match(Set res (CompareAndExchangeB mem (Binary oldval newval)));
    -  ins_cost(VOLATILE_REF_COST);
    -  effect(TEMP_DEF res, KILL cr);
    -  format %{
    -    "cmpxchgb_acq $res = $mem, $oldval, $newval\t# (byte, weak) if $mem == $oldval then $mem <-- $newval"
    -  %}
    -  ins_encode %{
    -    __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register,
    -               Assembler::byte, /*acquire*/ true, /*release*/ true,
    -               /*weak*/ false, $res$$Register);
    -    __ sxtbw($res$$Register, $res$$Register);
    -  %}
    -  ins_pipe(pipe_slow);
    -%}
    -
    -// This pattern is generated automatically from cas.m4.
    -// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE
    -instruct compareAndExchangeSAcq(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{
    -  predicate(needs_acquiring_load_exclusive(n));
    -  match(Set res (CompareAndExchangeS mem (Binary oldval newval)));
    -  ins_cost(VOLATILE_REF_COST);
    -  effect(TEMP_DEF res, KILL cr);
    -  format %{
    -    "cmpxchgs_acq $res = $mem, $oldval, $newval\t# (short, weak) if $mem == $oldval then $mem <-- $newval"
    -  %}
    -  ins_encode %{
    -    __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register,
    -               Assembler::halfword, /*acquire*/ true, /*release*/ true,
    -               /*weak*/ false, $res$$Register);
    -    __ sxthw($res$$Register, $res$$Register);
    -  %}
    -  ins_pipe(pipe_slow);
    -%}
    -
    -// This pattern is generated automatically from cas.m4.
    -// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE
    -instruct compareAndExchangeIAcq(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{
    -  predicate(needs_acquiring_load_exclusive(n));
    -  match(Set res (CompareAndExchangeI mem (Binary oldval newval)));
    -  ins_cost(VOLATILE_REF_COST);
    -  effect(TEMP_DEF res, KILL cr);
    -  format %{
    -    "cmpxchgw_acq $res = $mem, $oldval, $newval\t# (int, weak) if $mem == $oldval then $mem <-- $newval"
    -  %}
    -  ins_encode %{
    -    __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register,
    -               Assembler::word, /*acquire*/ true, /*release*/ true,
    -               /*weak*/ false, $res$$Register);
    -  %}
    -  ins_pipe(pipe_slow);
    -%}
    -
    -// This pattern is generated automatically from cas.m4.
    -// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE
    -instruct compareAndExchangeLAcq(iRegLNoSp res, indirect mem, iRegL oldval, iRegL newval, rFlagsReg cr) %{
    -  predicate(needs_acquiring_load_exclusive(n));
    -  match(Set res (CompareAndExchangeL mem (Binary oldval newval)));
    -  ins_cost(VOLATILE_REF_COST);
    -  effect(TEMP_DEF res, KILL cr);
    -  format %{
    -    "cmpxchg_acq $res = $mem, $oldval, $newval\t# (long, weak) if $mem == $oldval then $mem <-- $newval"
    -  %}
    -  ins_encode %{
    -    __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register,
    -               Assembler::xword, /*acquire*/ true, /*release*/ true,
    -               /*weak*/ false, $res$$Register);
    -  %}
    -  ins_pipe(pipe_slow);
    -%}
    -
    -// This pattern is generated automatically from cas.m4.
    -// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE
    -instruct compareAndExchangeNAcq(iRegNNoSp res, indirect mem, iRegN oldval, iRegN newval, rFlagsReg cr) %{
    -  predicate(needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() == 0);
    -  match(Set res (CompareAndExchangeN mem (Binary oldval newval)));
    -  ins_cost(VOLATILE_REF_COST);
    -  effect(TEMP_DEF res, KILL cr);
    -  format %{
    -    "cmpxchgw_acq $res = $mem, $oldval, $newval\t# (narrow oop, weak) if $mem == $oldval then $mem <-- $newval"
    -  %}
    -  ins_encode %{
    -    __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register,
    -               Assembler::word, /*acquire*/ true, /*release*/ true,
    -               /*weak*/ false, $res$$Register);
    -  %}
    -  ins_pipe(pipe_slow);
    -%}
    -
    -// This pattern is generated automatically from cas.m4.
    -// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE
    -instruct compareAndExchangePAcq(iRegPNoSp res, indirect mem, iRegP oldval, iRegP newval, rFlagsReg cr) %{
    -  predicate(needs_acquiring_load_exclusive(n) && (n->as_LoadStore()->barrier_data() == 0));
    -  match(Set res (CompareAndExchangeP mem (Binary oldval newval)));
    -  ins_cost(VOLATILE_REF_COST);
    -  effect(TEMP_DEF res, KILL cr);
    -  format %{
    -    "cmpxchg_acq $res = $mem, $oldval, $newval\t# (ptr, weak) if $mem == $oldval then $mem <-- $newval"
    -  %}
    -  ins_encode %{
    -    __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register,
    -               Assembler::xword, /*acquire*/ true, /*release*/ true,
    -               /*weak*/ false, $res$$Register);
    -  %}
    -  ins_pipe(pipe_slow);
    -%}
    -
    -// This pattern is generated automatically from cas.m4.
    -// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE
    -instruct weakCompareAndSwapB(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{
    -  match(Set res (WeakCompareAndSwapB mem (Binary oldval newval)));
    -  ins_cost(2 * VOLATILE_REF_COST);
    -  effect(KILL cr);
    -  format %{
    -    "cmpxchgb $res = $mem, $oldval, $newval\t# (byte, weak) if $mem == $oldval then $mem <-- $newval"
    -    "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)"
    -  %}
    -  ins_encode %{
    -    __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register,
    -               Assembler::byte, /*acquire*/ false, /*release*/ true,
    -               /*weak*/ true, noreg);
    -    __ csetw($res$$Register, Assembler::EQ);
    -  %}
    -  ins_pipe(pipe_slow);
    -%}
    -
    -// This pattern is generated automatically from cas.m4.
    -// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE
    -instruct weakCompareAndSwapS(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{
    -  match(Set res (WeakCompareAndSwapS mem (Binary oldval newval)));
    -  ins_cost(2 * VOLATILE_REF_COST);
    -  effect(KILL cr);
    -  format %{
    -    "cmpxchgs $res = $mem, $oldval, $newval\t# (short, weak) if $mem == $oldval then $mem <-- $newval"
    -    "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)"
    -  %}
    -  ins_encode %{
    -    __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register,
    -               Assembler::halfword, /*acquire*/ false, /*release*/ true,
    -               /*weak*/ true, noreg);
    -    __ csetw($res$$Register, Assembler::EQ);
    -  %}
    -  ins_pipe(pipe_slow);
    -%}
    -
    -// This pattern is generated automatically from cas.m4.
    -// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE
    -instruct weakCompareAndSwapI(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{
    -  match(Set res (WeakCompareAndSwapI mem (Binary oldval newval)));
    -  ins_cost(2 * VOLATILE_REF_COST);
    -  effect(KILL cr);
    -  format %{
    -    "cmpxchgw $res = $mem, $oldval, $newval\t# (int, weak) if $mem == $oldval then $mem <-- $newval"
    -    "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)"
    -  %}
    -  ins_encode %{
    -    __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register,
    -               Assembler::word, /*acquire*/ false, /*release*/ true,
    -               /*weak*/ true, noreg);
    -    __ csetw($res$$Register, Assembler::EQ);
    -  %}
    -  ins_pipe(pipe_slow);
    -%}
    -
    -// This pattern is generated automatically from cas.m4.
    -// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE
    -instruct weakCompareAndSwapL(iRegINoSp res, indirect mem, iRegL oldval, iRegL newval, rFlagsReg cr) %{
    -  match(Set res (WeakCompareAndSwapL mem (Binary oldval newval)));
    -  ins_cost(2 * VOLATILE_REF_COST);
    -  effect(KILL cr);
    -  format %{
    -    "cmpxchg $res = $mem, $oldval, $newval\t# (long, weak) if $mem == $oldval then $mem <-- $newval"
    -    "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)"
    -  %}
    -  ins_encode %{
    -    __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register,
    -               Assembler::xword, /*acquire*/ false, /*release*/ true,
    -               /*weak*/ true, noreg);
    -    __ csetw($res$$Register, Assembler::EQ);
    -  %}
    -  ins_pipe(pipe_slow);
    -%}
    -
    -// This pattern is generated automatically from cas.m4.
    -// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE
    -instruct weakCompareAndSwapN(iRegINoSp res, indirect mem, iRegN oldval, iRegN newval, rFlagsReg cr) %{
    -  predicate(n->as_LoadStore()->barrier_data() == 0);
    -  match(Set res (WeakCompareAndSwapN mem (Binary oldval newval)));
    -  ins_cost(2 * VOLATILE_REF_COST);
    -  effect(KILL cr);
    -  format %{
    -    "cmpxchgw $res = $mem, $oldval, $newval\t# (narrow oop, weak) if $mem == $oldval then $mem <-- $newval"
    -    "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)"
    -  %}
    -  ins_encode %{
    -    __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register,
    -               Assembler::word, /*acquire*/ false, /*release*/ true,
    -               /*weak*/ true, noreg);
    -    __ csetw($res$$Register, Assembler::EQ);
    -  %}
    -  ins_pipe(pipe_slow);
    -%}
    -
    -// This pattern is generated automatically from cas.m4.
    -// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE
    -instruct weakCompareAndSwapP(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval, rFlagsReg cr) %{
    -  predicate(n->as_LoadStore()->barrier_data() == 0);
    -  match(Set res (WeakCompareAndSwapP mem (Binary oldval newval)));
    -  ins_cost(2 * VOLATILE_REF_COST);
    -  effect(KILL cr);
    -  format %{
    -    "cmpxchg $res = $mem, $oldval, $newval\t# (ptr, weak) if $mem == $oldval then $mem <-- $newval"
    -    "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)"
    -  %}
    -  ins_encode %{
    -    __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register,
    -               Assembler::xword, /*acquire*/ false, /*release*/ true,
    -               /*weak*/ true, noreg);
    -    __ csetw($res$$Register, Assembler::EQ);
    -  %}
    -  ins_pipe(pipe_slow);
    -%}
    -
    -// This pattern is generated automatically from cas.m4.
    -// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE
    -instruct weakCompareAndSwapBAcq(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{
    -  predicate(needs_acquiring_load_exclusive(n));
    -  match(Set res (WeakCompareAndSwapB mem (Binary oldval newval)));
    -  ins_cost(VOLATILE_REF_COST);
    -  effect(KILL cr);
    -  format %{
    -    "cmpxchgb_acq $res = $mem, $oldval, $newval\t# (byte, weak) if $mem == $oldval then $mem <-- $newval"
    -    "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)"
    -  %}
    -  ins_encode %{
    -    __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register,
    -               Assembler::byte, /*acquire*/ true, /*release*/ true,
    -               /*weak*/ true, noreg);
    -    __ csetw($res$$Register, Assembler::EQ);
    -  %}
    -  ins_pipe(pipe_slow);
    -%}
    -
    -// This pattern is generated automatically from cas.m4.
    -// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE
    -instruct weakCompareAndSwapSAcq(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{
    -  predicate(needs_acquiring_load_exclusive(n));
    -  match(Set res (WeakCompareAndSwapS mem (Binary oldval newval)));
    -  ins_cost(VOLATILE_REF_COST);
    -  effect(KILL cr);
    -  format %{
    -    "cmpxchgs_acq $res = $mem, $oldval, $newval\t# (short, weak) if $mem == $oldval then $mem <-- $newval"
    -    "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)"
    -  %}
    -  ins_encode %{
    -    __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register,
    -               Assembler::halfword, /*acquire*/ true, /*release*/ true,
    -               /*weak*/ true, noreg);
    -    __ csetw($res$$Register, Assembler::EQ);
    -  %}
    -  ins_pipe(pipe_slow);
    -%}
    -
    -// This pattern is generated automatically from cas.m4.
    -// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE
    -instruct weakCompareAndSwapIAcq(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{
    -  predicate(needs_acquiring_load_exclusive(n));
    -  match(Set res (WeakCompareAndSwapI mem (Binary oldval newval)));
    -  ins_cost(VOLATILE_REF_COST);
    -  effect(KILL cr);
    -  format %{
    -    "cmpxchgw_acq $res = $mem, $oldval, $newval\t# (int, weak) if $mem == $oldval then $mem <-- $newval"
    -    "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)"
    -  %}
    -  ins_encode %{
    -    __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register,
    -               Assembler::word, /*acquire*/ true, /*release*/ true,
    -               /*weak*/ true, noreg);
    -    __ csetw($res$$Register, Assembler::EQ);
    -  %}
    -  ins_pipe(pipe_slow);
    -%}
    -
    -// This pattern is generated automatically from cas.m4.
    -// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE
    -instruct weakCompareAndSwapLAcq(iRegINoSp res, indirect mem, iRegL oldval, iRegL newval, rFlagsReg cr) %{
    -  predicate(needs_acquiring_load_exclusive(n));
    -  match(Set res (WeakCompareAndSwapL mem (Binary oldval newval)));
    -  ins_cost(VOLATILE_REF_COST);
    -  effect(KILL cr);
    -  format %{
    -    "cmpxchg_acq $res = $mem, $oldval, $newval\t# (long, weak) if $mem == $oldval then $mem <-- $newval"
    -    "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)"
    -  %}
    -  ins_encode %{
    -    __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register,
    -               Assembler::xword, /*acquire*/ true, /*release*/ true,
    -               /*weak*/ true, noreg);
    -    __ csetw($res$$Register, Assembler::EQ);
    -  %}
    -  ins_pipe(pipe_slow);
    -%}
    -
    -// This pattern is generated automatically from cas.m4.
    -// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE
    -instruct weakCompareAndSwapNAcq(iRegINoSp res, indirect mem, iRegN oldval, iRegN newval, rFlagsReg cr) %{
    -  predicate(needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() == 0);
    -  match(Set res (WeakCompareAndSwapN mem (Binary oldval newval)));
    -  ins_cost(VOLATILE_REF_COST);
    -  effect(KILL cr);
    -  format %{
    -    "cmpxchgw_acq $res = $mem, $oldval, $newval\t# (narrow oop, weak) if $mem == $oldval then $mem <-- $newval"
    -    "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)"
    -  %}
    -  ins_encode %{
    -    __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register,
    -               Assembler::word, /*acquire*/ true, /*release*/ true,
    -               /*weak*/ true, noreg);
    -    __ csetw($res$$Register, Assembler::EQ);
    -  %}
    -  ins_pipe(pipe_slow);
    -%}
    -
    -// This pattern is generated automatically from cas.m4.
    -// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE
    -instruct weakCompareAndSwapPAcq(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval, rFlagsReg cr) %{
    -  predicate(needs_acquiring_load_exclusive(n) && (n->as_LoadStore()->barrier_data() == 0));
    -  match(Set res (WeakCompareAndSwapP mem (Binary oldval newval)));
    -  ins_cost(VOLATILE_REF_COST);
    -  effect(KILL cr);
    -  format %{
    -    "cmpxchg_acq $res = $mem, $oldval, $newval\t# (ptr, weak) if $mem == $oldval then $mem <-- $newval"
    -    "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)"
    -  %}
    -  ins_encode %{
    -    __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register,
    -               Assembler::xword, /*acquire*/ true, /*release*/ true,
    -               /*weak*/ true, noreg);
    -    __ csetw($res$$Register, Assembler::EQ);
    -  %}
    -  ins_pipe(pipe_slow);
    -%}
    -
    -// END This section of the file is automatically generated. Do not edit --------------
    -// ---------------------------------------------------------------------
    -
    -instruct get_and_setI(indirect mem, iRegI newv, iRegINoSp prev) %{
    -  match(Set prev (GetAndSetI mem newv));
    -  ins_cost(2 * VOLATILE_REF_COST);
    -  format %{ "atomic_xchgw  $prev, $newv, [$mem]" %}
    -  ins_encode %{
    -    __ atomic_xchgw($prev$$Register, $newv$$Register, as_Register($mem$$base));
    -  %}
    -  ins_pipe(pipe_serial);
    -%}
    -
    -instruct get_and_setL(indirect mem, iRegL newv, iRegLNoSp prev) %{
    -  match(Set prev (GetAndSetL mem newv));
    -  ins_cost(2 * VOLATILE_REF_COST);
    -  format %{ "atomic_xchg  $prev, $newv, [$mem]" %}
    -  ins_encode %{
    -    __ atomic_xchg($prev$$Register, $newv$$Register, as_Register($mem$$base));
    -  %}
    -  ins_pipe(pipe_serial);
    -%}
    -
    -instruct get_and_setN(indirect mem, iRegN newv, iRegINoSp prev) %{
    -  predicate(n->as_LoadStore()->barrier_data() == 0);
    -  match(Set prev (GetAndSetN mem newv));
    -  ins_cost(2 * VOLATILE_REF_COST);
    -  format %{ "atomic_xchgw $prev, $newv, [$mem]" %}
    -  ins_encode %{
    -    __ atomic_xchgw($prev$$Register, $newv$$Register, as_Register($mem$$base));
    -  %}
    -  ins_pipe(pipe_serial);
    -%}
    -
    -instruct get_and_setP(indirect mem, iRegP newv, iRegPNoSp prev) %{
    -  predicate(n->as_LoadStore()->barrier_data() == 0);
    -  match(Set prev (GetAndSetP mem newv));
    -  ins_cost(2 * VOLATILE_REF_COST);
    -  format %{ "atomic_xchg  $prev, $newv, [$mem]" %}
    -  ins_encode %{
    -    __ atomic_xchg($prev$$Register, $newv$$Register, as_Register($mem$$base));
    -  %}
    -  ins_pipe(pipe_serial);
    -%}
    -
    -instruct get_and_setIAcq(indirect mem, iRegI newv, iRegINoSp prev) %{
    -  predicate(needs_acquiring_load_exclusive(n));
    -  match(Set prev (GetAndSetI mem newv));
    -  ins_cost(VOLATILE_REF_COST);
    -  format %{ "atomic_xchgw_acq  $prev, $newv, [$mem]" %}
    -  ins_encode %{
    -    __ atomic_xchgalw($prev$$Register, $newv$$Register, as_Register($mem$$base));
    -  %}
    -  ins_pipe(pipe_serial);
    -%}
    -
    -instruct get_and_setLAcq(indirect mem, iRegL newv, iRegLNoSp prev) %{
    -  predicate(needs_acquiring_load_exclusive(n));
    -  match(Set prev (GetAndSetL mem newv));
    -  ins_cost(VOLATILE_REF_COST);
    -  format %{ "atomic_xchg_acq  $prev, $newv, [$mem]" %}
    -  ins_encode %{
    -    __ atomic_xchgal($prev$$Register, $newv$$Register, as_Register($mem$$base));
    -  %}
    -  ins_pipe(pipe_serial);
    -%}
    -
    -instruct get_and_setNAcq(indirect mem, iRegN newv, iRegINoSp prev) %{
    -  predicate(needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() == 0);
    -  match(Set prev (GetAndSetN mem newv));
    -  ins_cost(VOLATILE_REF_COST);
    -  format %{ "atomic_xchgw_acq $prev, $newv, [$mem]" %}
    -  ins_encode %{
    -    __ atomic_xchgalw($prev$$Register, $newv$$Register, as_Register($mem$$base));
    -  %}
    -  ins_pipe(pipe_serial);
    -%}
    -
    -instruct get_and_setPAcq(indirect mem, iRegP newv, iRegPNoSp prev) %{
    -  predicate(needs_acquiring_load_exclusive(n) && (n->as_LoadStore()->barrier_data() == 0));
    -  match(Set prev (GetAndSetP mem newv));
    -  ins_cost(VOLATILE_REF_COST);
    -  format %{ "atomic_xchg_acq  $prev, $newv, [$mem]" %}
    -  ins_encode %{
    -    __ atomic_xchgal($prev$$Register, $newv$$Register, as_Register($mem$$base));
    -  %}
    -  ins_pipe(pipe_serial);
    -%}
    -
    -
    -instruct get_and_addL(indirect mem, iRegLNoSp newval, iRegL incr) %{
    -  match(Set newval (GetAndAddL mem incr));
    -  ins_cost(2 * VOLATILE_REF_COST + 1);
    -  format %{ "get_and_addL $newval, [$mem], $incr" %}
    -  ins_encode %{
    -    __ atomic_add($newval$$Register, $incr$$Register, as_Register($mem$$base));
    -  %}
    -  ins_pipe(pipe_serial);
    -%}
    -
    -instruct get_and_addL_no_res(indirect mem, Universe dummy, iRegL incr) %{
    -  predicate(n->as_LoadStore()->result_not_used());
    -  match(Set dummy (GetAndAddL mem incr));
    -  ins_cost(2 * VOLATILE_REF_COST);
    -  format %{ "get_and_addL [$mem], $incr" %}
    -  ins_encode %{
    -    __ atomic_add(noreg, $incr$$Register, as_Register($mem$$base));
    -  %}
    -  ins_pipe(pipe_serial);
    -%}
    -
    -instruct get_and_addLi(indirect mem, iRegLNoSp newval, immLAddSub incr) %{
    -  match(Set newval (GetAndAddL mem incr));
    -  ins_cost(2 * VOLATILE_REF_COST + 1);
    -  format %{ "get_and_addL $newval, [$mem], $incr" %}
    -  ins_encode %{
    -    __ atomic_add($newval$$Register, $incr$$constant, as_Register($mem$$base));
    -  %}
    -  ins_pipe(pipe_serial);
    -%}
    -
    -instruct get_and_addLi_no_res(indirect mem, Universe dummy, immLAddSub incr) %{
    -  predicate(n->as_LoadStore()->result_not_used());
    -  match(Set dummy (GetAndAddL mem incr));
    -  ins_cost(2 * VOLATILE_REF_COST);
    -  format %{ "get_and_addL [$mem], $incr" %}
    -  ins_encode %{
    -    __ atomic_add(noreg, $incr$$constant, as_Register($mem$$base));
    -  %}
    -  ins_pipe(pipe_serial);
    -%}
    -
    -instruct get_and_addI(indirect mem, iRegINoSp newval, iRegIorL2I incr) %{
    -  match(Set newval (GetAndAddI mem incr));
    -  ins_cost(2 * VOLATILE_REF_COST + 1);
    -  format %{ "get_and_addI $newval, [$mem], $incr" %}
    -  ins_encode %{
    -    __ atomic_addw($newval$$Register, $incr$$Register, as_Register($mem$$base));
    -  %}
    -  ins_pipe(pipe_serial);
    -%}
    -
    -instruct get_and_addI_no_res(indirect mem, Universe dummy, iRegIorL2I incr) %{
    -  predicate(n->as_LoadStore()->result_not_used());
    -  match(Set dummy (GetAndAddI mem incr));
    -  ins_cost(2 * VOLATILE_REF_COST);
    -  format %{ "get_and_addI [$mem], $incr" %}
    -  ins_encode %{
    -    __ atomic_addw(noreg, $incr$$Register, as_Register($mem$$base));
    -  %}
    -  ins_pipe(pipe_serial);
    -%}
    -
    -instruct get_and_addIi(indirect mem, iRegINoSp newval, immIAddSub incr) %{
    -  match(Set newval (GetAndAddI mem incr));
    -  ins_cost(2 * VOLATILE_REF_COST + 1);
    -  format %{ "get_and_addI $newval, [$mem], $incr" %}
    -  ins_encode %{
    -    __ atomic_addw($newval$$Register, $incr$$constant, as_Register($mem$$base));
    -  %}
    -  ins_pipe(pipe_serial);
    -%}
    -
    -instruct get_and_addIi_no_res(indirect mem, Universe dummy, immIAddSub incr) %{
    -  predicate(n->as_LoadStore()->result_not_used());
    -  match(Set dummy (GetAndAddI mem incr));
    -  ins_cost(2 * VOLATILE_REF_COST);
    -  format %{ "get_and_addI [$mem], $incr" %}
    -  ins_encode %{
    -    __ atomic_addw(noreg, $incr$$constant, as_Register($mem$$base));
    -  %}
    -  ins_pipe(pipe_serial);
    -%}
    -
    -instruct get_and_addLAcq(indirect mem, iRegLNoSp newval, iRegL incr) %{
    -  predicate(needs_acquiring_load_exclusive(n));
    -  match(Set newval (GetAndAddL mem incr));
    -  ins_cost(VOLATILE_REF_COST + 1);
    -  format %{ "get_and_addL_acq $newval, [$mem], $incr" %}
    -  ins_encode %{
    -    __ atomic_addal($newval$$Register, $incr$$Register, as_Register($mem$$base));
    -  %}
    -  ins_pipe(pipe_serial);
    -%}
    -
    -instruct get_and_addL_no_resAcq(indirect mem, Universe dummy, iRegL incr) %{
    -  predicate(n->as_LoadStore()->result_not_used() && needs_acquiring_load_exclusive(n));
    -  match(Set dummy (GetAndAddL mem incr));
    -  ins_cost(VOLATILE_REF_COST);
    -  format %{ "get_and_addL_acq [$mem], $incr" %}
    -  ins_encode %{
    -    __ atomic_addal(noreg, $incr$$Register, as_Register($mem$$base));
    -  %}
    -  ins_pipe(pipe_serial);
    -%}
    -
    -instruct get_and_addLiAcq(indirect mem, iRegLNoSp newval, immLAddSub incr) %{
    -  predicate(needs_acquiring_load_exclusive(n));
    -  match(Set newval (GetAndAddL mem incr));
    -  ins_cost(VOLATILE_REF_COST + 1);
    -  format %{ "get_and_addL_acq $newval, [$mem], $incr" %}
    -  ins_encode %{
    -    __ atomic_addal($newval$$Register, $incr$$constant, as_Register($mem$$base));
    -  %}
    -  ins_pipe(pipe_serial);
    -%}
    -
    -instruct get_and_addLi_no_resAcq(indirect mem, Universe dummy, immLAddSub incr) %{
    -  predicate(n->as_LoadStore()->result_not_used() && needs_acquiring_load_exclusive(n));
    -  match(Set dummy (GetAndAddL mem incr));
    -  ins_cost(VOLATILE_REF_COST);
    -  format %{ "get_and_addL_acq [$mem], $incr" %}
    -  ins_encode %{
    -    __ atomic_addal(noreg, $incr$$constant, as_Register($mem$$base));
    -  %}
    -  ins_pipe(pipe_serial);
    -%}
    -
    -instruct get_and_addIAcq(indirect mem, iRegINoSp newval, iRegIorL2I incr) %{
    -  predicate(needs_acquiring_load_exclusive(n));
    -  match(Set newval (GetAndAddI mem incr));
    -  ins_cost(VOLATILE_REF_COST + 1);
    -  format %{ "get_and_addI_acq $newval, [$mem], $incr" %}
    -  ins_encode %{
    -    __ atomic_addalw($newval$$Register, $incr$$Register, as_Register($mem$$base));
    -  %}
    -  ins_pipe(pipe_serial);
    -%}
    -
    -instruct get_and_addI_no_resAcq(indirect mem, Universe dummy, iRegIorL2I incr) %{
    -  predicate(n->as_LoadStore()->result_not_used() && needs_acquiring_load_exclusive(n));
    -  match(Set dummy (GetAndAddI mem incr));
    -  ins_cost(VOLATILE_REF_COST);
    -  format %{ "get_and_addI_acq [$mem], $incr" %}
    -  ins_encode %{
    -    __ atomic_addalw(noreg, $incr$$Register, as_Register($mem$$base));
    -  %}
    -  ins_pipe(pipe_serial);
    -%}
    -
    -instruct get_and_addIiAcq(indirect mem, iRegINoSp newval, immIAddSub incr) %{
    -  predicate(needs_acquiring_load_exclusive(n));
    -  match(Set newval (GetAndAddI mem incr));
    -  ins_cost(VOLATILE_REF_COST + 1);
    -  format %{ "get_and_addI_acq $newval, [$mem], $incr" %}
    -  ins_encode %{
    -    __ atomic_addalw($newval$$Register, $incr$$constant, as_Register($mem$$base));
    -  %}
    -  ins_pipe(pipe_serial);
    -%}
    -
    -instruct get_and_addIi_no_resAcq(indirect mem, Universe dummy, immIAddSub incr) %{
    -  predicate(n->as_LoadStore()->result_not_used() && needs_acquiring_load_exclusive(n));
    -  match(Set dummy (GetAndAddI mem incr));
    -  ins_cost(VOLATILE_REF_COST);
    -  format %{ "get_and_addI_acq [$mem], $incr" %}
    -  ins_encode %{
    -    __ atomic_addalw(noreg, $incr$$constant, as_Register($mem$$base));
    -  %}
    -  ins_pipe(pipe_serial);
    -%}
    -
     // Manifest a CmpU result in an integer register.
     // (src1 < src2) ? -1 : ((src1 > src2) ? 1 : 0)
     instruct cmpU3_reg_reg(iRegINoSp dst, iRegI src1, iRegI src2, rFlagsReg flags)
    diff --git a/src/hotspot/cpu/aarch64/aarch64_atomic.ad b/src/hotspot/cpu/aarch64/aarch64_atomic.ad
    new file mode 100644
    index 00000000000..faac2a43110
    --- /dev/null
    +++ b/src/hotspot/cpu/aarch64/aarch64_atomic.ad
    @@ -0,0 +1,909 @@
    +// Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved.
    +// Copyright (c) 2016, 2021, Red Hat Inc. 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.
    +//
    +//
    +
    +// BEGIN This file is automatically generated. Do not edit --------------
    +
    +// Sundry CAS operations.  Note that release is always true,
    +// regardless of the memory ordering of the CAS.  This is because we
    +// need the volatile case to be sequentially consistent but there is
    +// no trailing StoreLoad barrier emitted by C2.  Unfortunately we
    +// can't check the type of memory ordering here, so we always emit a
    +// STLXR.
    +
    +// This section is generated from aarch64_atomic_ad.m4
    +
    +
    +instruct compareAndExchangeB(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{
    +  match(Set res (CompareAndExchangeB mem (Binary oldval newval)));
    +  ins_cost(2*VOLATILE_REF_COST);
    +  effect(TEMP_DEF res, KILL cr);
    +  format %{
    +    "cmpxchgb $res = $mem, $oldval, $newval\t# (byte) if $mem == $oldval then $mem <-- $newval"
    +  %}
    +  ins_encode %{
    +    __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register,
    +               Assembler::byte, /*acquire*/ false, /*release*/ true,
    +               /*weak*/ false, $res$$Register);
    +    __ sxtbw($res$$Register, $res$$Register);
    +  %}
    +  ins_pipe(pipe_slow);
    +%}
    +
    +instruct compareAndExchangeS(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{
    +  match(Set res (CompareAndExchangeS mem (Binary oldval newval)));
    +  ins_cost(2*VOLATILE_REF_COST);
    +  effect(TEMP_DEF res, KILL cr);
    +  format %{
    +    "cmpxchgs $res = $mem, $oldval, $newval\t# (short) if $mem == $oldval then $mem <-- $newval"
    +  %}
    +  ins_encode %{
    +    __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register,
    +               Assembler::halfword, /*acquire*/ false, /*release*/ true,
    +               /*weak*/ false, $res$$Register);
    +    __ sxthw($res$$Register, $res$$Register);
    +  %}
    +  ins_pipe(pipe_slow);
    +%}
    +
    +instruct compareAndExchangeI(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{
    +  match(Set res (CompareAndExchangeI mem (Binary oldval newval)));
    +  ins_cost(2*VOLATILE_REF_COST);
    +  effect(TEMP_DEF res, KILL cr);
    +  format %{
    +    "cmpxchgw $res = $mem, $oldval, $newval\t# (int) if $mem == $oldval then $mem <-- $newval"
    +  %}
    +  ins_encode %{
    +    __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register,
    +               Assembler::word, /*acquire*/ false, /*release*/ true,
    +               /*weak*/ false, $res$$Register);
    +  %}
    +  ins_pipe(pipe_slow);
    +%}
    +
    +instruct compareAndExchangeL(iRegLNoSp res, indirect mem, iRegL oldval, iRegL newval, rFlagsReg cr) %{
    +  match(Set res (CompareAndExchangeL mem (Binary oldval newval)));
    +  ins_cost(2*VOLATILE_REF_COST);
    +  effect(TEMP_DEF res, KILL cr);
    +  format %{
    +    "cmpxchg $res = $mem, $oldval, $newval\t# (long) if $mem == $oldval then $mem <-- $newval"
    +  %}
    +  ins_encode %{
    +    __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register,
    +               Assembler::xword, /*acquire*/ false, /*release*/ true,
    +               /*weak*/ false, $res$$Register);
    +  %}
    +  ins_pipe(pipe_slow);
    +%}
    +
    +instruct compareAndExchangeN(iRegNNoSp res, indirect mem, iRegN oldval, iRegN newval, rFlagsReg cr) %{
    +  predicate(n->as_LoadStore()->barrier_data() == 0);
    +  match(Set res (CompareAndExchangeN mem (Binary oldval newval)));
    +  ins_cost(2*VOLATILE_REF_COST);
    +  effect(TEMP_DEF res, KILL cr);
    +  format %{
    +    "cmpxchgw $res = $mem, $oldval, $newval\t# (narrow oop) if $mem == $oldval then $mem <-- $newval"
    +  %}
    +  ins_encode %{
    +    __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register,
    +               Assembler::word, /*acquire*/ false, /*release*/ true,
    +               /*weak*/ false, $res$$Register);
    +  %}
    +  ins_pipe(pipe_slow);
    +%}
    +
    +instruct compareAndExchangeP(iRegPNoSp res, indirect mem, iRegP oldval, iRegP newval, rFlagsReg cr) %{
    +  predicate(n->as_LoadStore()->barrier_data() == 0);
    +  match(Set res (CompareAndExchangeP mem (Binary oldval newval)));
    +  ins_cost(2*VOLATILE_REF_COST);
    +  effect(TEMP_DEF res, KILL cr);
    +  format %{
    +    "cmpxchg $res = $mem, $oldval, $newval\t# (ptr) if $mem == $oldval then $mem <-- $newval"
    +  %}
    +  ins_encode %{
    +    __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register,
    +               Assembler::xword, /*acquire*/ false, /*release*/ true,
    +               /*weak*/ false, $res$$Register);
    +  %}
    +  ins_pipe(pipe_slow);
    +%}
    +
    +instruct compareAndExchangeBAcq(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{
    +  predicate(needs_acquiring_load_exclusive(n));
    +  match(Set res (CompareAndExchangeB mem (Binary oldval newval)));
    +  ins_cost(VOLATILE_REF_COST);
    +  effect(TEMP_DEF res, KILL cr);
    +  format %{
    +    "cmpxchgb_acq $res = $mem, $oldval, $newval\t# (byte) if $mem == $oldval then $mem <-- $newval"
    +  %}
    +  ins_encode %{
    +    __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register,
    +               Assembler::byte, /*acquire*/ true, /*release*/ true,
    +               /*weak*/ false, $res$$Register);
    +    __ sxtbw($res$$Register, $res$$Register);
    +  %}
    +  ins_pipe(pipe_slow);
    +%}
    +
    +instruct compareAndExchangeSAcq(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{
    +  predicate(needs_acquiring_load_exclusive(n));
    +  match(Set res (CompareAndExchangeS mem (Binary oldval newval)));
    +  ins_cost(VOLATILE_REF_COST);
    +  effect(TEMP_DEF res, KILL cr);
    +  format %{
    +    "cmpxchgs_acq $res = $mem, $oldval, $newval\t# (short) if $mem == $oldval then $mem <-- $newval"
    +  %}
    +  ins_encode %{
    +    __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register,
    +               Assembler::halfword, /*acquire*/ true, /*release*/ true,
    +               /*weak*/ false, $res$$Register);
    +    __ sxthw($res$$Register, $res$$Register);
    +  %}
    +  ins_pipe(pipe_slow);
    +%}
    +
    +instruct compareAndExchangeIAcq(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{
    +  predicate(needs_acquiring_load_exclusive(n));
    +  match(Set res (CompareAndExchangeI mem (Binary oldval newval)));
    +  ins_cost(VOLATILE_REF_COST);
    +  effect(TEMP_DEF res, KILL cr);
    +  format %{
    +    "cmpxchgw_acq $res = $mem, $oldval, $newval\t# (int) if $mem == $oldval then $mem <-- $newval"
    +  %}
    +  ins_encode %{
    +    __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register,
    +               Assembler::word, /*acquire*/ true, /*release*/ true,
    +               /*weak*/ false, $res$$Register);
    +  %}
    +  ins_pipe(pipe_slow);
    +%}
    +
    +instruct compareAndExchangeLAcq(iRegLNoSp res, indirect mem, iRegL oldval, iRegL newval, rFlagsReg cr) %{
    +  predicate(needs_acquiring_load_exclusive(n));
    +  match(Set res (CompareAndExchangeL mem (Binary oldval newval)));
    +  ins_cost(VOLATILE_REF_COST);
    +  effect(TEMP_DEF res, KILL cr);
    +  format %{
    +    "cmpxchg_acq $res = $mem, $oldval, $newval\t# (long) if $mem == $oldval then $mem <-- $newval"
    +  %}
    +  ins_encode %{
    +    __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register,
    +               Assembler::xword, /*acquire*/ true, /*release*/ true,
    +               /*weak*/ false, $res$$Register);
    +  %}
    +  ins_pipe(pipe_slow);
    +%}
    +
    +instruct compareAndExchangeNAcq(iRegNNoSp res, indirect mem, iRegN oldval, iRegN newval, rFlagsReg cr) %{
    +  predicate(needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() == 0);
    +  match(Set res (CompareAndExchangeN mem (Binary oldval newval)));
    +  ins_cost(VOLATILE_REF_COST);
    +  effect(TEMP_DEF res, KILL cr);
    +  format %{
    +    "cmpxchgw_acq $res = $mem, $oldval, $newval\t# (narrow oop) if $mem == $oldval then $mem <-- $newval"
    +  %}
    +  ins_encode %{
    +    __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register,
    +               Assembler::word, /*acquire*/ true, /*release*/ true,
    +               /*weak*/ false, $res$$Register);
    +  %}
    +  ins_pipe(pipe_slow);
    +%}
    +
    +instruct compareAndExchangePAcq(iRegPNoSp res, indirect mem, iRegP oldval, iRegP newval, rFlagsReg cr) %{
    +  predicate(needs_acquiring_load_exclusive(n) && (n->as_LoadStore()->barrier_data() == 0));
    +  match(Set res (CompareAndExchangeP mem (Binary oldval newval)));
    +  ins_cost(VOLATILE_REF_COST);
    +  effect(TEMP_DEF res, KILL cr);
    +  format %{
    +    "cmpxchg_acq $res = $mem, $oldval, $newval\t# (ptr) if $mem == $oldval then $mem <-- $newval"
    +  %}
    +  ins_encode %{
    +    __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register,
    +               Assembler::xword, /*acquire*/ true, /*release*/ true,
    +               /*weak*/ false, $res$$Register);
    +  %}
    +  ins_pipe(pipe_slow);
    +%}
    +
    +instruct compareAndSwapB(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{
    +  match(Set res (CompareAndSwapB mem (Binary oldval newval)));
    +  ins_cost(2*VOLATILE_REF_COST);
    +  effect(KILL cr);
    +  format %{
    +    "cmpxchgb $res = $mem, $oldval, $newval\t# (byte) if $mem == $oldval then $mem <-- $newval"
    +    "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)"
    +  %}
    +  ins_encode %{
    +    __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register,
    +               Assembler::byte, /*acquire*/ false, /*release*/ true,
    +               /*weak*/ false, noreg);
    +    __ csetw($res$$Register, Assembler::EQ);
    +  %}
    +  ins_pipe(pipe_slow);
    +%}
    +
    +instruct compareAndSwapS(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{
    +  match(Set res (CompareAndSwapS mem (Binary oldval newval)));
    +  ins_cost(2*VOLATILE_REF_COST);
    +  effect(KILL cr);
    +  format %{
    +    "cmpxchgs $res = $mem, $oldval, $newval\t# (short) if $mem == $oldval then $mem <-- $newval"
    +    "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)"
    +  %}
    +  ins_encode %{
    +    __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register,
    +               Assembler::halfword, /*acquire*/ false, /*release*/ true,
    +               /*weak*/ false, noreg);
    +    __ csetw($res$$Register, Assembler::EQ);
    +  %}
    +  ins_pipe(pipe_slow);
    +%}
    +
    +instruct compareAndSwapI(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{
    +  match(Set res (CompareAndSwapI mem (Binary oldval newval)));
    +  ins_cost(2*VOLATILE_REF_COST);
    +  effect(KILL cr);
    +  format %{
    +    "cmpxchgw $res = $mem, $oldval, $newval\t# (int) if $mem == $oldval then $mem <-- $newval"
    +    "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)"
    +  %}
    +  ins_encode %{
    +    __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register,
    +               Assembler::word, /*acquire*/ false, /*release*/ true,
    +               /*weak*/ false, noreg);
    +    __ csetw($res$$Register, Assembler::EQ);
    +  %}
    +  ins_pipe(pipe_slow);
    +%}
    +
    +instruct compareAndSwapL(iRegINoSp res, indirect mem, iRegL oldval, iRegL newval, rFlagsReg cr) %{
    +  match(Set res (CompareAndSwapL mem (Binary oldval newval)));
    +  ins_cost(2*VOLATILE_REF_COST);
    +  effect(KILL cr);
    +  format %{
    +    "cmpxchg $res = $mem, $oldval, $newval\t# (long) if $mem == $oldval then $mem <-- $newval"
    +    "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)"
    +  %}
    +  ins_encode %{
    +    __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register,
    +               Assembler::xword, /*acquire*/ false, /*release*/ true,
    +               /*weak*/ false, noreg);
    +    __ csetw($res$$Register, Assembler::EQ);
    +  %}
    +  ins_pipe(pipe_slow);
    +%}
    +
    +instruct compareAndSwapN(iRegINoSp res, indirect mem, iRegN oldval, iRegN newval, rFlagsReg cr) %{
    +  predicate(n->as_LoadStore()->barrier_data() == 0);
    +  match(Set res (CompareAndSwapN mem (Binary oldval newval)));
    +  ins_cost(2*VOLATILE_REF_COST);
    +  effect(KILL cr);
    +  format %{
    +    "cmpxchgw $res = $mem, $oldval, $newval\t# (narrow oop) if $mem == $oldval then $mem <-- $newval"
    +    "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)"
    +  %}
    +  ins_encode %{
    +    __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register,
    +               Assembler::word, /*acquire*/ false, /*release*/ true,
    +               /*weak*/ false, noreg);
    +    __ csetw($res$$Register, Assembler::EQ);
    +  %}
    +  ins_pipe(pipe_slow);
    +%}
    +
    +instruct compareAndSwapP(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval, rFlagsReg cr) %{
    +  predicate(n->as_LoadStore()->barrier_data() == 0);
    +  match(Set res (CompareAndSwapP mem (Binary oldval newval)));
    +  ins_cost(2*VOLATILE_REF_COST);
    +  effect(KILL cr);
    +  format %{
    +    "cmpxchg $res = $mem, $oldval, $newval\t# (ptr) if $mem == $oldval then $mem <-- $newval"
    +    "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)"
    +  %}
    +  ins_encode %{
    +    __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register,
    +               Assembler::xword, /*acquire*/ false, /*release*/ true,
    +               /*weak*/ false, noreg);
    +    __ csetw($res$$Register, Assembler::EQ);
    +  %}
    +  ins_pipe(pipe_slow);
    +%}
    +
    +instruct compareAndSwapBAcq(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{
    +  predicate(needs_acquiring_load_exclusive(n));
    +  match(Set res (CompareAndSwapB mem (Binary oldval newval)));
    +  ins_cost(VOLATILE_REF_COST);
    +  effect(KILL cr);
    +  format %{
    +    "cmpxchgb_acq $res = $mem, $oldval, $newval\t# (byte) if $mem == $oldval then $mem <-- $newval"
    +    "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)"
    +  %}
    +  ins_encode %{
    +    __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register,
    +               Assembler::byte, /*acquire*/ true, /*release*/ true,
    +               /*weak*/ false, noreg);
    +    __ csetw($res$$Register, Assembler::EQ);
    +  %}
    +  ins_pipe(pipe_slow);
    +%}
    +
    +instruct compareAndSwapSAcq(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{
    +  predicate(needs_acquiring_load_exclusive(n));
    +  match(Set res (CompareAndSwapS mem (Binary oldval newval)));
    +  ins_cost(VOLATILE_REF_COST);
    +  effect(KILL cr);
    +  format %{
    +    "cmpxchgs_acq $res = $mem, $oldval, $newval\t# (short) if $mem == $oldval then $mem <-- $newval"
    +    "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)"
    +  %}
    +  ins_encode %{
    +    __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register,
    +               Assembler::halfword, /*acquire*/ true, /*release*/ true,
    +               /*weak*/ false, noreg);
    +    __ csetw($res$$Register, Assembler::EQ);
    +  %}
    +  ins_pipe(pipe_slow);
    +%}
    +
    +instruct compareAndSwapIAcq(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{
    +  predicate(needs_acquiring_load_exclusive(n));
    +  match(Set res (CompareAndSwapI mem (Binary oldval newval)));
    +  ins_cost(VOLATILE_REF_COST);
    +  effect(KILL cr);
    +  format %{
    +    "cmpxchgw_acq $res = $mem, $oldval, $newval\t# (int) if $mem == $oldval then $mem <-- $newval"
    +    "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)"
    +  %}
    +  ins_encode %{
    +    __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register,
    +               Assembler::word, /*acquire*/ true, /*release*/ true,
    +               /*weak*/ false, noreg);
    +    __ csetw($res$$Register, Assembler::EQ);
    +  %}
    +  ins_pipe(pipe_slow);
    +%}
    +
    +instruct compareAndSwapLAcq(iRegINoSp res, indirect mem, iRegL oldval, iRegL newval, rFlagsReg cr) %{
    +  predicate(needs_acquiring_load_exclusive(n));
    +  match(Set res (CompareAndSwapL mem (Binary oldval newval)));
    +  ins_cost(VOLATILE_REF_COST);
    +  effect(KILL cr);
    +  format %{
    +    "cmpxchg_acq $res = $mem, $oldval, $newval\t# (long) if $mem == $oldval then $mem <-- $newval"
    +    "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)"
    +  %}
    +  ins_encode %{
    +    __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register,
    +               Assembler::xword, /*acquire*/ true, /*release*/ true,
    +               /*weak*/ false, noreg);
    +    __ csetw($res$$Register, Assembler::EQ);
    +  %}
    +  ins_pipe(pipe_slow);
    +%}
    +
    +instruct compareAndSwapNAcq(iRegINoSp res, indirect mem, iRegN oldval, iRegN newval, rFlagsReg cr) %{
    +  predicate(needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() == 0);
    +  match(Set res (CompareAndSwapN mem (Binary oldval newval)));
    +  ins_cost(VOLATILE_REF_COST);
    +  effect(KILL cr);
    +  format %{
    +    "cmpxchgw_acq $res = $mem, $oldval, $newval\t# (narrow oop) if $mem == $oldval then $mem <-- $newval"
    +    "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)"
    +  %}
    +  ins_encode %{
    +    __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register,
    +               Assembler::word, /*acquire*/ true, /*release*/ true,
    +               /*weak*/ false, noreg);
    +    __ csetw($res$$Register, Assembler::EQ);
    +  %}
    +  ins_pipe(pipe_slow);
    +%}
    +
    +instruct compareAndSwapPAcq(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval, rFlagsReg cr) %{
    +  predicate(needs_acquiring_load_exclusive(n) && (n->as_LoadStore()->barrier_data() == 0));
    +  match(Set res (CompareAndSwapP mem (Binary oldval newval)));
    +  ins_cost(VOLATILE_REF_COST);
    +  effect(KILL cr);
    +  format %{
    +    "cmpxchg_acq $res = $mem, $oldval, $newval\t# (ptr) if $mem == $oldval then $mem <-- $newval"
    +    "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)"
    +  %}
    +  ins_encode %{
    +    __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register,
    +               Assembler::xword, /*acquire*/ true, /*release*/ true,
    +               /*weak*/ false, noreg);
    +    __ csetw($res$$Register, Assembler::EQ);
    +  %}
    +  ins_pipe(pipe_slow);
    +%}
    +
    +instruct weakCompareAndSwapB(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{
    +  match(Set res (WeakCompareAndSwapB mem (Binary oldval newval)));
    +  ins_cost(2*VOLATILE_REF_COST);
    +  effect(KILL cr);
    +  format %{
    +    "cmpxchgb_weak $res = $mem, $oldval, $newval\t# (byte) if $mem == $oldval then $mem <-- $newval"
    +    "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)"
    +  %}
    +  ins_encode %{
    +    __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register,
    +               Assembler::byte, /*acquire*/ false, /*release*/ true,
    +               /*weak*/ true, noreg);
    +    __ csetw($res$$Register, Assembler::EQ);
    +  %}
    +  ins_pipe(pipe_slow);
    +%}
    +
    +instruct weakCompareAndSwapS(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{
    +  match(Set res (WeakCompareAndSwapS mem (Binary oldval newval)));
    +  ins_cost(2*VOLATILE_REF_COST);
    +  effect(KILL cr);
    +  format %{
    +    "cmpxchgs_weak $res = $mem, $oldval, $newval\t# (short) if $mem == $oldval then $mem <-- $newval"
    +    "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)"
    +  %}
    +  ins_encode %{
    +    __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register,
    +               Assembler::halfword, /*acquire*/ false, /*release*/ true,
    +               /*weak*/ true, noreg);
    +    __ csetw($res$$Register, Assembler::EQ);
    +  %}
    +  ins_pipe(pipe_slow);
    +%}
    +
    +instruct weakCompareAndSwapI(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{
    +  match(Set res (WeakCompareAndSwapI mem (Binary oldval newval)));
    +  ins_cost(2*VOLATILE_REF_COST);
    +  effect(KILL cr);
    +  format %{
    +    "cmpxchgw_weak $res = $mem, $oldval, $newval\t# (int) if $mem == $oldval then $mem <-- $newval"
    +    "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)"
    +  %}
    +  ins_encode %{
    +    __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register,
    +               Assembler::word, /*acquire*/ false, /*release*/ true,
    +               /*weak*/ true, noreg);
    +    __ csetw($res$$Register, Assembler::EQ);
    +  %}
    +  ins_pipe(pipe_slow);
    +%}
    +
    +instruct weakCompareAndSwapL(iRegINoSp res, indirect mem, iRegL oldval, iRegL newval, rFlagsReg cr) %{
    +  match(Set res (WeakCompareAndSwapL mem (Binary oldval newval)));
    +  ins_cost(2*VOLATILE_REF_COST);
    +  effect(KILL cr);
    +  format %{
    +    "cmpxchg_weak $res = $mem, $oldval, $newval\t# (long) if $mem == $oldval then $mem <-- $newval"
    +    "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)"
    +  %}
    +  ins_encode %{
    +    __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register,
    +               Assembler::xword, /*acquire*/ false, /*release*/ true,
    +               /*weak*/ true, noreg);
    +    __ csetw($res$$Register, Assembler::EQ);
    +  %}
    +  ins_pipe(pipe_slow);
    +%}
    +
    +instruct weakCompareAndSwapN(iRegINoSp res, indirect mem, iRegN oldval, iRegN newval, rFlagsReg cr) %{
    +  predicate(n->as_LoadStore()->barrier_data() == 0);
    +  match(Set res (WeakCompareAndSwapN mem (Binary oldval newval)));
    +  ins_cost(2*VOLATILE_REF_COST);
    +  effect(KILL cr);
    +  format %{
    +    "cmpxchgw_weak $res = $mem, $oldval, $newval\t# (narrow oop) if $mem == $oldval then $mem <-- $newval"
    +    "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)"
    +  %}
    +  ins_encode %{
    +    __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register,
    +               Assembler::word, /*acquire*/ false, /*release*/ true,
    +               /*weak*/ true, noreg);
    +    __ csetw($res$$Register, Assembler::EQ);
    +  %}
    +  ins_pipe(pipe_slow);
    +%}
    +
    +instruct weakCompareAndSwapP(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval, rFlagsReg cr) %{
    +  predicate(n->as_LoadStore()->barrier_data() == 0);
    +  match(Set res (WeakCompareAndSwapP mem (Binary oldval newval)));
    +  ins_cost(2*VOLATILE_REF_COST);
    +  effect(KILL cr);
    +  format %{
    +    "cmpxchg_weak $res = $mem, $oldval, $newval\t# (ptr) if $mem == $oldval then $mem <-- $newval"
    +    "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)"
    +  %}
    +  ins_encode %{
    +    __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register,
    +               Assembler::xword, /*acquire*/ false, /*release*/ true,
    +               /*weak*/ true, noreg);
    +    __ csetw($res$$Register, Assembler::EQ);
    +  %}
    +  ins_pipe(pipe_slow);
    +%}
    +
    +instruct weakCompareAndSwapBAcq(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{
    +  predicate(needs_acquiring_load_exclusive(n));
    +  match(Set res (WeakCompareAndSwapB mem (Binary oldval newval)));
    +  ins_cost(VOLATILE_REF_COST);
    +  effect(KILL cr);
    +  format %{
    +    "cmpxchgb_acq_weak $res = $mem, $oldval, $newval\t# (byte) if $mem == $oldval then $mem <-- $newval"
    +    "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)"
    +  %}
    +  ins_encode %{
    +    __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register,
    +               Assembler::byte, /*acquire*/ true, /*release*/ true,
    +               /*weak*/ true, noreg);
    +    __ csetw($res$$Register, Assembler::EQ);
    +  %}
    +  ins_pipe(pipe_slow);
    +%}
    +
    +instruct weakCompareAndSwapSAcq(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{
    +  predicate(needs_acquiring_load_exclusive(n));
    +  match(Set res (WeakCompareAndSwapS mem (Binary oldval newval)));
    +  ins_cost(VOLATILE_REF_COST);
    +  effect(KILL cr);
    +  format %{
    +    "cmpxchgs_acq_weak $res = $mem, $oldval, $newval\t# (short) if $mem == $oldval then $mem <-- $newval"
    +    "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)"
    +  %}
    +  ins_encode %{
    +    __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register,
    +               Assembler::halfword, /*acquire*/ true, /*release*/ true,
    +               /*weak*/ true, noreg);
    +    __ csetw($res$$Register, Assembler::EQ);
    +  %}
    +  ins_pipe(pipe_slow);
    +%}
    +
    +instruct weakCompareAndSwapIAcq(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{
    +  predicate(needs_acquiring_load_exclusive(n));
    +  match(Set res (WeakCompareAndSwapI mem (Binary oldval newval)));
    +  ins_cost(VOLATILE_REF_COST);
    +  effect(KILL cr);
    +  format %{
    +    "cmpxchgw_acq_weak $res = $mem, $oldval, $newval\t# (int) if $mem == $oldval then $mem <-- $newval"
    +    "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)"
    +  %}
    +  ins_encode %{
    +    __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register,
    +               Assembler::word, /*acquire*/ true, /*release*/ true,
    +               /*weak*/ true, noreg);
    +    __ csetw($res$$Register, Assembler::EQ);
    +  %}
    +  ins_pipe(pipe_slow);
    +%}
    +
    +instruct weakCompareAndSwapLAcq(iRegINoSp res, indirect mem, iRegL oldval, iRegL newval, rFlagsReg cr) %{
    +  predicate(needs_acquiring_load_exclusive(n));
    +  match(Set res (WeakCompareAndSwapL mem (Binary oldval newval)));
    +  ins_cost(VOLATILE_REF_COST);
    +  effect(KILL cr);
    +  format %{
    +    "cmpxchg_acq_weak $res = $mem, $oldval, $newval\t# (long) if $mem == $oldval then $mem <-- $newval"
    +    "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)"
    +  %}
    +  ins_encode %{
    +    __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register,
    +               Assembler::xword, /*acquire*/ true, /*release*/ true,
    +               /*weak*/ true, noreg);
    +    __ csetw($res$$Register, Assembler::EQ);
    +  %}
    +  ins_pipe(pipe_slow);
    +%}
    +
    +instruct weakCompareAndSwapNAcq(iRegINoSp res, indirect mem, iRegN oldval, iRegN newval, rFlagsReg cr) %{
    +  predicate(needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() == 0);
    +  match(Set res (WeakCompareAndSwapN mem (Binary oldval newval)));
    +  ins_cost(VOLATILE_REF_COST);
    +  effect(KILL cr);
    +  format %{
    +    "cmpxchgw_acq_weak $res = $mem, $oldval, $newval\t# (narrow oop) if $mem == $oldval then $mem <-- $newval"
    +    "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)"
    +  %}
    +  ins_encode %{
    +    __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register,
    +               Assembler::word, /*acquire*/ true, /*release*/ true,
    +               /*weak*/ true, noreg);
    +    __ csetw($res$$Register, Assembler::EQ);
    +  %}
    +  ins_pipe(pipe_slow);
    +%}
    +
    +instruct weakCompareAndSwapPAcq(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval, rFlagsReg cr) %{
    +  predicate(needs_acquiring_load_exclusive(n) && (n->as_LoadStore()->barrier_data() == 0));
    +  match(Set res (WeakCompareAndSwapP mem (Binary oldval newval)));
    +  ins_cost(VOLATILE_REF_COST);
    +  effect(KILL cr);
    +  format %{
    +    "cmpxchg_acq_weak $res = $mem, $oldval, $newval\t# (ptr) if $mem == $oldval then $mem <-- $newval"
    +    "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)"
    +  %}
    +  ins_encode %{
    +    __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register,
    +               Assembler::xword, /*acquire*/ true, /*release*/ true,
    +               /*weak*/ true, noreg);
    +    __ csetw($res$$Register, Assembler::EQ);
    +  %}
    +  ins_pipe(pipe_slow);
    +%}
    +
    +instruct getAndSetI(indirect mem, iRegI newval, iRegINoSp oldval) %{
    +  match(Set oldval (GetAndSetI mem newval));
    +  ins_cost(2*VOLATILE_REF_COST);
    +  format %{ "atomic_xchgw  $oldval, $newval, [$mem]" %}
    +  ins_encode %{
    +    __ atomic_xchgw($oldval$$Register, $newval$$Register, as_Register($mem$$base));
    +  %}
    +  ins_pipe(pipe_serial);
    +%}
    +
    +instruct getAndSetL(indirect mem, iRegL newval, iRegLNoSp oldval) %{
    +  match(Set oldval (GetAndSetL mem newval));
    +  ins_cost(2*VOLATILE_REF_COST);
    +  format %{ "atomic_xchg  $oldval, $newval, [$mem]" %}
    +  ins_encode %{
    +    __ atomic_xchg($oldval$$Register, $newval$$Register, as_Register($mem$$base));
    +  %}
    +  ins_pipe(pipe_serial);
    +%}
    +
    +instruct getAndSetN(indirect mem, iRegN newval, iRegNNoSp oldval) %{
    +  predicate(n->as_LoadStore()->barrier_data() == 0);
    +  match(Set oldval (GetAndSetN mem newval));
    +  ins_cost(2*VOLATILE_REF_COST);
    +  format %{ "atomic_xchgw  $oldval, $newval, [$mem]" %}
    +  ins_encode %{
    +    __ atomic_xchgw($oldval$$Register, $newval$$Register, as_Register($mem$$base));
    +  %}
    +  ins_pipe(pipe_serial);
    +%}
    +
    +instruct getAndSetP(indirect mem, iRegP newval, iRegPNoSp oldval) %{
    +  predicate(n->as_LoadStore()->barrier_data() == 0);
    +  match(Set oldval (GetAndSetP mem newval));
    +  ins_cost(2*VOLATILE_REF_COST);
    +  format %{ "atomic_xchg  $oldval, $newval, [$mem]" %}
    +  ins_encode %{
    +    __ atomic_xchg($oldval$$Register, $newval$$Register, as_Register($mem$$base));
    +  %}
    +  ins_pipe(pipe_serial);
    +%}
    +
    +instruct getAndSetIAcq(indirect mem, iRegI newval, iRegINoSp oldval) %{
    +  predicate(needs_acquiring_load_exclusive(n));
    +  match(Set oldval (GetAndSetI mem newval));
    +  ins_cost(2*VOLATILE_REF_COST);
    +  format %{ "atomic_xchgw_acq  $oldval, $newval, [$mem]" %}
    +  ins_encode %{
    +    __ atomic_xchgalw($oldval$$Register, $newval$$Register, as_Register($mem$$base));
    +  %}
    +  ins_pipe(pipe_serial);
    +%}
    +
    +instruct getAndSetLAcq(indirect mem, iRegL newval, iRegLNoSp oldval) %{
    +  predicate(needs_acquiring_load_exclusive(n));
    +  match(Set oldval (GetAndSetL mem newval));
    +  ins_cost(2*VOLATILE_REF_COST);
    +  format %{ "atomic_xchg_acq  $oldval, $newval, [$mem]" %}
    +  ins_encode %{
    +    __ atomic_xchgal($oldval$$Register, $newval$$Register, as_Register($mem$$base));
    +  %}
    +  ins_pipe(pipe_serial);
    +%}
    +
    +instruct getAndSetNAcq(indirect mem, iRegN newval, iRegNNoSp oldval) %{
    +  predicate(needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() == 0);
    +  match(Set oldval (GetAndSetN mem newval));
    +  ins_cost(2*VOLATILE_REF_COST);
    +  format %{ "atomic_xchgw_acq  $oldval, $newval, [$mem]" %}
    +  ins_encode %{
    +    __ atomic_xchgalw($oldval$$Register, $newval$$Register, as_Register($mem$$base));
    +  %}
    +  ins_pipe(pipe_serial);
    +%}
    +
    +instruct getAndSetPAcq(indirect mem, iRegP newval, iRegPNoSp oldval) %{
    +  predicate(needs_acquiring_load_exclusive(n) && (n->as_LoadStore()->barrier_data() == 0));
    +  match(Set oldval (GetAndSetP mem newval));
    +  ins_cost(2*VOLATILE_REF_COST);
    +  format %{ "atomic_xchg_acq  $oldval, $newval, [$mem]" %}
    +  ins_encode %{
    +    __ atomic_xchgal($oldval$$Register, $newval$$Register, as_Register($mem$$base));
    +  %}
    +  ins_pipe(pipe_serial);
    +%}
    +
    +instruct getAndAddI(indirect mem, iRegINoSp newval, iRegIorL2I incr) %{
    +  match(Set newval (GetAndAddI mem incr));
    +  ins_cost(2*VOLATILE_REF_COST+1);
    +  format %{ "get_and_addI $newval, [$mem], $incr" %}
    +  ins_encode %{
    +    __ atomic_addw($newval$$Register, $incr$$Register, as_Register($mem$$base));
    +  %}
    +  ins_pipe(pipe_serial);
    +%}
    +
    +instruct getAndAddIAcq(indirect mem, iRegINoSp newval, iRegIorL2I incr) %{
    +  predicate(needs_acquiring_load_exclusive(n));
    +  match(Set newval (GetAndAddI mem incr));
    +  ins_cost(VOLATILE_REF_COST+1);
    +  format %{ "get_and_addI_acq $newval, [$mem], $incr" %}
    +  ins_encode %{
    +    __ atomic_addalw($newval$$Register, $incr$$Register, as_Register($mem$$base));
    +  %}
    +  ins_pipe(pipe_serial);
    +%}
    +
    +instruct getAndAddINoRes(indirect mem, Universe dummy, iRegIorL2I incr) %{
    +  predicate(n->as_LoadStore()->result_not_used());
    +  match(Set dummy (GetAndAddI mem incr));
    +  ins_cost(2*VOLATILE_REF_COST);
    +  format %{ "get_and_addI noreg, [$mem], $incr" %}
    +  ins_encode %{
    +    __ atomic_addw(noreg, $incr$$Register, as_Register($mem$$base));
    +  %}
    +  ins_pipe(pipe_serial);
    +%}
    +
    +instruct getAndAddIAcqNoRes(indirect mem, Universe dummy, iRegIorL2I incr) %{
    +  predicate(n->as_LoadStore()->result_not_used() && needs_acquiring_load_exclusive(n));
    +  match(Set dummy (GetAndAddI mem incr));
    +  ins_cost(VOLATILE_REF_COST);
    +  format %{ "get_and_addI_acq noreg, [$mem], $incr" %}
    +  ins_encode %{
    +    __ atomic_addalw(noreg, $incr$$Register, as_Register($mem$$base));
    +  %}
    +  ins_pipe(pipe_serial);
    +%}
    +
    +instruct getAndAddIConst(indirect mem, iRegINoSp newval, immIAddSub incr) %{
    +  match(Set newval (GetAndAddI mem incr));
    +  ins_cost(2*VOLATILE_REF_COST+1);
    +  format %{ "get_and_addI $newval, [$mem], $incr" %}
    +  ins_encode %{
    +    __ atomic_addw($newval$$Register, $incr$$constant, as_Register($mem$$base));
    +  %}
    +  ins_pipe(pipe_serial);
    +%}
    +
    +instruct getAndAddIAcqConst(indirect mem, iRegINoSp newval, immIAddSub incr) %{
    +  predicate(needs_acquiring_load_exclusive(n));
    +  match(Set newval (GetAndAddI mem incr));
    +  ins_cost(VOLATILE_REF_COST+1);
    +  format %{ "get_and_addI_acq $newval, [$mem], $incr" %}
    +  ins_encode %{
    +    __ atomic_addalw($newval$$Register, $incr$$constant, as_Register($mem$$base));
    +  %}
    +  ins_pipe(pipe_serial);
    +%}
    +
    +instruct getAndAddINoResConst(indirect mem, Universe dummy, immIAddSub incr) %{
    +  predicate(n->as_LoadStore()->result_not_used());
    +  match(Set dummy (GetAndAddI mem incr));
    +  ins_cost(2*VOLATILE_REF_COST);
    +  format %{ "get_and_addI noreg, [$mem], $incr" %}
    +  ins_encode %{
    +    __ atomic_addw(noreg, $incr$$constant, as_Register($mem$$base));
    +  %}
    +  ins_pipe(pipe_serial);
    +%}
    +
    +instruct getAndAddIAcqNoResConst(indirect mem, Universe dummy, immIAddSub incr) %{
    +  predicate(n->as_LoadStore()->result_not_used() && needs_acquiring_load_exclusive(n));
    +  match(Set dummy (GetAndAddI mem incr));
    +  ins_cost(VOLATILE_REF_COST);
    +  format %{ "get_and_addI_acq noreg, [$mem], $incr" %}
    +  ins_encode %{
    +    __ atomic_addalw(noreg, $incr$$constant, as_Register($mem$$base));
    +  %}
    +  ins_pipe(pipe_serial);
    +%}
    +
    +instruct getAndAddL(indirect mem, iRegLNoSp newval, iRegL incr) %{
    +  match(Set newval (GetAndAddL mem incr));
    +  ins_cost(2*VOLATILE_REF_COST+1);
    +  format %{ "get_and_addL $newval, [$mem], $incr" %}
    +  ins_encode %{
    +    __ atomic_add($newval$$Register, $incr$$Register, as_Register($mem$$base));
    +  %}
    +  ins_pipe(pipe_serial);
    +%}
    +
    +instruct getAndAddLAcq(indirect mem, iRegLNoSp newval, iRegL incr) %{
    +  predicate(needs_acquiring_load_exclusive(n));
    +  match(Set newval (GetAndAddL mem incr));
    +  ins_cost(VOLATILE_REF_COST+1);
    +  format %{ "get_and_addL_acq $newval, [$mem], $incr" %}
    +  ins_encode %{
    +    __ atomic_addal($newval$$Register, $incr$$Register, as_Register($mem$$base));
    +  %}
    +  ins_pipe(pipe_serial);
    +%}
    +
    +instruct getAndAddLNoRes(indirect mem, Universe dummy, iRegL incr) %{
    +  predicate(n->as_LoadStore()->result_not_used());
    +  match(Set dummy (GetAndAddL mem incr));
    +  ins_cost(2*VOLATILE_REF_COST);
    +  format %{ "get_and_addL noreg, [$mem], $incr" %}
    +  ins_encode %{
    +    __ atomic_add(noreg, $incr$$Register, as_Register($mem$$base));
    +  %}
    +  ins_pipe(pipe_serial);
    +%}
    +
    +instruct getAndAddLAcqNoRes(indirect mem, Universe dummy, iRegL incr) %{
    +  predicate(n->as_LoadStore()->result_not_used() && needs_acquiring_load_exclusive(n));
    +  match(Set dummy (GetAndAddL mem incr));
    +  ins_cost(VOLATILE_REF_COST);
    +  format %{ "get_and_addL_acq noreg, [$mem], $incr" %}
    +  ins_encode %{
    +    __ atomic_addal(noreg, $incr$$Register, as_Register($mem$$base));
    +  %}
    +  ins_pipe(pipe_serial);
    +%}
    +
    +instruct getAndAddLConst(indirect mem, iRegLNoSp newval, immLAddSub incr) %{
    +  match(Set newval (GetAndAddL mem incr));
    +  ins_cost(2*VOLATILE_REF_COST+1);
    +  format %{ "get_and_addL $newval, [$mem], $incr" %}
    +  ins_encode %{
    +    __ atomic_add($newval$$Register, $incr$$constant, as_Register($mem$$base));
    +  %}
    +  ins_pipe(pipe_serial);
    +%}
    +
    +instruct getAndAddLAcqConst(indirect mem, iRegLNoSp newval, immLAddSub incr) %{
    +  predicate(needs_acquiring_load_exclusive(n));
    +  match(Set newval (GetAndAddL mem incr));
    +  ins_cost(VOLATILE_REF_COST+1);
    +  format %{ "get_and_addL_acq $newval, [$mem], $incr" %}
    +  ins_encode %{
    +    __ atomic_addal($newval$$Register, $incr$$constant, as_Register($mem$$base));
    +  %}
    +  ins_pipe(pipe_serial);
    +%}
    +
    +instruct getAndAddLNoResConst(indirect mem, Universe dummy, immLAddSub incr) %{
    +  predicate(n->as_LoadStore()->result_not_used());
    +  match(Set dummy (GetAndAddL mem incr));
    +  ins_cost(2*VOLATILE_REF_COST);
    +  format %{ "get_and_addL noreg, [$mem], $incr" %}
    +  ins_encode %{
    +    __ atomic_add(noreg, $incr$$constant, as_Register($mem$$base));
    +  %}
    +  ins_pipe(pipe_serial);
    +%}
    +
    +instruct getAndAddLAcqNoResConst(indirect mem, Universe dummy, immLAddSub incr) %{
    +  predicate(n->as_LoadStore()->result_not_used() && needs_acquiring_load_exclusive(n));
    +  match(Set dummy (GetAndAddL mem incr));
    +  ins_cost(VOLATILE_REF_COST);
    +  format %{ "get_and_addL_acq noreg, [$mem], $incr" %}
    +  ins_encode %{
    +    __ atomic_addal(noreg, $incr$$constant, as_Register($mem$$base));
    +  %}
    +  ins_pipe(pipe_serial);
    +%}
    diff --git a/src/hotspot/cpu/aarch64/aarch64_atomic_ad.m4 b/src/hotspot/cpu/aarch64/aarch64_atomic_ad.m4
    new file mode 100644
    index 00000000000..721b720873a
    --- /dev/null
    +++ b/src/hotspot/cpu/aarch64/aarch64_atomic_ad.m4
    @@ -0,0 +1,246 @@
    +// Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved.
    +// Copyright (c) 2016, 2021, Red Hat Inc. 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.
    +//
    +//
    +
    +// BEGIN This file is automatically generated. Do not edit --------------
    +
    +// Sundry CAS operations.  Note that release is always true,
    +// regardless of the memory ordering of the CAS.  This is because we
    +// need the volatile case to be sequentially consistent but there is
    +// no trailing StoreLoad barrier emitted by C2.  Unfortunately we
    +// can't check the type of memory ordering here, so we always emit a
    +// STLXR.
    +
    +// This section is generated from aarch64_atomic_ad.m4
    +
    +dnl Return Arg1 with two spaces before it. We need this because m4
    +dnl strips leading spaces from macro args.
    +define(`INDENT', `  $1')dnl
    +dnl
    +dnl
    +dnl
    +dnl ====================== CompareAndExchange*
    +dnl
    +define(`CAE_INSN1',
    +`
    +instruct compareAndExchange$1$7(iReg$2NoSp res, indirect mem, iReg$2 oldval, iReg$2 newval, rFlagsReg cr) %{
    +ifelse($7,Acq,INDENT(predicate(needs_acquiring_load_exclusive(n));),`dnl')
    +  match(Set res (CompareAndExchange$1 mem (Binary oldval newval)));
    +  ins_cost(`'ifelse($7,Acq,,2*)VOLATILE_REF_COST);
    +  effect(TEMP_DEF res, KILL cr);
    +  format %{
    +    "cmpxchg$5`'ifelse($7,Acq,_acq,) $res = $mem, $oldval, $newval\t# ($3) if $mem == $oldval then $mem <-- $newval"
    +  %}
    +  ins_encode %{
    +    __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register,
    +               Assembler::$4, /*acquire*/ ifelse($7,Acq,true,false), /*release*/ true,
    +               /*weak*/ false, $res$$Register);
    +    __ $6($res$$Register, $res$$Register);
    +  %}
    +  ins_pipe(pipe_slow);
    +%}')dnl
    +define(`CAE_INSN2',
    +`
    +instruct compareAndExchange$1$6(iReg$2NoSp res, indirect mem, iReg$2 oldval, iReg$2 newval, rFlagsReg cr) %{
    +ifelse($1$6,PAcq,INDENT(predicate(needs_acquiring_load_exclusive(n) && (n->as_LoadStore()->barrier_data() == 0));),
    +       $1$6,NAcq,INDENT(predicate(needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() == 0);),
    +       $1,P,INDENT(predicate(n->as_LoadStore()->barrier_data() == 0);),
    +       $1,N,INDENT(predicate(n->as_LoadStore()->barrier_data() == 0);),
    +       $6,Acq,INDENT(predicate(needs_acquiring_load_exclusive(n));),
    +       `dnl')
    +  match(Set res (CompareAndExchange$1 mem (Binary oldval newval)));
    +  ins_cost(`'ifelse($6,Acq,,2*)VOLATILE_REF_COST);
    +  effect(TEMP_DEF res, KILL cr);
    +  format %{
    +    "cmpxchg$5`'ifelse($6,Acq,_acq,) $res = $mem, $oldval, $newval\t# ($3) if $mem == $oldval then $mem <-- $newval"
    +  %}
    +  ins_encode %{
    +    __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register,
    +               Assembler::$4, /*acquire*/ ifelse($6,Acq,true,false), /*release*/ true,
    +               /*weak*/ false, $res$$Register);
    +  %}
    +  ins_pipe(pipe_slow);
    +%}')dnl
    +dnl
    +CAE_INSN1(B,    I,  byte,       byte,       b,  sxtbw,  )
    +CAE_INSN1(S,    I,  short,      halfword,   s,  sxthw,  )
    +CAE_INSN2(I,    I,  int,        word,       w,  ,   )
    +CAE_INSN2(L,    L,  long,       xword,      ,   ,   )
    +CAE_INSN2(N,    N,  narrow oop, word,       w,  ,   )
    +CAE_INSN2(P,    P,  ptr,        xword,      ,   ,   )
    +dnl
    +CAE_INSN1(B,    I,  byte,       byte,       b,  sxtbw,  Acq)
    +CAE_INSN1(S,    I,  short,      halfword,   s,  sxthw,  Acq)
    +CAE_INSN2(I,    I,  int,        word,       w,  Acq)
    +CAE_INSN2(L,    L,  long,       xword,      ,   Acq)
    +CAE_INSN2(N,    N,  narrow oop, word,       w,  Acq)
    +CAE_INSN2(P,    P,  ptr,        xword,      ,   Acq)
    +dnl
    +dnl
    +dnl
    +dnl ====================== (Weak)CompareAndSwap*
    +dnl
    +define(`CAS_INSN1',
    +`
    +instruct ifelse($7,Weak,'weakCompare`,'compare`)AndSwap$1$6(iRegINoSp res, indirect mem, iReg$2 oldval, iReg$2 newval, rFlagsReg cr) %{
    +ifelse($6,Acq,INDENT(predicate(needs_acquiring_load_exclusive(n));),`dnl')
    +  match(Set res ($7CompareAndSwap$1 mem (Binary oldval newval)));
    +  ins_cost(`'ifelse($6,Acq,,2*)VOLATILE_REF_COST);
    +  effect(KILL cr);
    +  format %{
    +    "cmpxchg$5`'ifelse($6,Acq,_acq,)`'ifelse($7,Weak,_weak) $res = $mem, $oldval, $newval\t# ($3) if $mem == $oldval then $mem <-- $newval"
    +    "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)"
    +  %}
    +  ins_encode %{
    +    __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register,
    +               Assembler::$4, /*acquire*/ ifelse($6,Acq,true,false), /*release*/ true,
    +               /*weak*/ ifelse($7,Weak,true,false), noreg);
    +    __ csetw($res$$Register, Assembler::EQ);
    +  %}
    +  ins_pipe(pipe_slow);
    +%}')dnl
    +dnl
    +define(`CAS_INSN2',
    +`
    +instruct ifelse($7,Weak,'weakCompare`,'compare`)AndSwap$1$6(iRegINoSp res, indirect mem, iReg$2 oldval, iReg$2 newval, rFlagsReg cr) %{
    +ifelse($1$6,PAcq,INDENT(predicate(needs_acquiring_load_exclusive(n) && (n->as_LoadStore()->barrier_data() == 0));),
    +       $1$6,NAcq,INDENT(predicate(needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() == 0);),
    +       $1,P,INDENT(predicate(n->as_LoadStore()->barrier_data() == 0);),
    +       $1,N,INDENT(predicate(n->as_LoadStore()->barrier_data() == 0);),
    +       $6,Acq,INDENT(predicate(needs_acquiring_load_exclusive(n));),
    +       `dnl')
    +  match(Set res ($7CompareAndSwap$1 mem (Binary oldval newval)));
    +  ins_cost(`'ifelse($6,Acq,,2*)VOLATILE_REF_COST);
    +  effect(KILL cr);
    +  format %{
    +    "cmpxchg$5`'ifelse($6,Acq,_acq,)`'ifelse($7,Weak,_weak) $res = $mem, $oldval, $newval\t# ($3) if $mem == $oldval then $mem <-- $newval"
    +    "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)"
    +  %}
    +  ins_encode %{
    +    __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register,
    +               Assembler::$4, /*acquire*/ ifelse($6,Acq,true,false), /*release*/ true,
    +               /*weak*/ ifelse($7,Weak,true,false), noreg);
    +    __ csetw($res$$Register, Assembler::EQ);
    +  %}
    +  ins_pipe(pipe_slow);
    +%}')dnl
    +dnl
    +CAS_INSN1(B,    I,  byte,       byte,       b,  ,           )
    +CAS_INSN1(S,    I,  short,      halfword,   s,  ,           )
    +CAS_INSN2(I,    I,  int,        word,       w,  ,           )
    +CAS_INSN2(L,    L,  long,       xword,      ,   ,           )
    +CAS_INSN2(N,    N,  narrow oop, word,       w,  ,           )
    +CAS_INSN2(P,    P,  ptr,        xword,      ,   ,           )
    +dnl
    +CAS_INSN1(B,    I,  byte,       byte,       b,  Acq,        )
    +CAS_INSN1(S,    I,  short,      halfword,   s,  Acq,        )
    +CAS_INSN2(I,    I,  int,        word,       w,  Acq,        )
    +CAS_INSN2(L,    L,  long,       xword,      ,   Acq,        )
    +CAS_INSN2(N,    N,  narrow oop, word,       w,  Acq,        )
    +CAS_INSN2(P,    P,  ptr,        xword,      ,   Acq,        )
    +dnl
    +CAS_INSN1(B,    I,  byte,       byte,       b,  ,       Weak)
    +CAS_INSN1(S,    I,  short,      halfword,   s,  ,       Weak)
    +CAS_INSN2(I,    I,  int,        word,       w,  ,       Weak)
    +CAS_INSN2(L,    L,  long,       xword,      ,   ,       Weak)
    +CAS_INSN2(N,    N,  narrow oop, word,       w,  ,       Weak)
    +CAS_INSN2(P,    P,  ptr,        xword,      ,   ,       Weak)
    +dnl
    +CAS_INSN1(B,    I,  byte,       byte,       b,  Acq,    Weak)
    +CAS_INSN1(S,    I,  short,      halfword,   s,  Acq,    Weak)
    +CAS_INSN2(I,    I,  int,        word,       w,  Acq,    Weak)
    +CAS_INSN2(L,    L,  long,       xword,      ,   Acq,    Weak)
    +CAS_INSN2(N,    N,  narrow oop, word,       w,  Acq,    Weak)
    +CAS_INSN2(P,    P,  ptr,        xword,      ,   Acq,    Weak)
    +dnl
    +dnl
    +dnl
    +dnl ====================== GetAndSet*
    +dnl
    +define(`GAS_INSN1',
    +`
    +instruct getAndSet$1$3(indirect mem, iReg$1 newval, iReg$1NoSp oldval) %{
    +ifelse($1$3,PAcq,INDENT(predicate(needs_acquiring_load_exclusive(n) && (n->as_LoadStore()->barrier_data() == 0));),
    +       $1$3,NAcq,INDENT(predicate(needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() == 0);),
    +       $1,P,INDENT(predicate(n->as_LoadStore()->barrier_data() == 0);),
    +       $1,N,INDENT(predicate(n->as_LoadStore()->barrier_data() == 0);),
    +       $3,Acq,INDENT(predicate(needs_acquiring_load_exclusive(n));),
    +       `dnl')
    +  match(Set oldval (GetAndSet$1 mem newval));
    +  ins_cost(`'ifelse($4,Acq,,2*)VOLATILE_REF_COST);
    +  format %{ "atomic_xchg$2`'ifelse($3,Acq,_acq)  $oldval, $newval, [$mem]" %}
    +  ins_encode %{
    +    __ atomic_xchg`'ifelse($3,Acq,al)$2($oldval$$Register, $newval$$Register, as_Register($mem$$base));
    +  %}
    +  ins_pipe(pipe_serial);
    +%}')dnl
    +dnl
    +GAS_INSN1(I,    w,  )
    +GAS_INSN1(L,    ,   )
    +GAS_INSN1(N,    w,  )
    +GAS_INSN1(P,    ,   )
    +dnl
    +GAS_INSN1(I,    w,  Acq)
    +GAS_INSN1(L,    ,   Acq)
    +GAS_INSN1(N,    w,  Acq)
    +GAS_INSN1(P,    ,   Acq)
    +dnl
    +dnl
    +dnl
    +dnl ====================== GetAndAdd*
    +dnl
    +define(`GAA_INSN1',
    +`
    +instruct getAndAdd$1$4$5$6(indirect mem, `'ifelse($5,NoRes,Universe dummy,iReg$1NoSp newval), `'ifelse($6,Const,imm$1AddSub incr,iReg$2 incr)) %{
    +ifelse($4$5,AcqNoRes,INDENT(predicate(n->as_LoadStore()->result_not_used() && needs_acquiring_load_exclusive(n));),
    +       $5,NoRes,INDENT(predicate(n->as_LoadStore()->result_not_used());),
    +       $4,Acq,INDENT(predicate(needs_acquiring_load_exclusive(n));),
    +       `dnl')
    +  match(Set ifelse($5,NoRes,dummy,newval) (GetAndAdd$1 mem incr));
    +  ins_cost(`'ifelse($4,Acq,,2*)VOLATILE_REF_COST`'ifelse($5,NoRes,,+1));
    +  format %{ "get_and_add$1`'ifelse($4,Acq,_acq) `'ifelse($5,NoRes,noreg,$newval), [$mem], $incr" %}
    +  ins_encode %{
    +    __ atomic_add`'ifelse($4,Acq,al)$3(`'ifelse($5,NoRes,noreg,$newval$$Register), `'ifelse($6,Const,$incr$$constant,$incr$$Register), as_Register($mem$$base));
    +  %}
    +  ins_pipe(pipe_serial);
    +%}')dnl
    +dnl
    +dnl
    +GAA_INSN1(I,    IorL2I,     w,  ,       ,           )
    +GAA_INSN1(I,    IorL2I,     w,  Acq,    ,           )
    +GAA_INSN1(I,    IorL2I,     w,  ,       NoRes,      )
    +GAA_INSN1(I,    IorL2I,     w,  Acq,    NoRes,      )
    +GAA_INSN1(I,    I,          w,  ,       ,       Const)
    +GAA_INSN1(I,    I,          w,  Acq,    ,       Const)
    +GAA_INSN1(I,    I,          w,  ,       NoRes,  Const)
    +GAA_INSN1(I,    I,          w,  Acq,    NoRes,  Const)
    +dnl
    +GAA_INSN1(L,    L,          ,   ,       ,           )
    +GAA_INSN1(L,    L,          ,   Acq,    ,           )
    +GAA_INSN1(L,    L,          ,   ,       NoRes,      )
    +GAA_INSN1(L,    L,          ,   Acq,    NoRes,      )
    +GAA_INSN1(L,    L,          ,   ,       ,       Const)
    +GAA_INSN1(L,    L,          ,   Acq,    ,       Const)
    +GAA_INSN1(L,    L,          ,   ,       NoRes,  Const)
    +GAA_INSN1(L,    L,          ,   Acq,    NoRes,  Const)
    +dnl
    diff --git a/src/hotspot/cpu/aarch64/cas.m4 b/src/hotspot/cpu/aarch64/cas.m4
    deleted file mode 100644
    index 7e13e153db1..00000000000
    --- a/src/hotspot/cpu/aarch64/cas.m4
    +++ /dev/null
    @@ -1,161 +0,0 @@
    -dnl Copyright (c) 2016, 2021, Red Hat Inc. All rights reserved.
    -dnl DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    -dnl
    -dnl This code is free software; you can redistribute it and/or modify it
    -dnl under the terms of the GNU General Public License version 2 only, as
    -dnl published by the Free Software Foundation.
    -dnl
    -dnl This code is distributed in the hope that it will be useful, but WITHOUT
    -dnl ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    -dnl FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    -dnl version 2 for more details (a copy is included in the LICENSE file that
    -dnl accompanied this code).
    -dnl
    -dnl You should have received a copy of the GNU General Public License version
    -dnl 2 along with this work; if not, write to the Free Software Foundation,
    -dnl Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    -dnl
    -dnl Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    -dnl or visit www.oracle.com if you need additional information or have any
    -dnl questions.
    -dnl
    -dnl
    -dnl Process this file with m4 cas.m4 to generate the CAE and wCAS
    -dnl instructions used in aarch64.ad.
    -dnl
    -
    -// BEGIN This section of the file is automatically generated. Do not edit --------------
    -
    -// Sundry CAS operations.  Note that release is always true,
    -// regardless of the memory ordering of the CAS.  This is because we
    -// need the volatile case to be sequentially consistent but there is
    -// no trailing StoreLoad barrier emitted by C2.  Unfortunately we
    -// can't check the type of memory ordering here, so we always emit a
    -// STLXR.
    -
    -// This section is generated from cas.m4
    -
    -dnl Return Arg1 with two spaces before it. We need this because m4
    -dnl strips leading spaces from macro args.
    -define(`INDENT', `  $1')dnl
    -dnl
    -define(`CAS_INSN',
    -`
    -// This pattern is generated automatically from cas.m4.
    -// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE
    -instruct compareAndExchange$1$6(iReg$2NoSp res, indirect mem, iReg$2 oldval, iReg$2 newval, rFlagsReg cr) %{
    -ifelse($1$6,PAcq,INDENT(predicate(needs_acquiring_load_exclusive(n) && (n->as_LoadStore()->barrier_data() == 0));),
    -       $1$6,NAcq,INDENT(predicate(needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() == 0);),
    -       $1,P,INDENT(predicate(n->as_LoadStore()->barrier_data() == 0);),
    -       $1,N,INDENT(predicate(n->as_LoadStore()->barrier_data() == 0);),
    -       $6,Acq,INDENT(predicate(needs_acquiring_load_exclusive(n));),
    -       `dnl')
    -  match(Set res (CompareAndExchange$1 mem (Binary oldval newval)));
    -  ifelse($6,Acq,'ins_cost(VOLATILE_REF_COST);`,'ins_cost(2 * VOLATILE_REF_COST);`)
    -  effect(TEMP_DEF res, KILL cr);
    -  format %{
    -    "cmpxchg$5`'ifelse($6,Acq,_acq,) $res = $mem, $oldval, $newval\t# ($3, weak) if $mem == $oldval then $mem <-- $newval"
    -  %}
    -  ins_encode %{
    -    __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register,
    -               Assembler::$4, /*acquire*/ ifelse($6,Acq,true,false), /*release*/ true,
    -               /*weak*/ false, $res$$Register);
    -  %}
    -  ins_pipe(pipe_slow);
    -%}')dnl
    -define(`CAS_INSN4',
    -`
    -// This pattern is generated automatically from cas.m4.
    -// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE
    -instruct compareAndExchange$1$7(iReg$2NoSp res, indirect mem, iReg$2 oldval, iReg$2 newval, rFlagsReg cr) %{
    -ifelse($7,Acq,INDENT(predicate(needs_acquiring_load_exclusive(n));),`dnl')
    -  match(Set res (CompareAndExchange$1 mem (Binary oldval newval)));
    -  ifelse($7,Acq,'ins_cost(VOLATILE_REF_COST);`,'ins_cost(2 * VOLATILE_REF_COST);`)
    -  effect(TEMP_DEF res, KILL cr);
    -  format %{
    -    "cmpxchg$5`'ifelse($7,Acq,_acq,) $res = $mem, $oldval, $newval\t# ($3, weak) if $mem == $oldval then $mem <-- $newval"
    -  %}
    -  ins_encode %{
    -    __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register,
    -               Assembler::$4, /*acquire*/ ifelse($7,Acq,true,false), /*release*/ true,
    -               /*weak*/ false, $res$$Register);
    -    __ $6($res$$Register, $res$$Register);
    -  %}
    -  ins_pipe(pipe_slow);
    -%}')dnl
    -CAS_INSN4(B,I,byte,byte,b,sxtbw)
    -CAS_INSN4(S,I,short,halfword,s,sxthw)
    -CAS_INSN(I,I,int,word,w)
    -CAS_INSN(L,L,long,xword)
    -CAS_INSN(N,N,narrow oop,word,w)
    -CAS_INSN(P,P,ptr,xword)
    -dnl
    -CAS_INSN4(B,I,byte,byte,b,sxtbw,Acq)
    -CAS_INSN4(S,I,short,halfword,s,sxthw,Acq)
    -CAS_INSN(I,I,int,word,w,Acq)
    -CAS_INSN(L,L,long,xword,,Acq)
    -CAS_INSN(N,N,narrow oop,word,w,Acq)
    -CAS_INSN(P,P,ptr,xword,,Acq)
    -dnl
    -define(`CAS_INSN2',
    -`
    -// This pattern is generated automatically from cas.m4.
    -// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE
    -instruct weakCompareAndSwap$1$6(iRegINoSp res, indirect mem, iReg$2 oldval, iReg$2 newval, rFlagsReg cr) %{
    -ifelse($6,Acq,INDENT(predicate(needs_acquiring_load_exclusive(n));),`dnl')
    -  match(Set res (WeakCompareAndSwap$1 mem (Binary oldval newval)));
    -  ifelse($6,Acq,'ins_cost(VOLATILE_REF_COST);`,'ins_cost(2 * VOLATILE_REF_COST);`)
    -  effect(KILL cr);
    -  format %{
    -    "cmpxchg$5`'ifelse($6,Acq,_acq,) $res = $mem, $oldval, $newval\t# ($3, weak) if $mem == $oldval then $mem <-- $newval"
    -    "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)"
    -  %}
    -  ins_encode %{
    -    __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register,
    -               Assembler::$4, /*acquire*/ ifelse($6,Acq,true,false), /*release*/ true,
    -               /*weak*/ true, noreg);
    -    __ csetw($res$$Register, Assembler::EQ);
    -  %}
    -  ins_pipe(pipe_slow);
    -%}')dnl
    -define(`CAS_INSN3',
    -`
    -// This pattern is generated automatically from cas.m4.
    -// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE
    -instruct weakCompareAndSwap$1$6(iRegINoSp res, indirect mem, iReg$2 oldval, iReg$2 newval, rFlagsReg cr) %{
    -ifelse($1$6,PAcq,INDENT(predicate(needs_acquiring_load_exclusive(n) && (n->as_LoadStore()->barrier_data() == 0));),
    -       $1$6,NAcq,INDENT(predicate(needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() == 0);),
    -       $1,P,INDENT(predicate(n->as_LoadStore()->barrier_data() == 0);),
    -       $1,N,INDENT(predicate(n->as_LoadStore()->barrier_data() == 0);),
    -       $6,Acq,INDENT(predicate(needs_acquiring_load_exclusive(n));),
    -       `dnl')
    -  match(Set res (WeakCompareAndSwap$1 mem (Binary oldval newval)));
    -  ifelse($6,Acq,'ins_cost(VOLATILE_REF_COST);`,'ins_cost(2 * VOLATILE_REF_COST);`)
    -  effect(KILL cr);
    -  format %{
    -    "cmpxchg$5`'ifelse($6,Acq,_acq,) $res = $mem, $oldval, $newval\t# ($3, weak) if $mem == $oldval then $mem <-- $newval"
    -    "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)"
    -  %}
    -  ins_encode %{
    -    __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register,
    -               Assembler::$4, /*acquire*/ ifelse($6,Acq,true,false), /*release*/ true,
    -               /*weak*/ true, noreg);
    -    __ csetw($res$$Register, Assembler::EQ);
    -  %}
    -  ins_pipe(pipe_slow);
    -%}')dnl
    -CAS_INSN2(B,I,byte,byte,b)
    -CAS_INSN2(S,I,short,halfword,s)
    -CAS_INSN3(I,I,int,word,w)
    -CAS_INSN3(L,L,long,xword)
    -CAS_INSN3(N,N,narrow oop,word,w)
    -CAS_INSN3(P,P,ptr,xword)
    -CAS_INSN2(B,I,byte,byte,b,Acq)
    -CAS_INSN2(S,I,short,halfword,s,Acq)
    -CAS_INSN3(I,I,int,word,w,Acq)
    -CAS_INSN3(L,L,long,xword,,Acq)
    -CAS_INSN3(N,N,narrow oop,word,w,Acq)
    -CAS_INSN3(P,P,ptr,xword,,Acq)
    -dnl
    -
    -// END This section of the file is automatically generated. Do not edit --------------
    
    From 5bd7db034aaf8aa6780945e02a7f9a35e16b036e Mon Sep 17 00:00:00 2001
    From: Matthias Baesken 
    Date: Mon, 1 Dec 2025 09:03:30 +0000
    Subject: [PATCH 068/706] 8372730: Problem list
     compiler/arguments/TestCodeEntryAlignment.java on x64
    
    Reviewed-by: lucy, goetz
    ---
     test/hotspot/jtreg/ProblemList.txt | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt
    index 7b4026484ca..423bcdecaa8 100644
    --- a/test/hotspot/jtreg/ProblemList.txt
    +++ b/test/hotspot/jtreg/ProblemList.txt
    @@ -79,7 +79,7 @@ compiler/c2/aarch64/TestStaticCallStub.java 8359963 linux-aarch64,macosx-aarch64
     
     serviceability/jvmti/NMethodRelocation/NMethodRelocationTest.java 8369150 generic-all
     
    -compiler/arguments/TestCodeEntryAlignment.java 8372703 macosx-x64
    +compiler/arguments/TestCodeEntryAlignment.java 8372703 generic-x64
     
     #############################################################################
     
    
    From 160148cc7b0c2774e7aa5fece653e41c9fa7c970 Mon Sep 17 00:00:00 2001
    From: Thomas Schatzl 
    Date: Mon, 1 Dec 2025 11:28:22 +0000
    Subject: [PATCH 069/706] 8372610: G1: JDK-8297692 broke code roots scan
     measurements
    
    Reviewed-by: iwalulya, sjohanss
    ---
     src/hotspot/share/gc/g1/g1RemSet.cpp | 17 +++++++++--------
     1 file changed, 9 insertions(+), 8 deletions(-)
    
    diff --git a/src/hotspot/share/gc/g1/g1RemSet.cpp b/src/hotspot/share/gc/g1/g1RemSet.cpp
    index d0633466f37..c7724de280f 100644
    --- a/src/hotspot/share/gc/g1/g1RemSet.cpp
    +++ b/src/hotspot/share/gc/g1/g1RemSet.cpp
    @@ -611,23 +611,24 @@ void G1RemSet::scan_collection_set_code_roots(G1ParScanThreadState* pss,
                                                   G1GCPhaseTimes::GCParPhases coderoots_phase,
                                                   G1GCPhaseTimes::GCParPhases objcopy_phase) {
       EventGCPhaseParallel event;
    -
       Tickspan code_root_scan_time;
       Tickspan code_root_trim_partially_time;
    -  G1EvacPhaseWithTrimTimeTracker timer(pss, code_root_scan_time, code_root_trim_partially_time);
     
       G1GCPhaseTimes* p = _g1h->phase_times();
    +  {
    +    G1EvacPhaseWithTrimTimeTracker timer(pss, code_root_scan_time, code_root_trim_partially_time);
     
    -  G1ScanCodeRootsClosure cl(_scan_state, pss, worker_id);
    -  // Code roots work distribution occurs inside the iteration method. So scan all collection
    -  // set regions for all threads.
    -  _g1h->collection_set_iterate_increment_from(&cl, worker_id);
    +    G1ScanCodeRootsClosure cl(_scan_state, pss, worker_id);
    +    // Code roots work distribution occurs inside the iteration method. So scan all collection
    +    // set regions for all threads.
    +    _g1h->collection_set_iterate_increment_from(&cl, worker_id);
    +
    +    p->record_or_add_thread_work_item(coderoots_phase, worker_id, cl.code_roots_scanned(), G1GCPhaseTimes::CodeRootsScannedNMethods);
    +  }
     
       p->record_or_add_time_secs(coderoots_phase, worker_id, code_root_scan_time.seconds());
       p->add_time_secs(objcopy_phase, worker_id, code_root_trim_partially_time.seconds());
     
    -  p->record_or_add_thread_work_item(coderoots_phase, worker_id, cl.code_roots_scanned(), G1GCPhaseTimes::CodeRootsScannedNMethods);
    -
       event.commit(GCId::current(), worker_id, G1GCPhaseTimes::phase_name(coderoots_phase));
     }
     
    
    From f5eecc454eb78fc1a3714dfe3cb94113238dd3ac Mon Sep 17 00:00:00 2001
    From: Matthew Donovan 
    Date: Mon, 1 Dec 2025 12:18:19 +0000
    Subject: [PATCH 070/706] 8353738: Update TLS unit tests to not use
     certificates with MD5 signatures
    
    Reviewed-by: djelinski, abarashev
    ---
     .../javax/management/security/keystoreAgent   | Bin 1325 -> 2710 bytes
     .../javax/management/security/keystoreClient  | Bin 1327 -> 2710 bytes
     .../javax/management/security/truststoreAgent | Bin 619 -> 2710 bytes
     .../management/security/truststoreClient      | Bin 618 -> 2710 bytes
     .../CriticalSubjectAltName.java               | 191 +++--
     .../net/ssl/HttpsURLConnection/crisubn.jks    | Bin 2794 -> 0 bytes
     .../net/ssl/HttpsURLConnection/trusted.jks    | Bin 743 -> 0 bytes
     .../HttpsURLConnection/DNSIdentities.java     | 705 ++---------------
     .../IPAddressDNSIdentities.java               | 681 +----------------
     .../IPAddressIPIdentities.java                | 690 +----------------
     .../HttpsURLConnection/IPIdentities.java      | 425 -----------
     .../https/HttpsURLConnection/Identities.java  | 710 ++----------------
     .../HttpsURLConnection/IdentitiesBase.java    | 187 +++++
     .../test/lib/security/CertificateBuilder.java |  14 +-
     14 files changed, 524 insertions(+), 3079 deletions(-)
     delete mode 100644 test/jdk/javax/net/ssl/HttpsURLConnection/crisubn.jks
     delete mode 100644 test/jdk/javax/net/ssl/HttpsURLConnection/trusted.jks
     delete mode 100644 test/jdk/sun/net/www/protocol/https/HttpsURLConnection/IPIdentities.java
     create mode 100644 test/jdk/sun/net/www/protocol/https/HttpsURLConnection/IdentitiesBase.java
    
    diff --git a/test/jdk/javax/management/security/keystoreAgent b/test/jdk/javax/management/security/keystoreAgent
    index cfb02e00c38b8e28e4dcf4b0fdc60b80bda58990..ebb95dd0dfa3b6852c2aea03ada04f74d918722c 100644
    GIT binary patch
    literal 2710
    zcma);c{CJ`7RP6^4WhwVLYC})jCGiw>?BNNmt`7^q>+8!$B?pR&0Zo)Nj#=x$uOjl
    zHEWhEl?<}RAf9*LJ9XY)@11+@x#xbq_ufCh=OPHu3=j~EAV4+fnWPhp682bu48TVO
    z=wA>5RO%FqAqaHU|0U5CK?rntr#SmG)9IQ2v&8}hf*uj*v`?W1!u|IK9V@~fq4uX`
    zLC8Qj(aT5+ifm=>QB|4V$DGWb5F;re5J-X@1QbHB&@=w~B8Z6&fDoW(x}IPJ#DO6|
    zX$ZUdbH*{1#n#t!LGgx6p=B@#0W$c+7^HQ8F11`Jv0Na;W+AVM^;zFwP@)}T>;`>iosjl1q~HQ_*FH7jwcEMi
    z!RXq8q``c*TRd<~SK$$E%Sd8A*N$-;I_)HxGZU6qWLOX@`(0PmYYHDZ`~*&#F>y;1
    z8M)w37RT=&p+i9{ZjE17`V*tPa-4-CswN39
    z`uHUz<)UEb*?o!D1#!B!{Din4En>L4HG*m#k;hY)WYc?lZ%`Oe{n`(S+vgf!s8Fc%yNTNy?y%@5#wyx*vlfWp?^1n*$p1#UN#
    zs~%$xPVJhynWI0n%$FYBDGqf|f}K3(enqJ>-F>DHnT>%)ajMHiHn
    zMYh_W6{~j*-xqX}0oo;9#5I$@M)b=fYhE6|0yo87on9v^_lQEQjY$8t0_89|yYd(N^|}S%Cm3(q#(H;L*heg?Ziw
    z*54sZQy;w;?>68K=e`;Q$kzXiRPu%rJ1(&zNylpy?mGlo6CJK;v^^zuCa@(1pD4j$
    zT{)U|Cl+Oviz!p?b5!;kgTAOxy&WXxv~N_7>@4sR7em5WC^bzszFiMDCr9q>6%5oL
    zd_6AOrIisHF~$`8LN(%9oeWQ4uGc=^*=cE}xTWOBvHah5jEaxz)|3$PYe%=nE6cw1
    zScRr$ehA)}vgI*BCWoMcR&1otjfd>SbU(GLG<3_?nr7<9zOxpaX{3}FtXW#Vy_~=m
    z`K1lAp_1KRlBKNweu&ji|%mxm*DUqsbiE?`y)l2ww
    zqqu`P>gT|s+{U1*VsT_yy{rEIlSp~v((97VRah70wa}l7k;5OdPXZXSq=R89KeZJ4
    zu(O8gAwyJ!4B9cwPMGP_HIl9w{(!snVY8O>s3&>f!M1oYwifeU$+#XWsX$;GV-AyP
    z*Rxg7MDYH$OD0YQ7C|V$3lIvp1;7D95yF2YE(J~q%<85WPDlZ%f>cpfS5rbLo(2Kp
    z`+JCi{t*G7K=k}SCcUw01;dbU
    z_yp03cgNT0yT%Z}pU>wJiNUTi1J7Vh2Ss~5T@#a#34zX5
    z$8XB(jgyPuau-MzgS%rl9H^L4Gh#kTs(rvjz4P#`$bdJ0c@O$(V$dL*s-mwx5^Ij>
    zZ8?Z*`V{gSW0-@bBZtxj*R#reeQnu1qai6oqP8E-8)WM))K}=UtXlz
    zrQ*s&!c2+2(!pv*e|1*#9LmdcKGX<1%CW#!&A?P`P&&odkP0LE-g>X^DSX-#Y>uK?
    zxPxQsK%n71>}vYR1J24zQGr!i!m^IH@s_+}Pw+`bR?AL2j5)(II0n<><{uYheOua7
    z0;h-JpC+QM`bv)i?t5O;ZZABu9_@1Andf|G!#`tP$eU<8>OP5-pulP7on+6+le)T?
    z@<4B2pz8I7rXJDLc-#Wuo7GlIwTq_edO
    zaFHebso&#}rm)2|4E?LNdp_4FO@$(N{wh`L*^Fent3&d4TN5H0<>A({o1%{el`&Tm
    zpv1VhnKmy!I;>N5y
    z8z2UtdsQ06D!B)wl89|x^QmWggP%-tygmGKrE)I%zr|jD>ym8-ra#(R?U*Y#xmvw4
    zOy0~!8$A82`Pn@IV2qmmg+L<|5Ujs{H4u;v01-O3k^jn9o*hH3scy;C(AjqKnPS5+L*M{3&VyK$+bJO-$Pj_}I9#*%(3A9Z;R-&Gn3BG43#*>V^m=g{dlEL;e)p}a%T$OS$go)pZYj?d8^K<
    zIc^QA>1+9wt*(2Xm)U&v{ek0ApL?1sO1VyXnX%k2a&pQ0d-%#3;ZWfc9tn|>WNvHq77(l(VrM)ddOPoZTq=I=4;DssR6+(yX4A~kR6
    zw69UtJHIK<2>rEt`oj;AZTGJ|+sn*p<#?z6*#1cMezDg3pP34jr=%5rsy^g>{91PK
    zq76lQy@|)&<5OPf1?o%}|9j%yo?8X1`}e1A``kC3X)3!s2e0@ns|u&rFQlszbuu&B
    z!izeu3(9lY^jQ3kRXeod;xFkP7Vfd_D{sCwlV6(j&O$*?ET64KVd?J2p*y}c?!J8b
    zKx*gR<4h|%%uhWtO8BFYEV3v_XSmhGh=Ud-I<@G;iMU@9XLHKhD=Q
    z-w3vPrX=jy;c<%d$>P)dmVKQy$?vOI+}U8gOHyxcN$$M+py<$>%|-9tPhxm;Prl+T
    zr(Cll_c}glp5Ge03R|uo-g&(5hIvOgz4Qgno#sevUhCF=lF
    zvW7tu<3uJFhqt9?40zc%wc0$|zVk9Nvam83L>qD&aI!Invaks=xdj>W8SsEO9Kx)g
    z#i>Q9hJptCAU?Y=hkH?KUVc(esv(a77f6Upm^rvK&yd%E8^q%lX7Mr#c7;hY3p0E9
    zMi|J6^BR~Km>XCani-jy8byio8e1Be85=;kw6(l(KC)kd*_XMom%*U1lc}+hVeYPp
    z^7|)oO+Ikj)`~}m`CwS*EO*OUyy@`~f2KY=GRMrsYL9A)#FDPv<+HzY1eJv8zVc{X
    z#ah1bK0{l-zTANmSsR4@a<8bky!b~#mE@vdO?wy2=E<;XDrvFP-B+&H@4``V-2R-x
    z1PwK(HM@j9O}xHFNx5(C7kftDcMo?oMFnIsF*7nSB0CQl70f_)2`-+P{V34y%!Us^
    z^{MiIuT{S@;M`Tbr_e7&XiB&BzqOW@3!k|=p5Jn^@TSq5%YiKmr&^!d*mPaev6gj(
    z&&|esy?G|nisS{GpPJ2%R!x^PpR_Hz*Wtn}!&$F{Zr+G%HnUpZ$SgFA<)pGes_xC`
    s1RYCmjWelRZulO{m{9H0U*5Di<--A8#+8qI>{e=jSUrVB$KkIw0BqD5(*OVf
    
    diff --git a/test/jdk/javax/management/security/keystoreClient b/test/jdk/javax/management/security/keystoreClient
    index f0e0b7f57187520d475f57004e05ab8418f308d4..2382154441dee509bcad652d7dc2bb22a633d1ea 100644
    GIT binary patch
    literal 2710
    zcma);XEYlO7sn+MBck@I?GzO&v7;KRN>QuBp2brmW>LFB%?gU-(F$6E+9hhWs(7rT
    zX0=w3+EP?$#d`Xl_dR{i`{{i@+;h+U{qO&N{GSWQKpq1D^l%JBi-8%IXq5Pa6~G86
    z!a(Ff7>LX-ED6VetNu#@6F?Yn-Y=Z{tFjna{^No|0Kg&)Smzhif_wgUfLYG9_aA)MZ7gf;saw=5V-@Sb`)
    zj+EBr?LIur=djfrJUgXj4xx3i5{>!k;%Obgw6T4|WKE-z(n@bY!Jxkb-whAm~gSaHNPZ#>?@sHB6Y0+
    zCoQh%oxUsw(4HJo>8j4e#pZX?$K8JsV0^gPBWr$^?dEg$)v@Sc%Cv3g_WliY&-p(n
    zFV&*VELN(k#VV$5Dn}$47Dy|pwdN`~Kl!+}c-zKhbRPovsd%2%>O!eW68)SORx=V8
    zi_2p+Mw^b1Q7nHEhWJK?*pi>M+&l5-W}QVOX+Ers!>(kg{$Pyt{8(Q$Fg#C+xHY67
    zE-{&PuD|au8KnjB&-vu%YGmaBP5E3S*OZiW(XJ(g9Uj&9)P?W0iHsTef?(ow|!Q8_Sevsw|bPRXMD*e3fRm&$rOXgXN
    z1JC>$GP551fRmR?nX9nozBhB8xJ=sf7c;o|>DJP2+O=S?rPhZsU#Rb5pDiA1O?
    zBUIoRP~h(+Mus8`$n6($0s`oMHS2#A!2b&AmX@}KuZJ+(q&<^U3X0$>D#9Q`zYb_X@|;G#tZoi-O&I={3uquZ%Z
    z;+Oep*Tp(mk6_t?@PbOaFwhy&*m6;M;&G?>iLOVTfP~$qs)o(6=xs@5M_YQO$n+fO)6iOL-q9TSGsFkJPtaJVU~E-hHVVs&g(=RtBa
    z(b6idjTN7_yJa85wZw4MyG_D<*Z(zyXc|p`pZ#d7CqMaabXU8(`zLwtNcqa0LZ(_5
    z*YvSj)YL8k?Z1a4Egk4P&-*xXK3GJg3X(dI(yt)p?CuV`qgKk+halp?+dp``WcJ!?
    z-L4pnt@QU1XrT1{$2;iZStX#jU&;Q??k!H7SLn=W_Rz&l
    zrplF6MxNlvv@XA=1m_06BOFLl7vj9_E6{#1U|-3qT}qO;ui|H3z|#eMAzMGYFsOjX
    zqgx#(lA%Ss-W*Cme>!wRr^
    zqS04gDuxl-YsM!}4Gw<#VT{-3X?O?OOYuyeEFU<8ZruDCazjQhqg2L3+y}{*70wB9
    z<_tC1s&tNTVWQ2SaCU30Z=&)C9$xsqk{fd=RMHMWr1@I*dh@r{!xm$!v#;GA<`AE-
    zbI}P9tnXG|4Rw>=#>?yM>J_OsqBbKlrCM`LXx9ql2sYYX`_nC_Q6YD8^6OV3@?uM2
    zXeO%*idIp`Mw?s@Q8aFKb3-M0e~5ZR``O0*UHLAhw9InYHq9ijGja5xPC$GHCUI9q
    zMD82(9HsUPh*aqR)#oLV)WKuIxx>gZ-I<297Ou#utNPLTbxu_On?{U-n*H_ANwh$e
    zn&(}pdgD=r&HcFfFXdJPf;q!sOsB32TeXTApWlS2^OIcq?ZQD?+&Z{O;wUZ
    zmGX)c=A1XI{aTHWhZWfN1)d&Vy=|O*!EVxGEmR_%&$@nW9Uo7Qt>SHL^rWaKM%$Ar6P7ZFg
    zcnfi=me^O0t>zLJ?BD5wJ1G#-WfKRBOpKc4`(V>QCxcmx_q=3HS&y6Hj)u{@!U@p|
    z1##Tfdhs%fEy^`1aU?>OB5}!79)2B;fV2Mo)qnsn9Z1YN@+c4=6#+i@bn)RahkgRT
    sV$@BAs&e}Pha44RmB81S)iX|pl1FlsRgGBUC<
    zurx6(>Gsk;Sbn%ibz|G+b3czQnUma9n4fTi{d$GGnOoAbfE=z(YEH|V-QBqQb@r>N
    zPcUo#X=u1lvGqW4=XH~nN=|XYIvpZ6%3d6ey5-+zwEe^nrxj6iuJAFY?RwbZZ`*k6
    zqWOiyw{It$$#I=>)}X`3P0gnB+3CQy-)B9wn8Luv2$2(Vd^Toh1ZvOoPL{S9Vb!sR(;-_hMoFlbGdJ=W8P@u-NZR@;V6wawl4@wFJA(Yexdr!3z_1^LQ4y2vOB
    z@^7E4le*z_c
    zYQ1Bfo_<7-t6$fr=W(*XAFNn5{pU;ZyH;$f_CGr6roC6G-+s<$gT`j|^zQX}i+?tS
    zuHpQco6Zq;`Oe{Z`M;B&dmenXWVNxNwnp}wDbaeBf33X{
    z^L?}UpAJiyB8|$qzNFdtZ+#OvdB579^EOGu4n1FiI^{}xovLqo>PP#k&lT}a>a8jJn7Ko8X4(VSYm7JEJaJw(
    zO=z*n`&6TKi#JbqZ8CdVH0$~6yIUqc7M-kJ)R5h}V$GqzybFQG2~prQ%^IO+YG4UW
    z$~wTLtYOf^IFX6P;ce+f170>xtu~Lg@4SqREUXL$(T3axoNUaYENsF|Zb62820S1R
    zhcK&WacWVjp`Zajh|ey};a-%Qm!FiAYRF^21rp*CW)3dRGvqbk2JyIsS-gybU15^U
    z!pvU25e9PNyapx)<^~pqW=3YF=27Cj#+C+V#s*L>Z7pw{kL*`q{$+0LWiV*$WNK_=
    z__FfU6roS@d?wSXCUu|u5~!fcQ?FBa>
    z)7%gK%SsPOr`BBg#3#;QePM@Jkb;Trl(lcH3|`cUzgSqnsk&#vXREg2lczuQT&%xQ
    z6Cri5wQy;p@vkh!FOMT{rsTio`1C%uk(~#O3TB|Y`fks?q-kzy
    z!Fc?*!u*M@ZFR<%?=9TkIoH?Is>i)p(sQuBp2brmW>LFB%?gU-(F$6E+9hhWs(7rT
    zX0=w3+EP?$#d`Xl_dR{i`{{i@+;h+U{qO&N{GSWQKpq1D^l%JBi-8%IXq5Pa6~G86
    z!a(Ff7>LX-ED6VetNu#@6F?Yn-Y=Z{tFjna{^No|0Kg&)Smzhif_wgUfLYG9_aA)MZ7gf;saw=5V-@Sb`)
    zj+EBr?LIur=djfrJUgXj4xx3i5{>!k;%Obgw6T4|WKE-z(n@bY!Jxkb-whAm~gSaHNPZ#>?@sHB6Y0+
    zCoQh%oxUsw(4HJo>8j4e#pZX?$K8JsV0^gPBWr$^?dEg$)v@Sc%Cv3g_WliY&-p(n
    zFV&*VELN(k#VV$5Dn}$47Dy|pwdN`~Kl!+}c-zKhbRPovsd%2%>O!eW68)SORx=V8
    zi_2p+Mw^b1Q7nHEhWJK?*pi>M+&l5-W}QVOX+Ers!>(kg{$Pyt{8(Q$Fg#C+xHY67
    zE-{&PuD|au8KnjB&-vu%YGmaBP5E3S*OZiW(XJ(g9Uj&9)P?W0iHsTef?(ow|!Q8_Sevsw|bPRXMD*e3fRm&$rOXgXN
    z1JC>$GP551fRmR?nX9nozBhB8xJ=sf7c;o|>DJP2+O=S?rPhZsU#Rb5pDiA1O?
    zBUIoRP~h(+Mus8`$n6($0s`oMHS2#A!2b&AmX@}KuZJ+(q&<^U3X0$>D#9Q`zYb_X@|;G#tZoi-O&I={3uquZ%Z
    z;+Oep*Tp(mk6_t?@PbOaFwhy&*m6;M;&G?>iLOVTfP~$qs)o(6=xs@5M_YQO$n+fO)6iOL-q9TSGsFkJPtaJVU~E-hHVVs&g(=RtBa
    z(b6idjTN7_yJa85wZw4MyG_D<*Z(zyXc|p`pZ#d7CqMaabXU8(`zLwtNcqa0LZ(_5
    z*YvSj)YL8k?Z1a4Egk4P&-*xXK3GJg3X(dI(yt)p?CuV`qgKk+halp?+dp``WcJ!?
    z-L4pnt@QU1XrT1{$2;iZStX#jU&;Q??k!H7SLn=W_Rz&l
    zrplF6MxNlvv@XA=1m_06BOFLl7vj9_E6{#1U|-3qT}qO;ui|H3z|#eMAzMGYFsOjX
    zqgx#(lA%Ss-W*Cme>!wRr^
    zqS04gDuxl-YsM!}4Gw<#VT{-3X?O?OOYuyeEFU<8ZruDCazjQhqg2L3+y}{*70wB9
    z<_tC1s&tNTVWQ2SaCU30Z=&)C9$xsqk{fd=RMHMWr1@I*dh@r{!xm$!v#;GA<`AE-
    zbI}P9tnXG|4Rw>=#>?yM>J_OsqBbKlrCM`LXx9ql2sYYX`_nC_Q6YD8^6OV3@?uM2
    zXeO%*idIp`Mw?s@Q8aFKb3-M0e~5ZR``O0*UHLAhw9InYHq9ijGja5xPC$GHCUI9q
    zMD82(9HsUPh*aqR)#oLV)WKuIxx>gZ-I<297Ou#utNPLTbxu_On?{U-n*H_ANwh$e
    zn&(}pdgD=r&HcFfFXdJPf;q!sOsB32TeXTApWlS2^OIcq?ZQD?+&Z{O;wUZ
    zmGX)c=A1XI{aTHWhZWfN1)d&Vy=|O*!EVxGEmR_%&$@nW9Uo7Qt>SHL^rWaKM%$Ar6P7ZFg
    zcnfi=me^O0t>zLJ?BD5wJ1G#-WfKRBOpKc4`(V>QCxcmx_q=3HS&y6Hj)u{@!U@p|
    z1##Tfdhs%fEy^`1aU?>OB5}!79)2B;fV2Mo)qnsn9Z1YN@+c4=6#+i@bn)RahkgRT
    sn8_{3kk5bz#NiNT^(;;;N;MQT;0N*9
    zg*n`dQuFeYa#9U>47fl-T*A!3rFn+D2HYSXw=j#BQLrmal3AG9%QwP6PMp`k#K7FZ
    z!qCjf%+x$eoY&aWz|7bH%B8L4jq{QH%E-#V+}O)t(Ade;*vRl@<*6w`pXB*Wrd3Vq
    zKKUh3L6xU!cbVdoe4z>ID`G0jo7zm&tk@ep{>jhyBlgnKW#Oi|AN-e<9*|D0x$=om
    zoWJ_Q4zC~u6Wb|k-&h&Es1tv&uz*u_&xFrbZN(=~f9Sbbf1@Ts>R@Z((njN7S&CmC
    zN8U`yf6ejr&0P}<+rOR@_A@avGB6@L4;U59KzH@so_k5t+|+{c_;H2#6J6Wtj4$6?
    zxV>|(ucuXyd$FYPs&{G4Z*BjY&)T_PzsUN#9W&?tqX!h$h={+Ew^2}<&lJkJvfzA9
    z{?zE?Q@kAqWt`@|R8YSDce2}Dy_WYa9eM7loX%z5-lbNr`wu?BNNmt`7^q>+8!$B?pR&0Zo)Nj#=x$uOjl
    zHEWhEl?<}RAf9*LJ9XY)@11+@x#xbq_ufCh=OPHu3=j~EAV4+fnWPhp682bu48TVO
    z=wA>5RO%FqAqaHU|0U5CK?rntr#SmG)9IQ2v&8}hf*uj*v`?W1!u|IK9V@~fq4uX`
    zLC8Qj(aT5+ifm=>QB|4V$DGWb5F;re5J-X@1QbHB&@=w~B8Z6&fDoW(x}IPJ#DO6|
    zX$ZUdbH*{1#n#t!LGgx6p=B@#0W$c+7^HQ8F11`Jv0Na;W+AVM^;zFwP@)}T>;`>iosjl1q~HQ_*FH7jwcEMi
    z!RXq8q``c*TRd<~SK$$E%Sd8A*N$-;I_)HxGZU6qWLOX@`(0PmYYHDZ`~*&#F>y;1
    z8M)w37RT=&p+i9{ZjE17`V*tPa-4-CswN39
    z`uHUz<)UEb*?o!D1#!B!{Din4En>L4HG*m#k;hY)WYc?lZ%`Oe{n`(S+vgf!s8Fc%yNTNy?y%@5#wyx*vlfWp?^1n*$p1#UN#
    zs~%$xPVJhynWI0n%$FYBDGqf|f}K3(enqJ>-F>DHnT>%)ajMHiHn
    zMYh_W6{~j*-xqX}0oo;9#5I$@M)b=fYhE6|0yo87on9v^_lQEQjY$8t0_89|yYd(N^|}S%Cm3(q#(H;L*heg?Ziw
    z*54sZQy;w;?>68K=e`;Q$kzXiRPu%rJ1(&zNylpy?mGlo6CJK;v^^zuCa@(1pD4j$
    zT{)U|Cl+Oviz!p?b5!;kgTAOxy&WXxv~N_7>@4sR7em5WC^bzszFiMDCr9q>6%5oL
    zd_6AOrIisHF~$`8LN(%9oeWQ4uGc=^*=cE}xTWOBvHah5jEaxz)|3$PYe%=nE6cw1
    zScRr$ehA)}vgI*BCWoMcR&1otjfd>SbU(GLG<3_?nr7<9zOxpaX{3}FtXW#Vy_~=m
    z`K1lAp_1KRlBKNweu&ji|%mxm*DUqsbiE?`y)l2ww
    zqqu`P>gT|s+{U1*VsT_yy{rEIlSp~v((97VRah70wa}l7k;5OdPXZXSq=R89KeZJ4
    zu(O8gAwyJ!4B9cwPMGP_HIl9w{(!snVY8O>s3&>f!M1oYwifeU$+#XWsX$;GV-AyP
    z*Rxg7MDYH$OD0YQ7C|V$3lIvp1;7D95yF2YE(J~q%<85WPDlZ%f>cpfS5rbLo(2Kp
    z`+JCi{t*G7K=k}SCcUw01;dbU
    z_yp03cgNT0yT%Z}pU>wJiNUTi1J7Vh2Ss~5T@#a#34zX5
    z$8XB(jgyPuau-MzgS%rl9H^L4Gh#kTs(rvjz4P#`$bdJ0c@O$(V$dL*s-mwx5^Ij>
    zZ8?Z*`V{gSW0-@bBZtxj*R#reeQnu1qai6oqP8E-8)WM))K}=UtXlz
    zrQ*s&!c2+2(!pv*e|1*#9LmdcKGX<1%CW#!&A?P`P&&odkP0LE-g>X^DSX-#Y>uK?
    zxPxQsK%n71>}vYR1J24zQGr!i!m^IH@s_+}Pw+`bR?AL2j5)(II0n<><{uYheOua7
    z0;h-JpC+QM`bv)i?t5O;ZZABu9_@1Andf|G!#`tP$eU<8>OP5-pulP7on+6+le)T?
    z@<4B2pz8I7rXJDLc-#Wuo7GlIwTq_edO
    zaFHebso&#}rm)2|4E?LNdp_4FO@$(N{wh`L*^Fent3&d4TN5H0<>A({o1%{el`&Tm
    zpv1VhnKmy!I;>N5y
    z8z2UtdsQ06D!B)wl89|x^QmWggP%-tygmGKrE)I%zr|jD>ym8-ra#(R?U*Y#xmvw4
    zOy0~!8$A82`Pn@IV2qmmg+L<|5Ujs{H4u;v01-O3k^jn9o*hH3scy;C(AjqKnPS)FR?K>|cBMU2oL9`*a0Vf-CC<~h~lUtA>p8*eu!y(M-S)5vwYA9&H58|^6
    zbGR3!=H(~lq#E)VaDjxlgqed&^9*?nxIsK_VHPi=U{{zVvoN!lZ-jxIIIn?;fw_T&
    zp_!4HsZo?Tud$_pnXv(sOIynu=Og=-k(GhDv6sQ1v6HE>kzwwxiSqj=aZNsO+t!Ll
    zhxuSw=PY;2S-k1-5r3vWJ2J=2#A=Ufio}wx-Q}~ta|D%y>Av!4T*X?x@IFIZzrNgo
    z6ImOC{&KIVxV-pBLY3sAUrl=#%;w3kYAR{5)7@9D*YCnnaNPc!!UPR9r!~8TK25y7
    zMoGDE?iYJT-gggoG(`nuGBGnUFd{n-7!}MwcL^?@nEfcw@63h|LG`Kff3H=)GvM4+
    zyrVGoQ3AyVv2uEW=r^gl^u5Yc{i5-pDL8i{+%UK&tM|=mZ^0ZjCdkTWrPHh)P2vH9D
    zK;l9Yq$IAGXgZ{+jE9Jji3vm`l1L=;Gs<{lGDI>q-!h#BW)lGl!H9!u?Px6@Yhc~z+0d)cWb1FHUdDD>v?R^y?>
    ze;zQg?ISZkOBt5BW<$wvqqyX$uf?nGwdz}{NU{MD?FGj2`myVMwKfS;+ss$_MmD;w
    znMZ>y&~qET-j`mGs#dbs-}Ha7_e|)mwZnTW8XIoBj3gleg@%wIxbtoaVHqId
    z+6AP?j|?jEo48OgjZNiWISS;RQ>?|Na%-rb>IXjx<5D{vkyM$F@sYUvGY?Z6rR(mn
    zN|aB_H~87VS!JloHElFlCGD-XGOQKk(GHxCw6wU&J=IVqLaF!Q<``QAshTBX_(7-Lwc^apJww79s*vsUTR{Wc2v
    zs{~p+6u0+cj|ci#)v3gxZf8&d?1&%J&u;jpZPjqKOQ+sr)a}{NMHj|`oog@vuE%;L
    zzfBd#&%%e(%tZ&`T^q;UyAZ8e?emoB$ka3V}*sKIu{;ZQX}67x>9%gS2ICp
    zH4R#hU<coWLbNTG*;N`cF;Q1{pad6})&{!wmOG3)S`#{9htC(V|1
    za@LE&yR|~!tXGpSk0h}|+8iRJi6fTnsW&ZB9=u+2Y@OIwl;x$r@V$uBS9DzCIC~z|
    zA_fC5a7$Dc^MC1F&ahpXz{TC*d>pQ{R{1D`hu0nb)><)BVQAtGeUCPF+~<|k>MT*C
    zJH_F(XBW>SQg`xiFSnPxXP<8(D-Ecm>xbeTB3{%b&iHmcwd`e$LW8=G<9=@1Dzixr
    z<~~`Ty_~1@omDnZn5O@{`|yC(%#bI?&Y+Iuap|^Ywi^glU{~foY{8RD@z;GK&
    z+H77z_Loja>6F-y&16PB=8XY`3#zFJV))&BV!ms
    zyXOY84a^7Kwi{GCr4OU5W%m0KVrRA|?MymFD;?wZsZNuHSM+R&x$?Arm{v&A@rPUBjQ^^MfqYD8a`49%{
    zpJfkby|D)IC@m!omsonVyStON9X*=PfIq7sZ5uj+85SHC2pjJ(SfRt{{JhKdhPPb(
    z;XbzT&<{^m1|hBA7_0&*{W*gnJ;??bH9IJE=tCBPo*WPr8%ei{fs=*@MHofXnK?)U
    z~3aEn!4n;G(ciyuP8
    zsznt3Yrrlj+@A9!>zTzOU2`Ay>1Isn-M8#9$aki`XFzP+SZ}^DJgOMiLwn|ZS6^-!
    zm=EZW)_Y6+R?Z~7y1XSz+>s&@j-Aw%zQY}b{u%-P8Ug-mK>L3f0WuHHo!wu+LAs>S
    O7Sr#R-7eCxQu+@^S{GCR
    
    diff --git a/test/jdk/javax/net/ssl/HttpsURLConnection/trusted.jks b/test/jdk/javax/net/ssl/HttpsURLConnection/trusted.jks
    deleted file mode 100644
    index 0202bec16205771e8143c9bb2ca5d13d015dc6bf..0000000000000000000000000000000000000000
    GIT binary patch
    literal 0
    HcmV?d00001
    
    literal 743
    zcmezO_TO6u1_mY|W(3nLiSfyaK#n8_!;~outPy&q29`kiRR&E=%Yc}F0W%XL6B8qY
    z0WTY;R+~rLcV0$D7FGrWcSCLiPB!LH7B*p~&|pJh13?gnLzpW#KQ~o3xFoS8)lkrY
    zA0)^n%mETq@GnX?6foce2{8+^gM{+)QVrz9c?}E=jExNp4NXi;%%jA4jVugIjLe~2
    z>RHq{AK4F#tPISJy$lA8olK3531z*mub}oJLyX0e!p0moXR{Jz7)>q%pMNfZZviL*$mme1+g`zUHSEQ_D
    zVrFDuT->C)WBL^Wc888FGF0sD&`eo6LTbCN7g*I7loNv$2
    z)gZc>vuf!o>o6H@#muGF2fdlCd0csOxO$?_RBhqju)A@Zc(~x^c#j{SiX;WLe&6g+
    zF0|S~clG|RP|b-sHdYIk25z4Hl||+>*Q=smy;U`LzW
    Date: Mon, 1 Dec 2025 12:30:02 +0000
    Subject: [PATCH 071/706] 8372409:
     java/net/httpclient/http3/H3MultipleConnectionsToSameHost.java timed out
     during warmup
    
    Reviewed-by: djelinski
    ---
     .../internal/net/http/Http3Connection.java    | 23 ++++++++++++++++++-
     .../H3MultipleConnectionsToSameHost.java      |  8 +++----
     2 files changed, 26 insertions(+), 5 deletions(-)
    
    diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/Http3Connection.java b/src/java.net.http/share/classes/jdk/internal/net/http/Http3Connection.java
    index 17f230f3b15..6bf1b9184f8 100644
    --- a/src/java.net.http/share/classes/jdk/internal/net/http/Http3Connection.java
    +++ b/src/java.net.http/share/classes/jdk/internal/net/http/Http3Connection.java
    @@ -561,7 +561,28 @@ public final class Http3Connection implements AutoCloseable {
             if (debug.on()) debug.log("Reference h3 stream: " + streamId);
             client.client.h3StreamReference();
             exchanges.put(streamId, exchange);
    -        exchange.start();
    +        // It's possible that the connection will have been closed
    +        // by the time we reach here.
    +        // We need to double-check that the connection is still opened
    +        // after having put the exchange to the exchanges map.
    +        if (isOpen()) {
    +            // only start the exchange if the connection is
    +            // still open
    +            exchange.start();
    +        } else {
    +            // Otherwise mark the exchange as unprocessed since we haven't
    +            // sent the headers yet and the connection got closed
    +            // before we started the exchange.
    +            TerminationCause tc = quicConnection.terminationCause();
    +            if (Log.http3()) {
    +                Log.logHttp3("HTTP/3 exchange for {0}/streamId={1} unprocessed due to {2}",
    +                        quicConnectionTag(), Long.toString(streamId), tc.getCloseCause());
    +            }
    +            exchange.exchange.markUnprocessedByPeer();
    +            exchange.cancelImpl(tc.getCloseCause(),
    +                    Http3Error.fromCode(tc.getCloseCode()).orElse(H3_NO_ERROR));
    +        }
    +        // OK to return the exchange even if already closed
             return exchange;
         }
     
    diff --git a/test/jdk/java/net/httpclient/http3/H3MultipleConnectionsToSameHost.java b/test/jdk/java/net/httpclient/http3/H3MultipleConnectionsToSameHost.java
    index 34d5163760f..862ccf22ddc 100644
    --- a/test/jdk/java/net/httpclient/http3/H3MultipleConnectionsToSameHost.java
    +++ b/test/jdk/java/net/httpclient/http3/H3MultipleConnectionsToSameHost.java
    @@ -23,7 +23,7 @@
     
     /*
      * @test id=with-continuations
    - * @bug 8087112
    + * @bug 8087112 8372409
      * @requires os.family != "windows" | ( os.name != "Windows 10" & os.name != "Windows Server 2016"
      *                                      & os.name != "Windows Server 2019" )
      * @library /test/lib /test/jdk/java/net/httpclient/lib
    @@ -46,7 +46,7 @@
      */
     /*
      * @test id=without-continuations
    - * @bug 8087112
    + * @bug 8087112 8372409
      * @requires os.family == "windows" & ( os.name == "Windows 10" | os.name == "Windows Server 2016"
      *                                     | os.name == "Windows Server 2019" )
      * @library /test/lib /test/jdk/java/net/httpclient/lib
    @@ -71,7 +71,7 @@
      */
     /*
      * @test id=useNioSelector
    - * @bug 8087112
    + * @bug 8087112 8372409
      * @library /test/lib /test/jdk/java/net/httpclient/lib
      * @build jdk.test.lib.net.SimpleSSLContext
      *        jdk.httpclient.test.lib.http2.Http2TestServer
    @@ -96,7 +96,7 @@
      */
     /*
      * @test id=reno-cc
    - * @bug 8087112
    + * @bug 8087112 8372409
      * @library /test/lib /test/jdk/java/net/httpclient/lib
      * @build jdk.test.lib.net.SimpleSSLContext
      *        jdk.httpclient.test.lib.http2.Http2TestServer
    
    From b98114f4a20bcf3390114b56d05c38b23268979a Mon Sep 17 00:00:00 2001
    From: Coleen Phillimore 
    Date: Mon, 1 Dec 2025 13:28:21 +0000
    Subject: [PATCH 072/706] 8365526: Crash with null Symbol passed to
     SystemDictionary::resolve_or_null
    
    Reviewed-by: dholmes, never, jsjolen
    ---
     src/hotspot/share/classfile/resolutionErrors.cpp | 13 +++++++++++--
     src/hotspot/share/classfile/resolutionErrors.hpp |  7 ++-----
     src/hotspot/share/classfile/systemDictionary.cpp | 13 +++++++++----
     3 files changed, 22 insertions(+), 11 deletions(-)
    
    diff --git a/src/hotspot/share/classfile/resolutionErrors.cpp b/src/hotspot/share/classfile/resolutionErrors.cpp
    index 25aa370d257..f5a335f17f3 100644
    --- a/src/hotspot/share/classfile/resolutionErrors.cpp
    +++ b/src/hotspot/share/classfile/resolutionErrors.cpp
    @@ -73,7 +73,7 @@ void ResolutionErrorTable::add_entry(const constantPoolHandle& pool, int cp_inde
     
       ResolutionErrorKey key(pool(), cp_index);
       ResolutionErrorEntry *entry = new ResolutionErrorEntry(error, message, cause, cause_msg);
    -  _resolution_error_table->put(key, entry);
    +  _resolution_error_table->put_when_absent(key, entry);
     }
     
     // create new nest host error entry
    @@ -85,7 +85,7 @@ void ResolutionErrorTable::add_entry(const constantPoolHandle& pool, int cp_inde
     
       ResolutionErrorKey key(pool(), cp_index);
       ResolutionErrorEntry *entry = new ResolutionErrorEntry(message);
    -  _resolution_error_table->put(key, entry);
    +  _resolution_error_table->put_when_absent(key, entry);
     }
     
     // find entry in the table
    @@ -126,6 +126,15 @@ ResolutionErrorEntry::~ResolutionErrorEntry() {
       }
     }
     
    +void ResolutionErrorEntry::set_nest_host_error(const char* message) {
    +  // If a message is already set, free it.
    +  if (nest_host_error() != nullptr) {
    +    FREE_C_HEAP_ARRAY(char, _nest_host_error);
    +  }
    +  _nest_host_error = message;
    +}
    +
    +
     class ResolutionErrorDeleteIterate : StackObj {
       ConstantPool* p;
     
    diff --git a/src/hotspot/share/classfile/resolutionErrors.hpp b/src/hotspot/share/classfile/resolutionErrors.hpp
    index 60f8aea68ef..39859ad2b70 100644
    --- a/src/hotspot/share/classfile/resolutionErrors.hpp
    +++ b/src/hotspot/share/classfile/resolutionErrors.hpp
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 2005, 2025, 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
    @@ -91,10 +91,7 @@ class ResolutionErrorEntry : public CHeapObj {
       ~ResolutionErrorEntry();
     
       // The incoming nest host error message is already in the C-Heap.
    -  void set_nest_host_error(const char* message) {
    -    _nest_host_error = message;
    -  }
    -
    +  void set_nest_host_error(const char* message);
     
       Symbol*            error() const              { return _error; }
       const char*        message() const            { return _message; }
    diff --git a/src/hotspot/share/classfile/systemDictionary.cpp b/src/hotspot/share/classfile/systemDictionary.cpp
    index 5c49a32b8d0..a17e7e129ce 100644
    --- a/src/hotspot/share/classfile/systemDictionary.cpp
    +++ b/src/hotspot/share/classfile/systemDictionary.cpp
    @@ -1864,14 +1864,19 @@ void SystemDictionary::add_nest_host_error(const constantPoolHandle& pool,
       {
         MutexLocker ml(Thread::current(), SystemDictionary_lock);
         ResolutionErrorEntry* entry = ResolutionErrorTable::find_entry(pool, which);
    -    if (entry != nullptr && entry->nest_host_error() == nullptr) {
    +    if (entry == nullptr) {
    +      // Only add a new entry to the resolution error table if one hasn't been found for this
    +      // constant pool index. In this case resolution succeeded but there's an error in this nest host
    +      // that we use the table to record.
    +      assert(pool->resolved_klass_at(which) != nullptr, "klass should be resolved if there is no entry");
    +      ResolutionErrorTable::add_entry(pool, which, message);
    +    } else {
           // An existing entry means we had a true resolution failure (LinkageError) with our nest host, but we
           // still want to add the error message for the higher-level access checks to report. We should
           // only reach here under the same error condition, so we can ignore the potential race with setting
    -      // the message. If we see it is already set then we can ignore it.
    +      // the message, and set it again.
    +      assert(entry->nest_host_error() == nullptr || strcmp(entry->nest_host_error(), message) == 0, "should be the same message");
           entry->set_nest_host_error(message);
    -    } else {
    -      ResolutionErrorTable::add_entry(pool, which, message);
         }
       }
     }
    
    From d328e4e7e2f58fbfeb661f3502f95016159d7230 Mon Sep 17 00:00:00 2001
    From: Matthias Baesken 
    Date: Mon, 1 Dec 2025 13:37:32 +0000
    Subject: [PATCH 073/706] 8372272: Hotspot shared lib loading - add load
     attempts to Events::log
    
    Reviewed-by: lucy, azeller
    ---
     src/hotspot/os/aix/os_aix.cpp         | 2 ++
     src/hotspot/os/bsd/os_bsd.cpp         | 2 ++
     src/hotspot/os/linux/os_linux.cpp     | 2 ++
     src/hotspot/os/windows/os_windows.cpp | 2 ++
     4 files changed, 8 insertions(+)
    
    diff --git a/src/hotspot/os/aix/os_aix.cpp b/src/hotspot/os/aix/os_aix.cpp
    index 48bd5e05816..7de031cac58 100644
    --- a/src/hotspot/os/aix/os_aix.cpp
    +++ b/src/hotspot/os/aix/os_aix.cpp
    @@ -1038,6 +1038,8 @@ static void* dll_load_library(const char *filename, int *eno, char *ebuf, int eb
         dflags |= RTLD_MEMBER;
       }
     
    +  Events::log_dll_message(nullptr, "Attempting to load shared library %s", filename);
    +
       void* result;
       const char* error_report = nullptr;
       JFR_ONLY(NativeLibraryLoadEvent load_event(filename, &result);)
    diff --git a/src/hotspot/os/bsd/os_bsd.cpp b/src/hotspot/os/bsd/os_bsd.cpp
    index 0b37cb100f6..0889cc4cdf8 100644
    --- a/src/hotspot/os/bsd/os_bsd.cpp
    +++ b/src/hotspot/os/bsd/os_bsd.cpp
    @@ -1035,6 +1035,8 @@ void *os::Bsd::dlopen_helper(const char *filename, int mode, char *ebuf, int ebu
       int rtn = fegetenv(&default_fenv);
       assert(rtn == 0, "fegetenv must succeed");
     
    +  Events::log_dll_message(nullptr, "Attempting to load shared library %s", filename);
    +
       void* result;
       JFR_ONLY(NativeLibraryLoadEvent load_event(filename, &result);)
       result = ::dlopen(filename, RTLD_LAZY);
    diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp
    index a1d957eb77d..cf64c22ddff 100644
    --- a/src/hotspot/os/linux/os_linux.cpp
    +++ b/src/hotspot/os/linux/os_linux.cpp
    @@ -1875,6 +1875,8 @@ void * os::Linux::dlopen_helper(const char *filename, char *ebuf, int ebuflen) {
       assert(rtn == 0, "fegetenv must succeed");
     #endif // IA32
     
    +  Events::log_dll_message(nullptr, "Attempting to load shared library %s", filename);
    +
       void* result;
       JFR_ONLY(NativeLibraryLoadEvent load_event(filename, &result);)
       result = ::dlopen(filename, RTLD_LAZY);
    diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp
    index 8a450a291d3..b9aeb4e8dd6 100644
    --- a/src/hotspot/os/windows/os_windows.cpp
    +++ b/src/hotspot/os/windows/os_windows.cpp
    @@ -1715,6 +1715,8 @@ static int _print_module(const char* fname, address base_address,
     // same architecture as Hotspot is running on
     void * os::dll_load(const char *name, char *ebuf, int ebuflen) {
       log_info(os)("attempting shared library load of %s", name);
    +  Events::log_dll_message(nullptr, "Attempting to load shared library %s", name);
    +
       void* result;
       JFR_ONLY(NativeLibraryLoadEvent load_event(name, &result);)
       result = LoadLibrary(name);
    
    From a1cc8f4e4107e361f64cf51ff73985e471cdde03 Mon Sep 17 00:00:00 2001
    From: William Kemper 
    Date: Mon, 1 Dec 2025 15:37:39 +0000
    Subject: [PATCH 074/706] 8372444: Genshen: Optimize evacuation function
    
    Reviewed-by: ysr, xpeng
    ---
     .../shenandoah/shenandoahGenerationalHeap.cpp | 71 +++++++++----------
     .../shenandoah/shenandoahGenerationalHeap.hpp |  4 +-
     .../shenandoahGenerationalHeap.inline.hpp     |  1 +
     .../gc/shenandoah/shenandoahOldGeneration.cpp |  2 +-
     .../gc/shenandoah/shenandoahOldGeneration.hpp |  2 +-
     5 files changed, 41 insertions(+), 39 deletions(-)
    
    diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp
    index e582ea6b189..134ae371bce 100644
    --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp
    +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp
    @@ -208,13 +208,13 @@ oop ShenandoahGenerationalHeap::evacuate_object(oop p, Thread* thread) {
     
       assert(ShenandoahThreadLocalData::is_evac_allowed(thread), "must be enclosed in oom-evac scope");
     
    -  ShenandoahHeapRegion* r = heap_region_containing(p);
    -  assert(!r->is_humongous(), "never evacuate humongous objects");
    +  ShenandoahHeapRegion* from_region = heap_region_containing(p);
    +  assert(!from_region->is_humongous(), "never evacuate humongous objects");
     
    -  ShenandoahAffiliation target_gen = r->affiliation();
    -  // gc_generation() can change asynchronously and should not be used here.
    -  assert(active_generation() != nullptr, "Error");
    -  if (active_generation()->is_young() && target_gen == YOUNG_GENERATION) {
    +  // Try to keep the object in the same generation
    +  const ShenandoahAffiliation target_gen = from_region->affiliation();
    +
    +  if (target_gen == YOUNG_GENERATION) {
         markWord mark = p->mark();
         if (mark.is_marked()) {
           // Already forwarded.
    @@ -224,26 +224,31 @@ oop ShenandoahGenerationalHeap::evacuate_object(oop p, Thread* thread) {
         if (mark.has_displaced_mark_helper()) {
           // We don't want to deal with MT here just to ensure we read the right mark word.
           // Skip the potential promotion attempt for this one.
    -    } else if (age_census()->is_tenurable(r->age() + mark.age())) {
    -      oop result = try_evacuate_object(p, thread, r, OLD_GENERATION);
    +    } else if (age_census()->is_tenurable(from_region->age() + mark.age())) {
    +      // If the object is tenurable, try to promote it
    +      oop result = try_evacuate_object(p, thread, from_region->age());
    +
    +      // If we failed to promote this aged object, we'll fall through to code below and evacuate to young-gen.
           if (result != nullptr) {
             return result;
           }
    -      // If we failed to promote this aged object, we'll fall through to code below and evacuate to young-gen.
         }
    +    return try_evacuate_object(p, thread, from_region->age());
       }
    -  return try_evacuate_object(p, thread, r, target_gen);
    +
    +  assert(target_gen == OLD_GENERATION, "Expected evacuation to old");
    +  return try_evacuate_object(p, thread, from_region->age());
     }
     
     // try_evacuate_object registers the object and dirties the associated remembered set information when evacuating
     // to OLD_GENERATION.
    -oop ShenandoahGenerationalHeap::try_evacuate_object(oop p, Thread* thread, ShenandoahHeapRegion* from_region,
    -                                        ShenandoahAffiliation target_gen) {
    +template
    +oop ShenandoahGenerationalHeap::try_evacuate_object(oop p, Thread* thread, uint from_region_age) {
       bool alloc_from_lab = true;
       bool has_plab = false;
       HeapWord* copy = nullptr;
       size_t size = ShenandoahForwarding::size(p);
    -  bool is_promotion = (target_gen == OLD_GENERATION) && from_region->is_young();
    +  constexpr bool is_promotion = (TO_GENERATION == OLD_GENERATION) && (FROM_GENERATION == YOUNG_GENERATION);
     
     #ifdef ASSERT
       if (ShenandoahOOMDuringEvacALot &&
    @@ -252,7 +257,7 @@ oop ShenandoahGenerationalHeap::try_evacuate_object(oop p, Thread* thread, Shena
       } else {
     #endif
         if (UseTLAB) {
    -      switch (target_gen) {
    +      switch (TO_GENERATION) {
             case YOUNG_GENERATION: {
               copy = allocate_from_gclab(thread, size);
               if ((copy == nullptr) && (size < ShenandoahThreadLocalData::gclab_size(thread))) {
    @@ -300,7 +305,7 @@ oop ShenandoahGenerationalHeap::try_evacuate_object(oop p, Thread* thread, Shena
         if (copy == nullptr) {
           // If we failed to allocate in LAB, we'll try a shared allocation.
           if (!is_promotion || !has_plab || (size > PLAB::min_size())) {
    -        ShenandoahAllocRequest req = ShenandoahAllocRequest::for_shared_gc(size, target_gen, is_promotion);
    +        ShenandoahAllocRequest req = ShenandoahAllocRequest::for_shared_gc(size, TO_GENERATION, is_promotion);
             copy = allocate_memory(req);
             alloc_from_lab = false;
           }
    @@ -314,8 +319,8 @@ oop ShenandoahGenerationalHeap::try_evacuate_object(oop p, Thread* thread, Shena
     #endif
     
       if (copy == nullptr) {
    -    if (target_gen == OLD_GENERATION) {
    -      if (from_region->is_young()) {
    +    if (TO_GENERATION == OLD_GENERATION) {
    +      if (FROM_GENERATION == YOUNG_GENERATION) {
             // Signal that promotion failed. Will evacuate this old object somewhere in young gen.
             old_generation()->handle_failed_promotion(thread, size);
             return nullptr;
    @@ -327,14 +332,12 @@ oop ShenandoahGenerationalHeap::try_evacuate_object(oop p, Thread* thread, Shena
         }
     
         control_thread()->handle_alloc_failure_evac(size);
    -
         oom_evac_handler()->handle_out_of_memory_during_evacuation();
    -
         return ShenandoahBarrierSet::resolve_forwarded(p);
       }
     
       if (ShenandoahEvacTracking) {
    -    evac_tracker()->begin_evacuation(thread, size * HeapWordSize, from_region->affiliation(), target_gen);
    +    evac_tracker()->begin_evacuation(thread, size * HeapWordSize, FROM_GENERATION, TO_GENERATION);
       }
     
       // Copy the object:
    @@ -342,8 +345,8 @@ oop ShenandoahGenerationalHeap::try_evacuate_object(oop p, Thread* thread, Shena
       oop copy_val = cast_to_oop(copy);
     
       // Update the age of the evacuated object
    -  if (target_gen == YOUNG_GENERATION && is_aging_cycle()) {
    -    ShenandoahHeap::increase_object_age(copy_val, from_region->age() + 1);
    +  if (TO_GENERATION == YOUNG_GENERATION && is_aging_cycle()) {
    +    increase_object_age(copy_val, from_region_age + 1);
       }
     
       // Try to install the new forwarding pointer.
    @@ -360,18 +363,12 @@ oop ShenandoahGenerationalHeap::try_evacuate_object(oop p, Thread* thread, Shena
     
         if (ShenandoahEvacTracking) {
           // Record that the evacuation succeeded
    -      evac_tracker()->end_evacuation(thread, size * HeapWordSize, from_region->affiliation(), target_gen);
    +      evac_tracker()->end_evacuation(thread, size * HeapWordSize, FROM_GENERATION, TO_GENERATION);
         }
     
    -    if (target_gen == OLD_GENERATION) {
    -      old_generation()->handle_evacuation(copy, size, from_region->is_young());
    -    } else {
    -      // When copying to the old generation above, we don't care
    -      // about recording object age in the census stats.
    -      assert(target_gen == YOUNG_GENERATION, "Error");
    +    if (TO_GENERATION == OLD_GENERATION) {
    +      old_generation()->handle_evacuation(copy, size);
         }
    -    shenandoah_assert_correct(nullptr, copy_val);
    -    return copy_val;
       }  else {
         // Failed to evacuate. We need to deal with the object that is left behind. Since this
         // new allocation is certainly after TAMS, it will be considered live in the next cycle.
    @@ -382,7 +379,7 @@ oop ShenandoahGenerationalHeap::try_evacuate_object(oop p, Thread* thread, Shena
           // For LAB allocations, it is enough to rollback the allocation ptr. Either the next
           // object will overwrite this stale copy, or the filler object on LAB retirement will
           // do this.
    -      switch (target_gen) {
    +      switch (TO_GENERATION) {
             case YOUNG_GENERATION: {
               ShenandoahThreadLocalData::gclab(thread)->undo_allocation(copy, size);
               break;
    @@ -405,14 +402,16 @@ oop ShenandoahGenerationalHeap::try_evacuate_object(oop p, Thread* thread, Shena
           // we have to keep the fwdptr initialized and pointing to our (stale) copy.
           assert(size >= ShenandoahHeap::min_fill_size(), "previously allocated object known to be larger than min_size");
           fill_with_object(copy, size);
    -      shenandoah_assert_correct(nullptr, copy_val);
    -      // For non-LAB allocations, the object has already been registered
         }
    -    shenandoah_assert_correct(nullptr, result);
    -    return result;
       }
    +  shenandoah_assert_correct(nullptr, result);
    +  return result;
     }
     
    +template oop ShenandoahGenerationalHeap::try_evacuate_object(oop p, Thread* thread, uint from_region_age);
    +template oop ShenandoahGenerationalHeap::try_evacuate_object(oop p, Thread* thread, uint from_region_age);
    +template oop ShenandoahGenerationalHeap::try_evacuate_object(oop p, Thread* thread, uint from_region_age);
    +
     inline HeapWord* ShenandoahGenerationalHeap::allocate_from_plab(Thread* thread, size_t size, bool is_promotion) {
       assert(UseTLAB, "TLABs should be enabled");
     
    diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.hpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.hpp
    index ed0223dc6fd..704c8538397 100644
    --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.hpp
    +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.hpp
    @@ -87,7 +87,9 @@ public:
       void update_region_ages(ShenandoahMarkingContext* ctx);
     
       oop evacuate_object(oop p, Thread* thread) override;
    -  oop try_evacuate_object(oop p, Thread* thread, ShenandoahHeapRegion* from_region, ShenandoahAffiliation target_gen);
    +
    +  template
    +  oop try_evacuate_object(oop p, Thread* thread, uint from_region_age);
     
       // In the generational mode, we will use these two functions for young, mixed, and global collections.
       // For young and mixed, the generation argument will be the young generation, otherwise it will be the global generation.
    diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.inline.hpp
    index 8289b48185b..aa20c686bd8 100644
    --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.inline.hpp
    +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.inline.hpp
    @@ -34,4 +34,5 @@ inline bool ShenandoahGenerationalHeap::is_tenurable(const ShenandoahHeapRegion*
       return _age_census->is_tenurable(r->age());
     }
     
    +
     #endif // SHARE_GC_SHENANDOAH_SHENANDOAHGENERATIONALHEAP_INLINE_HPP
    diff --git a/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp b/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp
    index 338c99c7c55..838326c0288 100644
    --- a/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp
    +++ b/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp
    @@ -619,7 +619,7 @@ void ShenandoahOldGeneration::log_failed_promotion(LogStream& ls, Thread* thread
       }
     }
     
    -void ShenandoahOldGeneration::handle_evacuation(HeapWord* obj, size_t words, bool promotion) {
    +void ShenandoahOldGeneration::handle_evacuation(HeapWord* obj, size_t words) const {
       // Only register the copy of the object that won the evacuation race.
       _card_scan->register_object_without_lock(obj);
     
    diff --git a/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.hpp b/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.hpp
    index cd78ed4ef5e..614a1596287 100644
    --- a/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.hpp
    +++ b/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.hpp
    @@ -179,7 +179,7 @@ public:
       void log_failed_promotion(LogStream& ls, Thread* thread, size_t size) const;
     
       // A successful evacuation re-dirties the cards and registers the object with the remembered set
    -  void handle_evacuation(HeapWord* obj, size_t words, bool promotion);
    +  void handle_evacuation(HeapWord* obj, size_t words) const;
     
       // Clear the flag after it is consumed by the control thread
       bool clear_failed_evacuation() {
    
    From 002fff39aace870b27a9068de1662fcb0b3033a6 Mon Sep 17 00:00:00 2001
    From: Brian Burkhalter 
    Date: Mon, 1 Dec 2025 16:57:59 +0000
    Subject: [PATCH 075/706] 8220816: (fs) Files.createDirectory should make it
     more obvious that it fails when the directory already exists
    
    Reviewed-by: alanb, jpai
    ---
     .../share/classes/java/nio/file/Files.java    | 50 ++++++++++---------
     1 file changed, 27 insertions(+), 23 deletions(-)
    
    diff --git a/src/java.base/share/classes/java/nio/file/Files.java b/src/java.base/share/classes/java/nio/file/Files.java
    index 80c771f5306..3f1d6fae4e4 100644
    --- a/src/java.base/share/classes/java/nio/file/Files.java
    +++ b/src/java.base/share/classes/java/nio/file/Files.java
    @@ -203,7 +203,7 @@ public final class Files {
          * @throws  UnsupportedOperationException
          *          if an unsupported option is specified
          * @throws  FileAlreadyExistsException
    -     *          If a file of that name already exists and the {@link
    +     *          If the path locates an existing file and the {@link
          *          StandardOpenOption#CREATE_NEW CREATE_NEW} option is specified
          *          (optional specific exception)
          * @throws  IOException
    @@ -340,7 +340,7 @@ public final class Files {
          *          if an unsupported open option is specified or the array contains
          *          attributes that cannot be set atomically when creating the file
          * @throws  FileAlreadyExistsException
    -     *          If a file of that name already exists and the {@link
    +     *          If the path locates an existing file and the {@link
          *          StandardOpenOption#CREATE_NEW CREATE_NEW} option is specified
          *          and the file is being opened for writing (optional specific
          *          exception)
    @@ -377,7 +377,7 @@ public final class Files {
          * @throws  UnsupportedOperationException
          *          if an unsupported open option is specified
          * @throws  FileAlreadyExistsException
    -     *          If a file of that name already exists and the {@link
    +     *          If the path locates an existing file and the {@link
          *          StandardOpenOption#CREATE_NEW CREATE_NEW} option is specified
          *          and the file is being opened for writing (optional specific
          *          exception)
    @@ -575,10 +575,11 @@ public final class Files {
             Set.of(StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE);
     
         /**
    -     * Creates a new and empty file, failing if the file already exists. The
    -     * check for the existence of the file and the creation of the new file if
    -     * it does not exist are a single operation that is atomic with respect to
    -     * all other filesystem activities that might affect the directory.
    +     * Creates a new and empty file, failing if {@code path} locates an existing
    +     * file. The check for the existence of the file and the creation of the new
    +     * file if it does not exist are a single operation that is atomic with
    +     * respect to all other filesystem activities that might affect the
    +     * directory.
          *
          * 

    The {@code attrs} parameter is optional {@link FileAttribute * file-attributes} to set atomically when creating the file. Each attribute @@ -598,7 +599,7 @@ public final class Files { * if the array contains an attribute that cannot be set atomically * when creating the file * @throws FileAlreadyExistsException - * If a file of that name already exists + * if {@code path} locates an existing file * (optional specific exception) * @throws IOException * if an I/O error occurs or the parent directory does not exist @@ -611,7 +612,8 @@ public final class Files { } /** - * Creates a new directory. The check for the existence of the file and the + * Creates a new directory, failing if {@code dir} locates an existing + * file. The check for the existence of the file and the * creation of the directory if it does not exist are a single operation * that is atomic with respect to all other filesystem activities that might * affect the directory. The {@link #createDirectories createDirectories} @@ -636,8 +638,8 @@ public final class Files { * if the array contains an attribute that cannot be set atomically * when creating the directory * @throws FileAlreadyExistsException - * if a directory could not otherwise be created because a file of - * that name already exists (optional specific exception) + * if {@code dir} locates an existing file + * (optional specific exception) * @throws IOException * if an I/O error occurs or the parent directory does not exist */ @@ -676,8 +678,8 @@ public final class Files { * if the array contains an attribute that cannot be set atomically * when creating the directory * @throws FileAlreadyExistsException - * if {@code dir} exists but is not a directory (optional specific - * exception) + * if {@code dir} locates an existing file that is not a directory + * (optional specific exception) * @throws IOException * if an I/O error occurs */ @@ -930,7 +932,8 @@ public final class Files { } /** - * Creates a symbolic link to a target (optional operation). + * Creates a symbolic link to a target, failing if {@code link} locates an + * existing file (optional operation). * *

    The {@code target} parameter is the target of the link. It may be an * {@link Path#isAbsolute absolute} or relative path and may not exist. When @@ -964,8 +967,8 @@ public final class Files { * array contains an attribute that cannot be set atomically when * creating the symbolic link * @throws FileAlreadyExistsException - * if a file with the name already exists (optional specific - * exception) + * if {@code link} locates an existing file + * (optional specific exception) * @throws IOException * if an I/O error occurs */ @@ -978,7 +981,8 @@ public final class Files { } /** - * Creates a new link (directory entry) for an existing file (optional + * Creates a new link (directory entry) for an existing file, + * failing if {@code link} locates an existing file (optional * operation). * *

    The {@code link} parameter locates the directory entry to create. @@ -1007,8 +1011,8 @@ public final class Files { * if the implementation does not support adding an existing file * to a directory * @throws FileAlreadyExistsException - * if the entry could not otherwise be created because a file of - * that name already exists (optional specific exception) + * if {@code link} locates an existing file + * (optional specific exception) * @throws IOException * if an I/O error occurs */ @@ -2711,7 +2715,7 @@ public final class Files { * @throws UnsupportedOperationException * if an unsupported option is specified * @throws FileAlreadyExistsException - * If a file of that name already exists and the {@link + * If the path locates an existing file and the {@link * StandardOpenOption#CREATE_NEW CREATE_NEW} option is specified * (optional specific exception) * @@ -2754,7 +2758,7 @@ public final class Files { * @throws UnsupportedOperationException * if an unsupported option is specified * @throws FileAlreadyExistsException - * If a file of that name already exists and the {@link + * If the path locates an existing file and the {@link * StandardOpenOption#CREATE_NEW CREATE_NEW} option is specified * (optional specific exception) * @@ -3161,7 +3165,7 @@ public final class Files { * @throws UnsupportedOperationException * if an unsupported option is specified * @throws FileAlreadyExistsException - * If a file of that name already exists and the {@link + * If the path locates an existing file and the {@link * StandardOpenOption#CREATE_NEW CREATE_NEW} option is specified * (optional specific exception) */ @@ -3222,7 +3226,7 @@ public final class Files { * @throws UnsupportedOperationException * if an unsupported option is specified * @throws FileAlreadyExistsException - * If a file of that name already exists and the {@link + * If the path locates an existing file and the {@link * StandardOpenOption#CREATE_NEW CREATE_NEW} option is specified * (optional specific exception) */ From 6cb1c8f9cfcb797af788ca8fb490f388cc68f525 Mon Sep 17 00:00:00 2001 From: Jiangli Zhou Date: Mon, 1 Dec 2025 17:29:15 +0000 Subject: [PATCH 076/706] 8371864: GaloisCounterMode.implGCMCrypt0 AVX512/AVX2 intrinsics stubs cause AES-GCM encryption failure for certain payload sizes Co-authored-by: Thomas Holenstein Co-authored-by: Lukas Zobernig Reviewed-by: shade, sviswanathan --- .../cpu/x86/stubGenerator_x86_64_aes.cpp | 7 +- .../Cipher/AES/TestGCMSplitBound.java | 145 ++++++++++++++++++ 2 files changed, 150 insertions(+), 2 deletions(-) create mode 100644 test/jdk/com/sun/crypto/provider/Cipher/AES/TestGCMSplitBound.java diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp index f0726ded7e5..1e728ffa279 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp @@ -3524,10 +3524,10 @@ void StubGenerator::aesgcm_avx512(Register in, Register len, Register ct, Regist false, true, false, false, false, ghashin_offset, aesout_offset, HashKey_32); ghash16_avx512(false, true, false, false, true, in, pos, avx512_subkeyHtbl, AAD_HASHx, SHUF_MASK, stack_offset, 16 * 16, 0, HashKey_16); + __ addl(pos, 16 * 16); __ bind(MESG_BELOW_32_BLKS); __ subl(len, 16 * 16); - __ addl(pos, 16 * 16); gcm_enc_dec_last_avx512(len, in, pos, AAD_HASHx, SHUF_MASK, avx512_subkeyHtbl, ghashin_offset, HashKey_16, true, true); __ bind(GHASH_DONE); @@ -4016,13 +4016,15 @@ void StubGenerator::aesgcm_avx2(Register in, Register len, Register ct, Register const Register rounds = r10; const XMMRegister ctr_blockx = xmm9; const XMMRegister aad_hashx = xmm8; - Label encrypt_done, encrypt_by_8_new, encrypt_by_8; + Label encrypt_done, encrypt_by_8_new, encrypt_by_8, exit; //This routine should be called only for message sizes of 128 bytes or more. //Macro flow: //process 8 16 byte blocks in initial_num_blocks. //process 8 16 byte blocks at a time until all are done 'encrypt_by_8_new followed by ghash_last_8' __ xorl(pos, pos); + __ cmpl(len, 128); + __ jcc(Assembler::less, exit); //Generate 8 constants for htbl generateHtbl_8_block_avx2(subkeyHtbl); @@ -4090,6 +4092,7 @@ void StubGenerator::aesgcm_avx2(Register in, Register len, Register ct, Register __ vpxor(xmm0, xmm0, xmm0, Assembler::AVX_128bit); __ vpxor(xmm13, xmm13, xmm13, Assembler::AVX_128bit); + __ bind(exit); } #undef __ diff --git a/test/jdk/com/sun/crypto/provider/Cipher/AES/TestGCMSplitBound.java b/test/jdk/com/sun/crypto/provider/Cipher/AES/TestGCMSplitBound.java new file mode 100644 index 00000000000..133e68b344f --- /dev/null +++ b/test/jdk/com/sun/crypto/provider/Cipher/AES/TestGCMSplitBound.java @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2025, 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 8371864 + * @run main/othervm/timeout=600 TestGCMSplitBound + * @requires (os.simpleArch == "x64" & (vm.cpu.features ~= ".*avx2.*" | + * vm.cpu.features ~= ".*avx512.*")) + * @summary Test GaloisCounterMode.implGCMCrypt0 AVX512/AVX2 intrinsics. + */ + +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; +import java.time.Duration; +import java.util.Arrays; +import javax.crypto.Cipher; +import javax.crypto.SecretKey; +import javax.crypto.spec.GCMParameterSpec; +import javax.crypto.spec.SecretKeySpec; + +public class TestGCMSplitBound { + + static final SecureRandom SECURE_RANDOM = newDefaultSecureRandom(); + + private static SecureRandom newDefaultSecureRandom() { + SecureRandom retval = new SecureRandom(); + retval.nextLong(); // force seeding + return retval; + } + + private static byte[] randBytes(int size) { + byte[] rand = new byte[size]; + SECURE_RANDOM.nextBytes(rand); + return rand; + } + + private static final int IV_SIZE_IN_BYTES = 12; + private static final int TAG_SIZE_IN_BYTES = 16; + + private Cipher getCipher(final byte[] key, final byte[] aad, + final byte[] nonce, int mode) + throws Exception { + SecretKey keySpec = new SecretKeySpec(key, "AES"); + AlgorithmParameterSpec params = + new GCMParameterSpec(8 * TAG_SIZE_IN_BYTES, nonce, 0, nonce.length); + Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); + cipher.init(mode, keySpec, params); + if (aad != null && aad.length != 0) { + cipher.updateAAD(aad); + } + return cipher; + } + + private byte[] gcmEncrypt(final byte[] key, final byte[] plaintext, + final byte[] aad) + throws Exception { + byte[] nonce = randBytes(IV_SIZE_IN_BYTES); + Cipher cipher = getCipher(key, aad, nonce, Cipher.ENCRYPT_MODE); + int outputSize = cipher.getOutputSize(plaintext.length); + int len = IV_SIZE_IN_BYTES + outputSize; + byte[] output = new byte[len]; + System.arraycopy(nonce, 0, output, 0, IV_SIZE_IN_BYTES); + cipher.doFinal(plaintext, 0, plaintext.length, output, + IV_SIZE_IN_BYTES); + return output; + } + + private byte[] gcmDecrypt(final byte[] key, final byte[] ciphertext, + final byte[] aad) + throws Exception { + byte[] nonce = new byte[IV_SIZE_IN_BYTES]; + System.arraycopy(ciphertext, 0, nonce, 0, IV_SIZE_IN_BYTES); + Cipher cipher = getCipher(key, aad, nonce, Cipher.DECRYPT_MODE); + return cipher.doFinal(ciphertext, IV_SIZE_IN_BYTES, + ciphertext.length - IV_SIZE_IN_BYTES); + } + + // x86-64 parallel intrinsic data size + private static final int PARALLEL_LEN = 512; + // max data size for x86-64 intrinsic + private static final int SPLIT_LEN = 1048576; // 1MB + + private void encryptAndDecrypt(byte[] key, byte[] aad, byte[] message, + int messageSize) + throws Exception { + byte[] ciphertext = gcmEncrypt(key, message, aad); + byte[] decrypted = gcmDecrypt(key, ciphertext, aad); + if (ciphertext == null) { + throw new RuntimeException("ciphertext is null"); + } + if (Arrays.compare(decrypted, 0, messageSize, + message, 0, messageSize) != 0) { + throw new RuntimeException( + "Decrypted message is different from the original message"); + } + } + + private void run() throws Exception { + byte[] aad = randBytes(20); + byte[] key = randBytes(16); + // Force JIT. + for (int i = 0; i < 100000; i++) { + byte[] message = randBytes(PARALLEL_LEN); + encryptAndDecrypt(key, aad, message, PARALLEL_LEN); + } + for (int messageSize = SPLIT_LEN - 300; messageSize <= SPLIT_LEN + 300; + messageSize++) { + byte[] message = randBytes(messageSize); + try { + encryptAndDecrypt(key, aad, message, messageSize); + } catch (Exception e) { + throw new RuntimeException("Failed for messageSize " + + Integer.toHexString(messageSize), e); + } + } + } + + public static void main(String[] args) throws Exception { + TestGCMSplitBound test = new TestGCMSplitBound(); + for (int i = 0; i < 3; i++) { + test.run(); + } + } +} From 45c0600d3abfa4bcd0338840523c0df69283afe2 Mon Sep 17 00:00:00 2001 From: Justin Lu Date: Mon, 1 Dec 2025 18:17:00 +0000 Subject: [PATCH 077/706] 8372609: Bug4944439 does not enforce locale correctly Reviewed-by: liach, jpai --- .../text/Format/NumberFormat/Bug4944439.java | 25 +++---------------- 1 file changed, 4 insertions(+), 21 deletions(-) diff --git a/test/jdk/java/text/Format/NumberFormat/Bug4944439.java b/test/jdk/java/text/Format/NumberFormat/Bug4944439.java index 561052e9a95..a13a36733e2 100644 --- a/test/jdk/java/text/Format/NumberFormat/Bug4944439.java +++ b/test/jdk/java/text/Format/NumberFormat/Bug4944439.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, 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 @@ -23,22 +23,19 @@ /* * @test - * @bug 4944439 + * @bug 4944439 8372609 * @summary Confirm that numbers where all digits after the decimal separator are 0 * and which are between Long.MIN_VALUE and Long.MAX_VALUE are returned * as Long(not double). * @run junit Bug4944439 */ -import java.text.DecimalFormat; +import java.text.NumberFormat; import java.util.ArrayList; import java.util.Locale; import java.util.stream.Stream; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; @@ -47,21 +44,7 @@ import static org.junit.jupiter.api.Assertions.assertInstanceOf; public class Bug4944439 { - // Save JVM default locale - private static final Locale savedLocale = Locale.getDefault(); - private static final DecimalFormat df = new DecimalFormat(); - - // Set JVM default locale to US for testing - @BeforeAll - static void initAll() { - Locale.setDefault(Locale.US); - } - - // Restore JVM default locale - @AfterAll - static void tearDownAll() { - Locale.setDefault(savedLocale); - } + private static final NumberFormat df = NumberFormat.getInstance(Locale.US); // Check return type and value returned by DecimalFormat.parse() for longs @ParameterizedTest From 79e99bb0778608733a677821a0bb35041e9fb939 Mon Sep 17 00:00:00 2001 From: Xiaolong Peng Date: Mon, 1 Dec 2025 18:30:38 +0000 Subject: [PATCH 078/706] 8372566: Genshen: crash at ShenandoahScanRemembered::process_clusters after JDK-8371667 Reviewed-by: wkemper, kdnilsen, ysr --- src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp index 22a59b5ac18..5c4d10ca8a5 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp @@ -1015,7 +1015,7 @@ HeapWord* ShenandoahHeap::allocate_memory_under_lock(ShenandoahAllocRequest& req // Record the plab configuration for this result and register the object. if (result != nullptr && req.is_old()) { old_generation()->configure_plab_for_current_thread(req); - if (req.type() == ShenandoahAllocRequest::_alloc_shared_gc) { + if (!req.is_lab_alloc()) { // Register the newly allocated object while we're holding the global lock since there's no synchronization // built in to the implementation of register_object(). There are potential races when multiple independent // threads are allocating objects, some of which might span the same card region. For example, consider From 84ffe87260753973835ea6b88443e28bcaf0122f Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Tue, 2 Dec 2025 08:38:22 +0000 Subject: [PATCH 079/706] 8342175: MemoryEaterMT fails intermittently with ExceptionInInitializerError Reviewed-by: lmesnik, aboldtch --- test/hotspot/jtreg/vmTestbase/nsk/share/gc/GC.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/GC.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/GC.java index 6b33783306f..15bbc9eb964 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/GC.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/GC.java @@ -48,6 +48,9 @@ public class GC extends nsk.share.test.Tests { public GCTestRunner(Test test, String[] args) { super(test, args); + // GC tests often run at the brink of OOME, make sure + // LocalRandom is loaded, initialized, and has enough memory. + LocalRandom.init(); } private GCParams getGCParams(String[] args) { From 7278d2e8e5835f090672f7625d391a1b4c1a6626 Mon Sep 17 00:00:00 2001 From: Per Minborg Date: Tue, 2 Dec 2025 09:39:29 +0000 Subject: [PATCH 080/706] 8372258: Improve TypeVariable support Reviewed-by: liach --- .../java/lang/reflect/TypeVariable.java | 4 +- .../reflectiveObjects/TypeVariableImpl.java | 16 +++-- ...otectInnerStateOfTypeVariableImplTest.java | 70 +++++++++++++++++++ 3 files changed, 84 insertions(+), 6 deletions(-) create mode 100644 test/jdk/java/lang/reflect/Generics/ProtectInnerStateOfTypeVariableImplTest.java diff --git a/src/java.base/share/classes/java/lang/reflect/TypeVariable.java b/src/java.base/share/classes/java/lang/reflect/TypeVariable.java index 01746e34385..85e99fd3f92 100644 --- a/src/java.base/share/classes/java/lang/reflect/TypeVariable.java +++ b/src/java.base/share/classes/java/lang/reflect/TypeVariable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, 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,7 +72,7 @@ public interface TypeVariable extends Type, Annota Type[] getBounds(); /** - * Returns the {@code GenericDeclaration} object representing the + * Returns a {@code GenericDeclaration} object representing the * generic declaration declared for this type variable. * * @return the generic declaration declared for this type variable. diff --git a/src/java.base/share/classes/sun/reflect/generics/reflectiveObjects/TypeVariableImpl.java b/src/java.base/share/classes/sun/reflect/generics/reflectiveObjects/TypeVariableImpl.java index 75750d38f2f..560e9a4f7c9 100644 --- a/src/java.base/share/classes/sun/reflect/generics/reflectiveObjects/TypeVariableImpl.java +++ b/src/java.base/share/classes/sun/reflect/generics/reflectiveObjects/TypeVariableImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, 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,6 +35,8 @@ import java.lang.reflect.TypeVariable; import java.util.LinkedHashMap; import java.util.Map; import java.util.Objects; + +import jdk.internal.reflect.ReflectionFactory; import sun.reflect.annotation.AnnotationSupport; import sun.reflect.annotation.TypeAnnotationParser; import sun.reflect.annotation.AnnotationType; @@ -125,18 +127,24 @@ public class TypeVariableImpl } /** - * Returns the {@code GenericDeclaration} object representing the + * Returns a {@code GenericDeclaration} object representing the * generic declaration that declared this type variable. * - * @return the generic declaration that declared this type variable. + * @return a generic declaration that declared this type variable. * * @since 1.5 */ + @SuppressWarnings("unchecked") public D getGenericDeclaration() { assert genericDeclaration instanceof Class || genericDeclaration instanceof Method || genericDeclaration instanceof Constructor : "Unexpected kind of GenericDeclaration"; - return genericDeclaration; + // If the `genericDeclaration` instance is mutable, we need to make a copy. + return switch (genericDeclaration) { + case Method method -> (D) ReflectionFactory.getReflectionFactory().copyMethod(method); + case Constructor ctor -> (D) ReflectionFactory.getReflectionFactory().copyConstructor(ctor); + default -> genericDeclaration; + }; } diff --git a/test/jdk/java/lang/reflect/Generics/ProtectInnerStateOfTypeVariableImplTest.java b/test/jdk/java/lang/reflect/Generics/ProtectInnerStateOfTypeVariableImplTest.java new file mode 100644 index 00000000000..05a2a8e84de --- /dev/null +++ b/test/jdk/java/lang/reflect/Generics/ProtectInnerStateOfTypeVariableImplTest.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2025, 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 8372258 + * @summary Test if a copy of the internal state is provided + * @run junit ProtectInnerStateOfTypeVariableImplTest + */ + +import org.junit.jupiter.api.Test; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.lang.reflect.TypeVariable; + +import static org.junit.jupiter.api.Assertions.*; + +final class ProtectInnerStateOfTypeVariableImplTest { + + static final class Foo { + public Foo() { + } + + X x() { + return null; + } + } + + @Test + void testMethod() throws NoSuchMethodException { + Method method = Foo.class.getDeclaredMethod("x"); + TypeVariable tv = method.getTypeParameters()[0]; + + Method gd = tv.getGenericDeclaration(); + Method gd2 = tv.getGenericDeclaration(); + assertNotSame(gd, gd2); + } + + @Test + void testConstructor() throws NoSuchMethodException { + Constructor ctor = Foo.class.getConstructor(); + TypeVariable> tv = ctor.getTypeParameters()[0]; + + Constructor gd = tv.getGenericDeclaration(); + Constructor gd2 = tv.getGenericDeclaration(); + assertNotSame(gd, gd2); + } + +} From f636fcadd72eba7aefbf3f89777c14b3e3f19fb8 Mon Sep 17 00:00:00 2001 From: Axel Boldt-Christmas Date: Tue, 2 Dec 2025 10:58:44 +0000 Subject: [PATCH 081/706] 8372645: ParallelGC: Remove race between allocation and expansion before is_init_completed Reviewed-by: ayang, sjohanss, eosterlund --- .../gc/parallel/parallelScavengeHeap.cpp | 23 +++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp index 3a13d0d0535..4d291120e4a 100644 --- a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp +++ b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp @@ -307,9 +307,13 @@ HeapWord* ParallelScavengeHeap::mem_allocate_cas_noexpand(size_t size, bool is_t HeapWord* ParallelScavengeHeap::mem_allocate_work(size_t size, bool is_tlab) { for (uint loop_count = 0; /* empty */; ++loop_count) { - HeapWord* result = mem_allocate_cas_noexpand(size, is_tlab); - if (result != nullptr) { - return result; + HeapWord* result; + { + ConditionalMutexLocker locker(Heap_lock, !is_init_completed()); + result = mem_allocate_cas_noexpand(size, is_tlab); + if (result != nullptr) { + return result; + } } // Read total_collections() under the lock so that multiple @@ -326,10 +330,15 @@ HeapWord* ParallelScavengeHeap::mem_allocate_work(size_t size, bool is_tlab) { } if (!is_init_completed()) { - // Can't do GC; try heap expansion to satisfy the request. - result = expand_heap_and_allocate(size, is_tlab); - if (result != nullptr) { - return result; + // Double checked locking, this ensure that is_init_completed() does not + // transition while expanding the heap. + MonitorLocker ml(InitCompleted_lock, Monitor::_no_safepoint_check_flag); + if (!is_init_completed()) { + // Can't do GC; try heap expansion to satisfy the request. + result = expand_heap_and_allocate(size, is_tlab); + if (result != nullptr) { + return result; + } } } From e27abe8a979880f308c69ea53319565dcd2142b6 Mon Sep 17 00:00:00 2001 From: Axel Boldt-Christmas Date: Tue, 2 Dec 2025 10:59:04 +0000 Subject: [PATCH 082/706] 8372540: SerialGC: Remove race between allocation and expansion before is_init_completed Reviewed-by: ayang, sjohanss, eosterlund --- src/hotspot/share/gc/serial/serialHeap.cpp | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/hotspot/share/gc/serial/serialHeap.cpp b/src/hotspot/share/gc/serial/serialHeap.cpp index 03ad1282f5f..faef3b89125 100644 --- a/src/hotspot/share/gc/serial/serialHeap.cpp +++ b/src/hotspot/share/gc/serial/serialHeap.cpp @@ -304,9 +304,12 @@ HeapWord* SerialHeap::mem_allocate_work(size_t size, bool is_tlab) { HeapWord* result = nullptr; for (uint try_count = 1; /* break */; try_count++) { - result = mem_allocate_cas_noexpand(size, is_tlab); - if (result != nullptr) { - break; + { + ConditionalMutexLocker locker(Heap_lock, !is_init_completed()); + result = mem_allocate_cas_noexpand(size, is_tlab); + if (result != nullptr) { + break; + } } uint gc_count_before; // Read inside the Heap_lock locked region. { @@ -320,10 +323,15 @@ HeapWord* SerialHeap::mem_allocate_work(size_t size, bool is_tlab) { } if (!is_init_completed()) { - // Can't do GC; try heap expansion to satisfy the request. - result = expand_heap_and_allocate(size, is_tlab); - if (result != nullptr) { - return result; + // Double checked locking, this ensure that is_init_completed() does not + // transition while expanding the heap. + MonitorLocker ml(InitCompleted_lock, Monitor::_no_safepoint_check_flag); + if (!is_init_completed()) { + // Can't do GC; try heap expansion to satisfy the request. + result = expand_heap_and_allocate(size, is_tlab); + if (result != nullptr) { + return result; + } } } From 3f046f6dec72392d0693655c0f0ef9189529ce45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20Sikstr=C3=B6m?= Date: Tue, 2 Dec 2025 11:56:22 +0000 Subject: [PATCH 083/706] 8372747: G1: Conservative heap alignment does not account for card table constraint Reviewed-by: mdoerr, stefank, tschatzl, sjohanss --- src/hotspot/share/gc/g1/g1Arguments.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1Arguments.cpp b/src/hotspot/share/gc/g1/g1Arguments.cpp index 5cbafd2ae94..2be0e008c22 100644 --- a/src/hotspot/share/gc/g1/g1Arguments.cpp +++ b/src/hotspot/share/gc/g1/g1Arguments.cpp @@ -77,10 +77,11 @@ void G1Arguments::initialize_alignments() { } size_t G1Arguments::conservative_max_heap_alignment() { - if (FLAG_IS_DEFAULT(G1HeapRegionSize)) { - return G1HeapRegion::max_ergonomics_size(); - } - return G1HeapRegion::max_region_size(); + const size_t region_size = FLAG_IS_DEFAULT(G1HeapRegionSize) + ? G1HeapRegion::max_ergonomics_size() + : G1HeapRegion::max_region_size(); + + return calculate_heap_alignment(region_size); } void G1Arguments::initialize_verification_types() { From fd7283be47489d3297aac6ecf6658ee9500b2891 Mon Sep 17 00:00:00 2001 From: Doug Lea Date: Tue, 2 Dec 2025 12:05:31 +0000 Subject: [PATCH 084/706] 8360046: Scalability issue when submitting virtual threads with almost empty tasks Reviewed-by: vklang --- .../classes/java/lang/VirtualThread.java | 18 +- .../java/util/concurrent/ForkJoinPool.java | 632 +++++++++--------- .../util/concurrent/forkjoin/Starvation.java | 20 +- 3 files changed, 341 insertions(+), 329 deletions(-) diff --git a/src/java.base/share/classes/java/lang/VirtualThread.java b/src/java.base/share/classes/java/lang/VirtualThread.java index 6064b46d50a..51543f835c1 100644 --- a/src/java.base/share/classes/java/lang/VirtualThread.java +++ b/src/java.base/share/classes/java/lang/VirtualThread.java @@ -315,6 +315,18 @@ final class VirtualThread extends BaseVirtualThread { } } + /** + * Submits the given task to the given executor. If the scheduler is a + * ForkJoinPool then the task is first adapted to a ForkJoinTask. + */ + private void submit(Executor executor, Runnable task) { + if (executor instanceof ForkJoinPool pool) { + pool.submit(ForkJoinTask.adapt(task)); + } else { + executor.execute(task); + } + } + /** * Submits the runContinuation task to the scheduler. For the default scheduler, * and calling it on a worker thread, the task will be pushed to the local queue, @@ -335,12 +347,12 @@ final class VirtualThread extends BaseVirtualThread { if (currentThread().isVirtual()) { Continuation.pin(); try { - scheduler.execute(runContinuation); + submit(scheduler, runContinuation); } finally { Continuation.unpin(); } } else { - scheduler.execute(runContinuation); + submit(scheduler, runContinuation); } done = true; } catch (RejectedExecutionException ree) { @@ -1536,4 +1548,4 @@ final class VirtualThread extends BaseVirtualThread { unblocker.setDaemon(true); unblocker.start(); } -} \ No newline at end of file +} diff --git a/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java b/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java index 1f2c8d2ffa6..f289186e0ad 100644 --- a/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java +++ b/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java @@ -560,89 +560,70 @@ public class ForkJoinPool extends AbstractExecutorService * access (which is usually needed anyway). * * Signalling. Signals (in signalWork) cause new or reactivated - * workers to scan for tasks. Method signalWork and its callers - * try to approximate the unattainable goal of having the right - * number of workers activated for the tasks at hand, but must err - * on the side of too many workers vs too few to avoid stalls: + * workers to scan for tasks. SignalWork is invoked in two cases: + * (1) When a task is pushed onto an empty queue, and (2) When a + * worker takes a top-level task from a queue that has additional + * tasks. Together, these suffice in O(log(#threads)) steps to + * fully activate with at least enough workers, and ideally no + * more than required. This ideal is unobtainable: Callers do not + * know whether another worker will finish its current task and + * poll for others without need of a signal (which is otherwise an + * advantage of work-stealing vs other schemes), and also must + * conservatively estimate the triggering conditions of emptiness + * or non-emptiness; all of which usually cause more activations + * than necessary (see below). (Method signalWork is also used as + * failsafe in case of Thread failures in deregisterWorker, to + * activate or create a new worker to replace them). * - * * If computations are purely tree structured, it suffices for - * every worker to activate another when it pushes a task into - * an empty queue, resulting in O(log(#threads)) steps to full - * activation. Emptiness must be conservatively approximated, - * which may result in unnecessary signals. Also, to reduce - * resource usages in some cases, at the expense of slower - * startup in others, activation of an idle thread is preferred - * over creating a new one, here and elsewhere. - * - * * At the other extreme, if "flat" tasks (those that do not in - * turn generate others) come in serially from only a single - * producer, each worker taking a task from a queue should - * propagate a signal if there are more tasks in that - * queue. This is equivalent to, but generally faster than, - * arranging the stealer take multiple tasks, re-pushing one or - * more on its own queue, and signalling (because its queue is - * empty), also resulting in logarithmic full activation - * time. If tasks do not not engage in unbounded loops based on - * the actions of other workers with unknown dependencies loop, - * this form of proagation can be limited to one signal per - * activation (phase change). We distinguish the cases by - * further signalling only if the task is an InterruptibleTask - * (see below), which are the only supported forms of task that - * may do so. - * - * * Because we don't know about usage patterns (or most commonly, - * mixtures), we use both approaches, which present even more - * opportunities to over-signal. (Failure to distinguish these - * cases in terms of submission methods was arguably an early - * design mistake.) Note that in either of these contexts, - * signals may be (and often are) unnecessary because active - * workers continue scanning after running tasks without the - * need to be signalled (which is one reason work stealing is - * often faster than alternatives), so additional workers - * aren't needed. - * - * * For rapidly branching tasks that require full pool resources, - * oversignalling is OK, because signalWork will soon have no - * more workers to create or reactivate. But for others (mainly - * externally submitted tasks), overprovisioning may cause very - * noticeable slowdowns due to contention and resource - * wastage. We reduce impact by deactivating workers when - * queues don't have accessible tasks, but reactivating and - * rescanning if other tasks remain. - * - * * Despite these, signal contention and overhead effects still - * occur during ramp-up and ramp-down of small computations. + * Top-Level scheduling + * ==================== * * Scanning. Method runWorker performs top-level scanning for (and * execution of) tasks by polling a pseudo-random permutation of * the array (by starting at a given index, and using a constant * cyclically exhaustive stride.) It uses the same basic polling * method as WorkQueue.poll(), but restarts with a different - * permutation on each invocation. The pseudorandom generator - * need not have high-quality statistical properties in the long + * permutation on each rescan. The pseudorandom generator need + * not have high-quality statistical properties in the long * term. We use Marsaglia XorShifts, seeded with the Weyl sequence - * from ThreadLocalRandom probes, which are cheap and - * suffice. Each queue's polling attempts to avoid becoming stuck - * when other scanners/pollers stall. Scans do not otherwise - * explicitly take into account core affinities, loads, cache - * localities, etc, However, they do exploit temporal locality - * (which usually approximates these) by preferring to re-poll - * from the same queue after a successful poll before trying - * others, which also reduces bookkeeping, cache traffic, and - * scanning overhead. But it also reduces fairness, which is - * partially counteracted by giving up on detected interference - * (which also reduces contention when too many workers try to - * take small tasks from the same queue). + * from ThreadLocalRandom probes, which are cheap and suffice. * * Deactivation. When no tasks are found by a worker in runWorker, - * it tries to deactivate()), giving up (and rescanning) on "ctl" - * contention. To avoid missed signals during deactivation, the - * method rescans and reactivates if there may have been a missed - * signal during deactivation. To reduce false-alarm reactivations - * while doing so, we scan multiple times (analogously to method - * quiescent()) before trying to reactivate. Because idle workers - * are often not yet blocked (parked), we use a WorkQueue field to - * advertise that a waiter actually needs unparking upon signal. + * it invokes deactivate, that first deactivates (to an IDLE + * phase). Avoiding missed signals during deactivation requires a + * (conservative) rescan, reactivating if there may be tasks to + * poll. Because idle workers are often not yet blocked (parked), + * we use a WorkQueue field to advertise that a waiter actually + * needs unparking upon signal. + * + * When tasks are constructed as (recursive) DAGs, top-level + * scanning is usually infrequent, and doesn't encounter most + * of the following problems addressed by runWorker and awaitWork: + * + * Locality. Polls are organized into "runs", continuing until + * empty or contended, while also minimizing interference by + * postponing bookeeping to ends of runs. This may reduce + * fairness. + * + * Contention. When many workers try to poll few queues, they + * often collide, generating CAS failures and disrupting locality + * of workers already running their tasks. This also leads to + * stalls when tasks cannot be taken because other workers have + * not finished poll operations, which is detected by reading + * ahead in queue arrays. In both cases, workers restart scans in a + * way that approximates randomized backoff. + * + * Oversignalling. When many short top-level tasks are present in + * a small number of queues, the above signalling strategy may + * activate many more workers than needed, worsening locality and + * contention problems, while also generating more global + * contention (field ctl is CASed on every activation and + * deactivation). We filter out (both in runWorker and + * signalWork) attempted signals that are surely not needed + * because the signalled tasks are already taken. + * + * Shutdown and Quiescence + * ======================= * * Quiescence. Workers scan looking for work, giving up when they * don't find any, without being sure that none are available. @@ -892,9 +873,7 @@ public class ForkJoinPool extends AbstractExecutorService * shutdown, runners are interrupted so they can cancel. Since * external joining callers never run these tasks, they must await * cancellation by others, which can occur along several different - * paths. The inability to rely on caller-runs may also require - * extra signalling (resulting in scanning and contention) so is - * done only conditionally in methods push and runworker. + * paths. * * Across these APIs, rules for reporting exceptions for tasks * with results accessed via join() differ from those via get(), @@ -961,9 +940,13 @@ public class ForkJoinPool extends AbstractExecutorService * less-contended applications. To help arrange this, some * non-reference fields are declared as "long" even when ints or * shorts would suffice. For class WorkQueue, an - * embedded @Contended region segregates fields most heavily - * updated by owners from those most commonly read by stealers or - * other management. + * embedded @Contended isolates the very busy top index, along + * with status and bookkeeping fields written (mostly) by owners, + * that otherwise interfere with reading array and base + * fields. There are other variables commonly contributing to + * false-sharing-related performance issues (including fields of + * class Thread), but we can't do much about this except try to + * minimize access. * * Initial sizing and resizing of WorkQueue arrays is an even more * delicate tradeoff because the best strategy systematically @@ -972,13 +955,11 @@ public class ForkJoinPool extends AbstractExecutorService * direct false-sharing and indirect cases due to GC bookkeeping * (cardmarks etc), and reduce the number of resizes, which are * not especially fast because they require atomic transfers. - * Currently, arrays for workers are initialized to be just large - * enough to avoid resizing in most tree-structured tasks, but - * larger for external queues where both false-sharing problems - * and the need for resizing are more common. (Maintenance note: - * any changes in fields, queues, or their uses, or JVM layout - * policies, must be accompanied by re-evaluation of these - * placement and sizing decisions.) + * Currently, arrays are initialized to be just large enough to + * avoid resizing in most tree-structured tasks, but grow rapidly + * until large. (Maintenance note: any changes in fields, queues, + * or their uses, or JVM layout policies, must be accompanied by + * re-evaluation of these placement and sizing decisions.) * * Style notes * =========== @@ -1061,17 +1042,11 @@ public class ForkJoinPool extends AbstractExecutorService static final int DEFAULT_COMMON_MAX_SPARES = 256; /** - * Initial capacity of work-stealing queue array for workers. + * Initial capacity of work-stealing queue array. * Must be a power of two, at least 2. See above. */ static final int INITIAL_QUEUE_CAPACITY = 1 << 6; - /** - * Initial capacity of work-stealing queue array for external queues. - * Must be a power of two, at least 2. See above. - */ - static final int INITIAL_EXTERNAL_QUEUE_CAPACITY = 1 << 9; - // conversions among short, int, long static final int SMASK = 0xffff; // (unsigned) short bits static final long LMASK = 0xffffffffL; // lower 32 bits of long @@ -1211,11 +1186,11 @@ public class ForkJoinPool extends AbstractExecutorService @jdk.internal.vm.annotation.Contended("w") int stackPred; // pool stack (ctl) predecessor link @jdk.internal.vm.annotation.Contended("w") + volatile int parking; // nonzero if parked in awaitWork + @jdk.internal.vm.annotation.Contended("w") volatile int source; // source queue id (or DROPPED) @jdk.internal.vm.annotation.Contended("w") int nsteals; // number of steals from other queues - @jdk.internal.vm.annotation.Contended("w") - volatile int parking; // nonzero if parked in awaitWork // Support for atomic operations private static final Unsafe U; @@ -1248,11 +1223,11 @@ public class ForkJoinPool extends AbstractExecutorService */ WorkQueue(ForkJoinWorkerThread owner, int id, int cfg, boolean clearThreadLocals) { - array = new ForkJoinTask[owner == null ? - INITIAL_EXTERNAL_QUEUE_CAPACITY : - INITIAL_QUEUE_CAPACITY]; - this.owner = owner; this.config = (clearThreadLocals) ? cfg | CLEAR_TLS : cfg; + if ((this.owner = owner) == null) { + array = new ForkJoinTask[INITIAL_QUEUE_CAPACITY]; + phase = id | IDLE; + } } /** @@ -1279,27 +1254,27 @@ public class ForkJoinPool extends AbstractExecutorService * @throws RejectedExecutionException if array could not be resized */ final void push(ForkJoinTask task, ForkJoinPool pool, boolean internal) { - int s = top, b = base, m, cap, room; ForkJoinTask[] a; - if ((a = array) != null && (cap = a.length) > 0 && // else disabled - task != null) { - int pk = task.noUserHelp() + 1; // prev slot offset - if ((room = (m = cap - 1) - (s - b)) >= 0) { + int s = top, b = base, m, cap, room; ForkJoinTask[] a, na; + if ((a = array) != null && (cap = a.length) > 0) { // else disabled + int k = (m = cap - 1) & s; + if ((room = m - (s - b)) >= 0) { top = s + 1; - long pos = slotOffset(m & s); + long pos = slotOffset(k); if (!internal) U.putReference(a, pos, task); // inside lock else U.getAndSetReference(a, pos, task); // fully fenced - if (room == 0) // resize - growArray(a, cap, s); + if (room == 0 && (na = growArray(a, cap, s)) != null) + k = ((a = na).length - 1) & s; // resize } if (!internal) unlockPhase(); if (room < 0) throw new RejectedExecutionException("Queue capacity exceeded"); - if ((room == 0 || a[m & (s - pk)] == null) && - pool != null) - pool.signalWork(); // may have appeared empty + if (pool != null && + (room == 0 || + U.getReferenceAcquire(a, slotOffset(m & (s - 1))) == null)) + pool.signalWork(a, k); // may have appeared empty } } @@ -1308,11 +1283,12 @@ public class ForkJoinPool extends AbstractExecutorService * @param a old array * @param cap old array capacity * @param s current top + * @return new array, or null on failure */ - private void growArray(ForkJoinTask[] a, int cap, int s) { - int newCap = cap << 1; + private ForkJoinTask[] growArray(ForkJoinTask[] a, int cap, int s) { + int newCap = (cap >= 1 << 16) ? cap << 1 : cap << 2; + ForkJoinTask[] newArray = null; if (a != null && a.length == cap && cap > 0 && newCap > 0) { - ForkJoinTask[] newArray = null; try { newArray = new ForkJoinTask[newCap]; } catch (OutOfMemoryError ex) { @@ -1329,34 +1305,45 @@ public class ForkJoinPool extends AbstractExecutorService updateArray(newArray); // fully fenced } } + return newArray; } /** - * Takes next task, if one exists, in order specified by mode, - * so acts as either local-pop or local-poll. Called only by owner. - * @param fifo nonzero if FIFO mode + * Takes next task, if one exists, in lifo order. */ - private ForkJoinTask nextLocalTask(int fifo) { + private ForkJoinTask localPop() { ForkJoinTask t = null; - ForkJoinTask[] a = array; - int b = base, p = top, cap; - if (p - b > 0 && a != null && (cap = a.length) > 0) { - for (int m = cap - 1, s, nb;;) { - if (fifo == 0 || (nb = b + 1) == p) { - if ((t = (ForkJoinTask)U.getAndSetReference( - a, slotOffset(m & (s = p - 1)), null)) != null) - updateTop(s); // else lost race for only task - break; + int s = top - 1, cap; long k; ForkJoinTask[] a; + if ((a = array) != null && (cap = a.length) > 0 && + U.getReference(a, k = slotOffset((cap - 1) & s)) != null && + (t = (ForkJoinTask)U.getAndSetReference(a, k, null)) != null) + updateTop(s); + return t; + } + + /** + * Takes next task, if one exists, in fifo order. + */ + private ForkJoinTask localPoll() { + ForkJoinTask t = null; + int p = top, cap; ForkJoinTask[] a; + if ((a = array) != null && (cap = a.length) > 0) { + for (int b = base; p - b > 0; ) { + int nb = b + 1; + long k = slotOffset((cap - 1) & b); + if (U.getReference(a, k) == null) { + if (nb == p) + break; // else base is lagging + while (b == (b = U.getIntAcquire(this, BASE))) + Thread.onSpinWait(); // spin to reduce memory traffic } - if ((t = (ForkJoinTask)U.getAndSetReference( - a, slotOffset(m & b), null)) != null) { + else if ((t = (ForkJoinTask) + U.getAndSetReference(a, k, null)) != null) { updateBase(nb); break; } - while (b == (b = U.getIntAcquire(this, BASE))) - Thread.onSpinWait(); // spin to reduce memory traffic - if (p - b <= 0) - break; + else + b = base; } } return t; @@ -1364,10 +1351,9 @@ public class ForkJoinPool extends AbstractExecutorService /** * Takes next task, if one exists, using configured mode. - * (Always internal, never called for Common pool.) */ final ForkJoinTask nextLocalTask() { - return nextLocalTask(config & FIFO); + return (config & FIFO) == 0 ? localPop() : localPoll(); } /** @@ -1443,12 +1429,12 @@ public class ForkJoinPool extends AbstractExecutorService // specialized execution methods /** - * Runs the given task, as well as remaining local tasks. + * Runs the given task, as well as remaining local tasks */ final void topLevelExec(ForkJoinTask task, int fifo) { while (task != null) { task.doExec(); - task = nextLocalTask(fifo); + task = (fifo != 0) ? localPoll() : localPop(); } } @@ -1578,7 +1564,7 @@ public class ForkJoinPool extends AbstractExecutorService * Cancels all local tasks. Called only by owner. */ final void cancelTasks() { - for (ForkJoinTask t; (t = nextLocalTask(0)) != null; ) { + for (ForkJoinTask t; (t = localPop()) != null; ) { try { t.cancel(false); } catch (Throwable ignore) { @@ -1780,7 +1766,8 @@ public class ForkJoinPool extends AbstractExecutorService * @param w caller's WorkQueue */ final void registerWorker(WorkQueue w) { - if (w != null && (runState & STOP) == 0L) { + if (w != null) { + w.array = new ForkJoinTask[INITIAL_QUEUE_CAPACITY]; ThreadLocalRandom.localInit(); int seed = w.stackPred = ThreadLocalRandom.getProbe(); int phaseSeq = seed & ~((IDLE << 1) - 1); // initial phase tag @@ -1858,17 +1845,18 @@ public class ForkJoinPool extends AbstractExecutorService } if ((tryTerminate(false, false) & STOP) == 0L && phase != 0 && w != null && w.source != DROPPED) { - signalWork(); // possibly replace w.cancelTasks(); // clean queue + signalWork(null, 0); // possibly replace } if (ex != null) ForkJoinTask.rethrow(ex); } /** - * Releases an idle worker, or creates one if not enough exist. + * Releases an idle worker, or creates one if not enough exist, + * giving up if array a is nonnull and task at a[k] already taken. */ - final void signalWork() { + final void signalWork(ForkJoinTask[] a, int k) { int pc = parallelism; for (long c = ctl;;) { WorkQueue[] qs = queues; @@ -1884,13 +1872,15 @@ public class ForkJoinPool extends AbstractExecutorService if (sp == 0) { if ((short)(c >>> TC_SHIFT) >= pc) break; - nc = ((c + TC_UNIT) & TC_MASK); + nc = ((c + TC_UNIT) & TC_MASK) | ac; } else if ((v = w) == null) break; else - nc = (v.stackPred & LMASK) | (c & TC_MASK); - if (c == (c = compareAndExchangeCtl(c, nc | ac))) { + nc = (v.stackPred & LMASK) | (c & TC_MASK) | ac; + if (a != null && k < a.length && k >= 0 && a[k] == null) + break; + if (c == (c = ctl) && c == (c = compareAndExchangeCtl(c, nc))) { if (v == null) createWorker(); else { @@ -1973,178 +1963,196 @@ public class ForkJoinPool extends AbstractExecutorService * @param w caller's WorkQueue (may be null on failed initialization) */ final void runWorker(WorkQueue w) { - if (w != null) { - int phase = w.phase, r = w.stackPred; // seed from registerWorker - int fifo = w.config & FIFO, nsteals = 0, src = -1; - for (;;) { - WorkQueue[] qs; + if (w != null && w.phase != 0) { // else unregistered + WorkQueue[] qs; + int r = w.stackPred; // seed from registerWorker + int fifo = (int)config & FIFO, rescans = 0, inactive = 0, taken = 0, n; + while ((runState & STOP) == 0L && (qs = queues) != null && + (n = qs.length) > 0) { + int i = r, step = (r >>> 16) | 1; r ^= r << 13; r ^= r >>> 17; r ^= r << 5; // xorshift - if ((runState & STOP) != 0L || (qs = queues) == null) - break; - int n = qs.length, i = r, step = (r >>> 16) | 1; - boolean rescan = false; - scan: for (int l = n; l > 0; --l, i += step) { // scan queues - int j, cap; WorkQueue q; ForkJoinTask[] a; - if ((q = qs[j = i & (n - 1)]) != null && - (a = q.array) != null && (cap = a.length) > 0) { - for (int m = cap - 1, pb = -1, b = q.base;;) { - ForkJoinTask t; long k; + scan: for (int j = n; j != 0; --j, i += step) { + WorkQueue q; int qid; + if ((q = qs[qid = i & (n - 1)]) != null) { + ForkJoinTask[] a; int cap; // poll queue + while ((a = q.array) != null && (cap = a.length) > 0) { + int b, nb, nk; long bp; ForkJoinTask t; t = (ForkJoinTask)U.getReferenceAcquire( - a, k = slotOffset(m & b)); - if (b != (b = q.base) || t == null || - !U.compareAndSetReference(a, k, t, null)) { - if (a[b & m] == null) { - if (rescan) // end of run - break scan; - if (a[(b + 1) & m] == null && - a[(b + 2) & m] == null) { - break; // probably empty + a, bp = slotOffset((cap - 1) & (b = q.base))); + long np = slotOffset(nk = (nb = b + 1) & (cap - 1)); + if (q.base == b) { // else inconsistent + if (t == null) { + if (q.array == a) { // else resized + if (rescans > 0) // ran or stalled + break scan; + if (U.getReference(a, np) == null && + (rescans >= 0 || + (U.getReferenceAcquire(a, bp) == null && + q.top == q.base))) + break; + rescans = 1; // may be stalled } - if (pb == (pb = b)) { // track progress - rescan = true; // stalled; reorder scan + } + else if (inactive != 0) { + if ((inactive = tryReactivate(w)) != 0) { + rescans = 1; // can't take yet break scan; } } - } - else { - boolean propagate; - int nb = q.base = b + 1, prevSrc = src; - w.nsteals = ++nsteals; - w.source = src = j; // volatile - rescan = true; - int nh = t.noUserHelp(); - if (propagate = - (prevSrc != src || nh != 0) && a[nb & m] != null) - signalWork(); - w.topLevelExec(t, fifo); - if ((b = q.base) != nb && !propagate) - break scan; // reduce interference + else if (U.compareAndSetReference(a, bp, t, null)) { + q.base = nb; + Object nt = U.getReferenceAcquire(a, np); + w.source = qid; + rescans = 1; + ++taken; + if (nt != null && // confirm a[nk] + U.getReferenceAcquire(a, np) == nt) + signalWork(a, nk); // propagate + w.topLevelExec(t, fifo); + } } } } } - if (!rescan) { - if (((phase = deactivate(w, phase)) & IDLE) != 0) - break; - src = -1; // re-enable propagation + if (rescans >= 0) + --rescans; + else if (inactive == 0) { + if ((inactive = deactivate(w, taken)) != 0) + taken = 0; } + else if (awaitWork(w) == 0) + inactive = rescans = 0; + else + break; } } } /** - * Deactivates and if necessary awaits signal or termination. + * Tries to deactivate worker, keeping active on contention * - * @param w the worker - * @param phase current phase - * @return current phase, with IDLE set if worker should exit + * @param w the work queue + * @param taken number of stolen tasks since last deactivation + * @return nonzero if inactive */ - private int deactivate(WorkQueue w, int phase) { - if (w == null) // currently impossible - return IDLE; - int p = phase | IDLE, activePhase = phase + (IDLE << 1); - long pc = ctl, qc = (activePhase & LMASK) | ((pc - RC_UNIT) & UMASK); - int sp = w.stackPred = (int)pc; // set ctl stack link - w.phase = p; - if (!compareAndSetCtl(pc, qc)) // try to enqueue - return w.phase = phase; // back out on possible signal - int ac = (short)(qc >>> RC_SHIFT), n; long e; WorkQueue[] qs; - if (((e = runState) & STOP) != 0L || - ((e & SHUTDOWN) != 0L && ac == 0 && quiescent() > 0) || - (qs = queues) == null || (n = qs.length) <= 0) - return IDLE; // terminating - - for (int prechecks = Math.min(ac, 2), // reactivation threshold - k = Math.max(n + (n << 1), SPIN_WAITS << 1);;) { - WorkQueue q; int cap; ForkJoinTask[] a; long c; - if (w.phase == activePhase) - return activePhase; - if (--k < 0) - return awaitWork(w, p); // block, drop, or exit - if ((q = qs[k & (n - 1)]) == null) - Thread.onSpinWait(); - else if ((a = q.array) != null && (cap = a.length) > 0 && - a[q.base & (cap - 1)] != null && --prechecks < 0 && - (int)(c = ctl) == activePhase && - compareAndSetCtl(c, (sp & LMASK) | ((c + RC_UNIT) & UMASK))) - return w.phase = activePhase; // reactivate + private int deactivate(WorkQueue w, int taken) { + int inactive = 0, phase; + if (w != null && (inactive = (phase = w.phase) & IDLE) == 0) { + long sp = (phase + (IDLE << 1)) & LMASK, pc, c; + w.phase = phase | IDLE; + w.stackPred = (int)(pc = ctl); // set ctl stack link + if (!compareAndSetCtl( // try to enqueue + pc, c = ((pc - RC_UNIT) & UMASK) | sp)) + w.phase = phase; // back out on contention + else { + if (taken != 0) { + w.nsteals += taken; + if ((w.config & CLEAR_TLS) != 0 && + (Thread.currentThread() instanceof ForkJoinWorkerThread f)) + f.resetThreadLocals(); // (instanceof check always true) + } + if (((c & RC_MASK) == 0L && quiescent() > 0) || taken == 0) + inactive = w.phase & IDLE; // check quiescent termination + else { // spin for approx 1 scan cost + int tc = (short)(c >>> TC_SHIFT); + int spins = Math.max((tc << 1) + tc, SPIN_WAITS); + while ((inactive = w.phase & IDLE) != 0 && --spins != 0) + Thread.onSpinWait(); + } + } } + return inactive; + } + + /** + * Reactivates worker w if it is currently top of ctl stack + * + * @param w the work queue + * @return 0 if now active + */ + private int tryReactivate(WorkQueue w) { + int inactive = 0; + if (w != null) { // always true; hoist checks + int sp = w.stackPred, phase, activePhase; long c; + if ((inactive = (phase = w.phase) & IDLE) != 0 && + (int)(c = ctl) == (activePhase = phase + IDLE) && + compareAndSetCtl(c, (sp & LMASK) | ((c + RC_UNIT) & UMASK))) { + w.phase = activePhase; + inactive = 0; + } + } + return inactive; } /** * Awaits signal or termination. * * @param w the work queue - * @param p current phase (known to be idle) - * @return current phase, with IDLE set if worker should exit + * @return 0 if now active */ - private int awaitWork(WorkQueue w, int p) { - if (w != null) { - ForkJoinWorkerThread t; long deadline; - if ((w.config & CLEAR_TLS) != 0 && (t = w.owner) != null) - t.resetThreadLocals(); // clear before reactivate - if ((ctl & RC_MASK) > 0L) - deadline = 0L; - else if ((deadline = - (((w.source != INVALID_ID) ? keepAlive : TIMEOUT_SLOP)) + - System.currentTimeMillis()) == 0L) - deadline = 1L; // avoid zero - int activePhase = p + IDLE; - if ((p = w.phase) != activePhase && (runState & STOP) == 0L) { + private int awaitWork(WorkQueue w) { + int inactive = 0, phase; + if (w != null) { // always true; hoist checks + long waitTime = (w.source == INVALID_ID) ? 0L : keepAlive; + if ((inactive = (phase = w.phase) & IDLE) != 0) { LockSupport.setCurrentBlocker(this); - w.parking = 1; // enable unpark - while ((p = w.phase) != activePhase) { - boolean trimmable = false; int trim; - Thread.interrupted(); // clear status + int activePhase = phase + IDLE; + for (long deadline = 0L;;) { + Thread.interrupted(); // clear status if ((runState & STOP) != 0L) break; - if (deadline != 0L) { - if ((trim = tryTrim(w, p, deadline)) > 0) - break; - else if (trim < 0) - deadline = 0L; - else - trimmable = true; + boolean trimmable = false; // use timed wait if trimmable + long d = 0L, c; + if (((c = ctl) & RC_MASK) == 0L && (int)c == activePhase) { + long now = System.currentTimeMillis(); + if (deadline == 0L) + deadline = waitTime + now; + if (deadline - now <= TIMEOUT_SLOP) { + if (tryTrim(w, c, activePhase)) + break; + continue; // lost race to trim + } + d = deadline; + trimmable = true; } - U.park(trimmable, deadline); + w.parking = 1; // enable unpark and recheck + if ((inactive = w.phase & IDLE) != 0) + U.park(trimmable, d); + w.parking = 0; // close unpark window + if (inactive == 0 || (inactive = w.phase & IDLE) == 0) + break; } - w.parking = 0; LockSupport.setCurrentBlocker(null); } } - return p; + return inactive; } /** * Tries to remove and deregister worker after timeout, and release - * another to do the same. - * @return > 0: trimmed, < 0 : not trimmable, else 0 + * another to do the same unless new tasks are found. */ - private int tryTrim(WorkQueue w, int phase, long deadline) { - long c, nc; int stat, activePhase, vp, i; WorkQueue[] vs; WorkQueue v; - if ((activePhase = phase + IDLE) != (int)(c = ctl) || w == null) - stat = -1; // no longer ctl top - else if (deadline - System.currentTimeMillis() >= TIMEOUT_SLOP) - stat = 0; // spurious wakeup - else if (!compareAndSetCtl( - c, nc = ((w.stackPred & LMASK) | (RC_MASK & c) | - (TC_MASK & (c - TC_UNIT))))) - stat = -1; // lost race to signaller - else { - stat = 1; - w.source = DROPPED; - w.phase = activePhase; - if ((vp = (int)nc) != 0 && (vs = queues) != null && - vs.length > (i = vp & SMASK) && (v = vs[i]) != null && - compareAndSetCtl( // try to wake up next waiter - nc, ((UMASK & (nc + RC_UNIT)) | - (nc & TC_MASK) | (v.stackPred & LMASK)))) { - v.source = INVALID_ID; // enable cascaded timeouts - v.phase = vp; - U.unpark(v.owner); + private boolean tryTrim(WorkQueue w, long c, int activePhase) { + if (w != null) { + int vp, i; WorkQueue[] vs; WorkQueue v; + long nc = ((w.stackPred & LMASK) | + ((RC_MASK & c) | (TC_MASK & (c - TC_UNIT)))); + if (compareAndSetCtl(c, nc)) { + w.source = DROPPED; + w.phase = activePhase; + if ((vp = (int)nc) != 0 && (vs = queues) != null && + vs.length > (i = vp & SMASK) && (v = vs[i]) != null && + compareAndSetCtl( // try to wake up next waiter + nc, ((v.stackPred & LMASK) | + ((UMASK & (nc + RC_UNIT)) | (nc & TC_MASK))))) { + v.source = INVALID_ID; // enable cascaded timeouts + v.phase = vp; + U.unpark(v.owner); + } + return true; } } - return stat; + return false; } /** @@ -2561,52 +2569,35 @@ public class ForkJoinPool extends AbstractExecutorService /** * Finds and locks a WorkQueue for an external submitter, or - * throws RejectedExecutionException if shutdown or terminating. - * @param r current ThreadLocalRandom.getProbe() value + * throws RejectedExecutionException if shutdown * @param rejectOnShutdown true if RejectedExecutionException - * should be thrown when shutdown (else only if terminating) + * should be thrown when shutdown */ - private WorkQueue submissionQueue(int r, boolean rejectOnShutdown) { - int reuse; // nonzero if prefer create - if ((reuse = r) == 0) { - ThreadLocalRandom.localInit(); // initialize caller's probe + final WorkQueue externalSubmissionQueue(boolean rejectOnShutdown) { + int r; + if ((r = ThreadLocalRandom.getProbe()) == 0) { + ThreadLocalRandom.localInit(); // initialize caller's probe r = ThreadLocalRandom.getProbe(); } - for (int probes = 0; ; ++probes) { - int n, i, id; WorkQueue[] qs; WorkQueue q; - if ((qs = queues) == null) - break; - if ((n = qs.length) <= 0) + for (;;) { + WorkQueue q; WorkQueue[] qs; int n, id, i; + if ((qs = queues) == null || (n = qs.length) <= 0) break; if ((q = qs[i = (id = r & EXTERNAL_ID_MASK) & (n - 1)]) == null) { - WorkQueue w = new WorkQueue(null, id, 0, false); - w.phase = id; - boolean reject = ((lockRunState() & SHUTDOWN) != 0 && - rejectOnShutdown); - if (!reject && queues == qs && qs[i] == null) - q = qs[i] = w; // else lost race to install + WorkQueue newq = new WorkQueue(null, id, 0, false); + lockRunState(); + if (qs[i] == null && queues == qs) + q = qs[i] = newq; // else lost race to install unlockRunState(); - if (q != null) - return q; - if (reject) + } + if (q != null && q.tryLockPhase()) { + if (rejectOnShutdown && (runState & SHUTDOWN) != 0L) { + q.unlockPhase(); // check while q lock held break; - reuse = 0; - } - if (reuse == 0 || !q.tryLockPhase()) { // move index - if (reuse == 0) { - if (probes >= n >> 1) - reuse = r; // stop prefering free slot } - else if (q != null) - reuse = 0; // probe on collision - r = ThreadLocalRandom.advanceProbe(r); - } - else if (rejectOnShutdown && (runState & SHUTDOWN) != 0L) { - q.unlockPhase(); // check while q lock held - break; - } - else return q; + } + r = ThreadLocalRandom.advanceProbe(r); // move } throw new RejectedExecutionException(); } @@ -2620,24 +2611,12 @@ public class ForkJoinPool extends AbstractExecutorService } else { // find and lock queue internal = false; - q = submissionQueue(ThreadLocalRandom.getProbe(), true); + q = externalSubmissionQueue(true); } q.push(task, signalIfEmpty ? this : null, internal); return task; } - /** - * Returns queue for an external submission, bypassing call to - * submissionQueue if already established and unlocked. - */ - final WorkQueue externalSubmissionQueue(boolean rejectOnShutdown) { - WorkQueue[] qs; WorkQueue q; int n; - int r = ThreadLocalRandom.getProbe(); - return (((qs = queues) != null && (n = qs.length) > 0 && - (q = qs[r & EXTERNAL_ID_MASK & (n - 1)]) != null && r != 0 && - q.tryLockPhase()) ? q : submissionQueue(r, rejectOnShutdown)); - } - /** * Returns queue for an external thread, if one exists that has * possibly ever submitted to the given pool (nonzero probe), or @@ -3310,11 +3289,14 @@ public class ForkJoinPool extends AbstractExecutorService * @since 19 */ public int setParallelism(int size) { + int prevSize; if (size < 1 || size > MAX_CAP) throw new IllegalArgumentException(); if ((config & PRESET_SIZE) != 0) throw new UnsupportedOperationException("Cannot override System property"); - return getAndSetParallelism(size); + if ((prevSize = getAndSetParallelism(size)) < size) + signalWork(null, 0); // trigger worker activation + return prevSize; } /** diff --git a/test/jdk/java/util/concurrent/forkjoin/Starvation.java b/test/jdk/java/util/concurrent/forkjoin/Starvation.java index 8397e852ffa..d864fa0ba33 100644 --- a/test/jdk/java/util/concurrent/forkjoin/Starvation.java +++ b/test/jdk/java/util/concurrent/forkjoin/Starvation.java @@ -28,6 +28,7 @@ */ import java.util.concurrent.Callable; import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.ForkJoinTask; import java.util.concurrent.atomic.AtomicInteger; public class Starvation { @@ -42,7 +43,7 @@ public class Starvation { while (count.get() == c) Thread.onSpinWait(); return null; }}; - public static void main(String[] args) throws Exception { + static void testSubmitExternalCallable() throws Exception { try (var pool = new ForkJoinPool(2)) { for (int i = 0; i < 100_000; i++) { var future1 = pool.submit(new AwaitCount(i)); @@ -53,4 +54,21 @@ public class Starvation { } } } + + static void testSubmitAdaptedCallable() throws Exception { + try (var pool = new ForkJoinPool(2)) { + for (int i = 0; i < 100_000; i++) { + var future1 = pool.submit(new AwaitCount(i)); + var future2 = pool.submit(ForkJoinTask.adapt(noop)); + future2.get(); + count.set(i + 1); + future1.get(); + } + } + } + + public static void main(String[] args) throws Exception { + testSubmitExternalCallable(); + testSubmitAdaptedCallable(); + } } From 13e062e7a36cf9880416a4e867de13778c6bed2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Jeli=C5=84ski?= Date: Tue, 2 Dec 2025 12:13:03 +0000 Subject: [PATCH 085/706] 8366578: Remove the field tagSize in various QuicPacketEncoder.OutgoingQuicPacket subclasses Reviewed-by: jpai, dfuchs --- .../internal/net/http/quic/packets/QuicPacketEncoder.java | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/quic/packets/QuicPacketEncoder.java b/src/java.net.http/share/classes/jdk/internal/net/http/quic/packets/QuicPacketEncoder.java index 890c1a63a35..db519dc7557 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/quic/packets/QuicPacketEncoder.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/quic/packets/QuicPacketEncoder.java @@ -577,7 +577,6 @@ public class QuicPacketEncoder { final byte[] encodedPacketNumber; final List frames; final int payloadSize; - private int tagSize; OutgoingHandshakePacket(QuicConnectionId sourceId, QuicConnectionId destinationId, @@ -590,7 +589,6 @@ public class QuicPacketEncoder { this.encodedPacketNumber = encodedPacketNumber; this.frames = List.copyOf(frames); this.payloadSize = frames.stream().mapToInt(QuicFrame::size).reduce(0, Math::addExact); - this.tagSize = tagSize; this.length = computeLength(payloadSize, encodedPacketNumber.length, tagSize); this.size = computeSize(length); } @@ -676,7 +674,6 @@ public class QuicPacketEncoder { final int size; final byte[] encodedPacketNumber; final List frames; - private int tagSize; final int payloadSize; OutgoingZeroRttPacket(QuicConnectionId sourceId, @@ -689,7 +686,6 @@ public class QuicPacketEncoder { this.packetNumber = packetNumber; this.encodedPacketNumber = encodedPacketNumber; this.frames = List.copyOf(frames); - this.tagSize = tagSize; this.payloadSize = this.frames.stream().mapToInt(QuicFrame::size) .reduce(0, Math::addExact); this.length = computeLength(payloadSize, encodedPacketNumber.length, tagSize); @@ -778,7 +774,6 @@ public class QuicPacketEncoder { final int size; final byte[] encodedPacketNumber; final List frames; - private int tagSize; final int payloadSize; OutgoingOneRttPacket(QuicConnectionId destinationId, @@ -789,7 +784,6 @@ public class QuicPacketEncoder { this.packetNumber = packetNumber; this.encodedPacketNumber = encodedPacketNumber; this.frames = List.copyOf(frames); - this.tagSize = tagSize; this.payloadSize = this.frames.stream().mapToInt(QuicFrame::size) .reduce(0, Math::addExact); this.size = computeSize(payloadSize, encodedPacketNumber.length, tagSize); @@ -853,7 +847,6 @@ public class QuicPacketEncoder { final int size; final byte[] encodedPacketNumber; final List frames; - private int tagSize; final int payloadSize; private record InitialPacketVariableComponents(int length, byte[] token, QuicConnectionId sourceId, @@ -873,7 +866,6 @@ public class QuicPacketEncoder { this.packetNumber = packetNumber; this.encodedPacketNumber = encodedPacketNumber; this.frames = List.copyOf(frames); - this.tagSize = tagSize; this.payloadSize = this.frames.stream() .mapToInt(QuicFrame::size) .reduce(0, Math::addExact); From 5cba2c8461005f2f7bcafdce622126a113f4bbd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Jeli=C5=84ski?= Date: Tue, 2 Dec 2025 12:13:21 +0000 Subject: [PATCH 086/706] 8368093: Remove Stream::createPseudoHeaders Reviewed-by: dfuchs, jpai, vyazici --- .../classes/jdk/internal/net/http/Stream.java | 31 ------------------- 1 file changed, 31 deletions(-) diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/Stream.java b/src/java.net.http/share/classes/jdk/internal/net/http/Stream.java index 4b59a777de2..9a7ccd8f3a1 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/Stream.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/Stream.java @@ -31,7 +31,6 @@ import java.io.UncheckedIOException; import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.net.ProtocolException; -import java.net.URI; import java.net.http.HttpResponse.BodyHandler; import java.net.http.HttpResponse.ResponseInfo; import java.nio.ByteBuffer; @@ -973,36 +972,6 @@ class Stream extends ExchangeImpl { return headers; } - private static HttpHeaders createPseudoHeaders(HttpRequest request) { - HttpHeadersBuilder hdrs = new HttpHeadersBuilder(); - String method = request.method(); - hdrs.setHeader(":method", method); - URI uri = request.uri(); - hdrs.setHeader(":scheme", uri.getScheme()); - String host = uri.getHost(); - int port = uri.getPort(); - assert host != null; - if (port != -1) { - hdrs.setHeader(":authority", host + ":" + port); - } else { - hdrs.setHeader(":authority", host); - } - String query = uri.getRawQuery(); - String path = uri.getRawPath(); - if (path == null || path.isEmpty()) { - if (method.equalsIgnoreCase("OPTIONS")) { - path = "*"; - } else { - path = "/"; - } - } - if (query != null) { - path += "?" + query; - } - hdrs.setHeader(":path", Utils.encode(path)); - return hdrs.build(); - } - HttpHeaders getRequestPseudoHeaders() { return requestPseudoHeaders; } From 07856fce34ba14a83fc1ac0faffe3b5ba883e0b5 Mon Sep 17 00:00:00 2001 From: Jaikiran Pai Date: Tue, 2 Dec 2025 12:17:40 +0000 Subject: [PATCH 087/706] 8372787: ModuleReader should throw IOException consistently when using --patch-module and ModuleReader is closed Reviewed-by: alanb --- .../jdk/internal/module/ModulePatcher.java | 20 ++- .../patched/PatchedModuleReaderTest.java | 132 ++++++++++++++++++ .../java.base/java/lang/PatchedFoo.java | 26 ++++ 3 files changed, 177 insertions(+), 1 deletion(-) create mode 100644 test/jdk/java/lang/module/ModuleReader/patched/PatchedModuleReaderTest.java create mode 100644 test/jdk/java/lang/module/ModuleReader/patched/java.base/java/lang/PatchedFoo.java diff --git a/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java b/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java index d24cc77600c..eb3f25ceca7 100644 --- a/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java +++ b/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java @@ -225,6 +225,7 @@ public final class ModulePatcher { private final ModuleReference mref; private final URL delegateCodeSourceURL; private volatile ModuleReader delegate; + private volatile boolean closed; /** * Creates the ModuleReader to reads resources in a patched module. @@ -291,6 +292,15 @@ public final class ModulePatcher { return r; } + /** + * Throws an IOException if the ModuleReader is closed. + */ + private void ensureOpen() throws IOException { + if (closed) { + throw new IOException("ModuleReader is closed"); + } + } + /** * Finds a resources in the patch locations. Returns null if not found * or the name is "module-info.class" as that cannot be overridden. @@ -310,7 +320,7 @@ public final class ModulePatcher { * Finds a resource of the given name in the patched module. */ public Resource findResource(String name) throws IOException { - + assert !closed : "module reader is closed"; // patch locations Resource r = findResourceInPatch(name); if (r != null) @@ -354,6 +364,7 @@ public final class ModulePatcher { @Override public Optional find(String name) throws IOException { + ensureOpen(); Resource r = findResourceInPatch(name); if (r != null) { URI uri = URI.create(r.getURL().toString()); @@ -365,6 +376,7 @@ public final class ModulePatcher { @Override public Optional open(String name) throws IOException { + ensureOpen(); Resource r = findResourceInPatch(name); if (r != null) { return Optional.of(r.getInputStream()); @@ -375,6 +387,7 @@ public final class ModulePatcher { @Override public Optional read(String name) throws IOException { + ensureOpen(); Resource r = findResourceInPatch(name); if (r != null) { ByteBuffer bb = r.getByteBuffer(); @@ -398,6 +411,7 @@ public final class ModulePatcher { @Override public Stream list() throws IOException { + ensureOpen(); Stream s = delegate().list(); for (ResourceFinder finder : finders) { s = Stream.concat(s, finder.list()); @@ -407,6 +421,10 @@ public final class ModulePatcher { @Override public void close() throws IOException { + if (closed) { + return; + } + closed = true; closeAll(finders); delegate().close(); } diff --git a/test/jdk/java/lang/module/ModuleReader/patched/PatchedModuleReaderTest.java b/test/jdk/java/lang/module/ModuleReader/patched/PatchedModuleReaderTest.java new file mode 100644 index 00000000000..80f4e324627 --- /dev/null +++ b/test/jdk/java/lang/module/ModuleReader/patched/PatchedModuleReaderTest.java @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2025, 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.io.IOException; +import java.lang.module.ModuleFinder; +import java.lang.module.ModuleReader; +import java.lang.module.ModuleReference; +import java.net.URI; +import java.util.Optional; +import java.util.stream.Stream; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/* + * @test + * @bug 8372787 + * @summary Test the behaviour of ModuleReader when using --patch-module + * @comment patch the java.base module with a test specific resource + * @compile/module=java.base java/lang/PatchedFoo.java + * @run junit/othervm ${test.main.class} + */ +class PatchedModuleReaderTest { + + private static ModuleReference patchedModuleRef; + + @BeforeAll + static void beforeAll() { + patchedModuleRef = ModuleFinder.ofSystem() + .find("java.base") + .orElseThrow(); + } + + /* + * Verifies that the resource that was patched into a module + * is found by the ModuleReader. + */ + @Test + void testResourceFound() throws Exception { + try (ModuleReader reader = patchedModuleRef.open()) { + String resourceName = "java/lang/PatchedFoo.class"; + Optional res = reader.find(resourceName); + assertTrue(res.isPresent(), resourceName + " is missing in " + + patchedModuleRef.descriptor().name() + " module"); + URI uri = res.get(); + assertEquals("file", uri.getScheme(), + "unexpected scheme in resource URI " + uri); + assertTrue(uri.getPath().endsWith(resourceName), + "unexpected path component " + uri.getPath() + + " in resource URI " + uri); + + } + } + + /* + * Verifies the ModuleReader against a resource which isn't + * expected to be part of the patched module. + */ + @Test + void testResourceNotFound() throws Exception { + try (ModuleReader reader = patchedModuleRef.open()) { + String nonExistentResource = "foo/bar/NonExistent.class"; + Optional res = reader.find(nonExistentResource); + assertTrue(res.isEmpty(), "unexpected resource " + nonExistentResource + + " in " + patchedModuleRef.descriptor().name() + " module"); + } + } + + /* + * This test opens a ModuleReader for a patched module, accumulates + * the Stream of resources from that ModuleReader and then closes that + * ModuleReader. It then verifies that the closed ModuleReader + * throws the specified IOException whenever it is used for subsequent + * operations on the Stream of resources. + */ + @Test + void testIOExceptionAfterClose() throws Exception { + ModuleReader reader; + Stream resources; + try (var _ = reader = patchedModuleRef.open()) { + // hold on to the available resources, to test them after the + // ModuleReader is closed + resources = reader.list(); + } // close the ModuleReader + + // verify IOException is thrown by the closed ModuleReader + + assertThrows(IOException.class, () -> reader.list(), + "ModuleReader.list()"); + + resources.forEach(rn -> { + assertThrows(IOException.class, () -> reader.read(rn), + "ModuleReader.read(String)"); + assertThrows(IOException.class, () -> reader.open(rn), + "ModuleReader.open(String)"); + assertThrows(IOException.class, () -> reader.find(rn), + "ModuleReader.find(String)"); + }); + + // repeat the test for a non-existent resource + String nonExistentResource = "foo/bar/NonExistent.class"; + assertThrows(IOException.class, () -> reader.read(nonExistentResource), + "ModuleReader.read(String)"); + assertThrows(IOException.class, () -> reader.open(nonExistentResource), + "ModuleReader.open(String)"); + assertThrows(IOException.class, () -> reader.find(nonExistentResource), + "ModuleReader.find(String)"); + } +} diff --git a/test/jdk/java/lang/module/ModuleReader/patched/java.base/java/lang/PatchedFoo.java b/test/jdk/java/lang/module/ModuleReader/patched/java.base/java/lang/PatchedFoo.java new file mode 100644 index 00000000000..814757134d6 --- /dev/null +++ b/test/jdk/java/lang/module/ModuleReader/patched/java.base/java/lang/PatchedFoo.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2025, 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 java.lang; + +public class PatchedFoo { +} From d3083ac05453c9dd303038f90ddab50d52124e51 Mon Sep 17 00:00:00 2001 From: Yasumasa Suenaga Date: Tue, 2 Dec 2025 12:19:48 +0000 Subject: [PATCH 088/706] 8371194: serviceability/sa/TestJhsdbJstackMixedWithXComp.java failing Co-authored-by: Patricio Chilano Mateo Reviewed-by: cjplummer, pchilanomate --- .../debugger/bsd/BsdDebuggerLocal.java | 48 ++++--- .../sun/jvm/hotspot/debugger/cdbg/CFrame.java | 11 +- .../debugger/linux/LinuxCDebugger.java | 14 +- .../linux/aarch64/LinuxAARCH64CFrame.java | 39 +++++- .../linux/amd64/LinuxAMD64CFrame.java | 67 ++++++--- .../linux/ppc64/LinuxPPC64CFrame.java | 10 +- .../linux/riscv64/LinuxRISCV64CFrame.java | 26 +++- .../hotspot/runtime/aarch64/AARCH64Frame.java | 10 +- .../jvm/hotspot/runtime/amd64/AMD64Frame.java | 4 +- .../classes/sun/jvm/hotspot/tools/PStack.java | 131 ++++++++---------- test/hotspot/jtreg/ProblemList.txt | 1 - .../sa/TestJhsdbJstackMixedWithXComp.java | 31 ++++- 12 files changed, 256 insertions(+), 136 deletions(-) diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebuggerLocal.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebuggerLocal.java index 10f6881d010..efbb613994d 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebuggerLocal.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebuggerLocal.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2025, 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,7 +25,9 @@ package sun.jvm.hotspot.debugger.bsd; import java.util.ArrayList; +import java.util.Collections; import java.util.List; +import java.util.stream.IntStream; import sun.jvm.hotspot.debugger.Address; import sun.jvm.hotspot.debugger.DebuggerBase; @@ -75,10 +77,11 @@ public class BsdDebuggerLocal extends DebuggerBase implements BsdDebugger { // CDebugger support private BsdCDebugger cdbg; - // threadList and loadObjectList are filled by attach0 method - private List threadList; + // loadObjectList is filled by attach0 method private List loadObjectList; + private List javaThreadList; + // called by native method lookupByAddress0 private ClosestSymbol createClosestSymbol(String name, long offset) { return new ClosestSymbol(name, offset); @@ -241,10 +244,21 @@ public class BsdDebuggerLocal extends DebuggerBase implements BsdDebugger { } } + private void fillJavaThreadList() { + // TODO: thread list on macOS is now supported for corefile only. + if (!isCore && isDarwin) { + javaThreadList = Collections.emptyList(); + } else { + Threads threads = VM.getVM().getThreads(); + javaThreadList = IntStream.range(0, threads.getNumberOfThreads()) + .mapToObj(threads::getJavaThreadAt) + .toList(); + } + } + /** From the Debugger interface via JVMDebugger */ public synchronized void attach(int processID) throws DebuggerException { checkAttached(); - threadList = new ArrayList<>(); loadObjectList = new ArrayList<>(); class AttachTask implements WorkerThreadTask { int pid; @@ -264,7 +278,6 @@ public class BsdDebuggerLocal extends DebuggerBase implements BsdDebugger { /** From the Debugger interface via JVMDebugger */ public synchronized void attach(String execName, String coreName) { checkAttached(); - threadList = new ArrayList<>(); loadObjectList = new ArrayList<>(); attach0(execName, coreName); attached = true; @@ -278,7 +291,7 @@ public class BsdDebuggerLocal extends DebuggerBase implements BsdDebugger { return false; } - threadList = null; + javaThreadList = null; loadObjectList = null; if (isCore) { @@ -492,7 +505,12 @@ public class BsdDebuggerLocal extends DebuggerBase implements BsdDebugger { /** From the BsdCDebugger interface */ public List getThreadList() { requireAttach(); - return threadList; + if (javaThreadList == null) { + fillJavaThreadList(); + } + return javaThreadList.stream() + .map(JavaThread::getThreadProxy) + .toList(); } /** From the BsdCDebugger interface */ @@ -561,21 +579,19 @@ public class BsdDebuggerLocal extends DebuggerBase implements BsdDebugger { /** this functions used for core file reading and called from native attach0, it returns an array of long integers as [thread_id, stack_start, stack_end, thread_id, stack_start, stack_end, ....] for - all java threads recorded in Threads. Also adds the ThreadProxy to threadList */ + all java threads recorded in Threads. */ public long[] getJavaThreadsInfo() { requireAttach(); - Threads threads = VM.getVM().getThreads(); - int len = threads.getNumberOfThreads(); - long[] result = new long[len * 3]; // triple + if (javaThreadList == null) { + fillJavaThreadList(); + } + long[] result = new long[javaThreadList.size() * 3]; // triple long beg, end; int i = 0; - for (int k = 0; k < threads.getNumberOfThreads(); k++) { - JavaThread t = threads.getJavaThreadAt(k); + for (var t : javaThreadList) { end = t.getStackBaseValue(); beg = end - t.getStackSize(); - BsdThread bsdt = (BsdThread)t.getThreadProxy(); - long uid = bsdt.getUniqueThreadId(); - if (threadList != null) threadList.add(bsdt); + long uid = ((BsdThread)t.getThreadProxy()).getUniqueThreadId(); result[i] = uid; result[i + 1] = beg; result[i + 2] = end; diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/CFrame.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/CFrame.java index 47f41fe1383..bc366ef02b5 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/CFrame.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/CFrame.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, 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 sun.jvm.hotspot.debugger.cdbg; import sun.jvm.hotspot.debugger.*; +import sun.jvm.hotspot.runtime.*; +import sun.jvm.hotspot.utilities.*; /** Models a "C" programming language frame on the stack -- really just an arbitrary frame with hooks to access C and C++ debug @@ -37,7 +39,7 @@ public interface CFrame { public CFrame sender(ThreadProxy th); /** Find sender frame with given FP and PC */ - public default CFrame sender(ThreadProxy th, Address fp, Address pc) { + public default CFrame sender(ThreadProxy th, Address sp, Address fp, Address pc) { return sender(th); } @@ -70,4 +72,9 @@ public interface CFrame { /** Visit all local variables in this frame if debug information is available. Automatically descends into compound types and arrays. */ public void iterateLocals(ObjectVisitor v); + + /** Get Frame instance assosiated with this CFrame. */ + public default Frame toFrame() { + throw new UnsupportedPlatformException(); + } } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/LinuxCDebugger.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/LinuxCDebugger.java index 894e31949b2..e3543503216 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/LinuxCDebugger.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/LinuxCDebugger.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2015, Red Hat Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -81,9 +81,11 @@ class LinuxCDebugger implements CDebugger { String cpu = dbg.getCPU(); if (cpu.equals("amd64")) { AMD64ThreadContext context = (AMD64ThreadContext) thread.getContext(); + Address sp = context.getRegisterAsAddress(AMD64ThreadContext.RSP); + if (sp == null) return null; Address pc = context.getRegisterAsAddress(AMD64ThreadContext.RIP); if (pc == null) return null; - return LinuxAMD64CFrame.getTopFrame(dbg, pc, context); + return LinuxAMD64CFrame.getTopFrame(dbg, sp, pc, context); } else if (cpu.equals("ppc64")) { PPC64ThreadContext context = (PPC64ThreadContext) thread.getContext(); Address sp = context.getRegisterAsAddress(PPC64ThreadContext.SP); @@ -93,18 +95,22 @@ class LinuxCDebugger implements CDebugger { return new LinuxPPC64CFrame(dbg, sp, pc, LinuxDebuggerLocal.getAddressSize()); } else if (cpu.equals("aarch64")) { AARCH64ThreadContext context = (AARCH64ThreadContext) thread.getContext(); + Address sp = context.getRegisterAsAddress(AARCH64ThreadContext.SP); + if (sp == null) return null; Address fp = context.getRegisterAsAddress(AARCH64ThreadContext.FP); if (fp == null) return null; Address pc = context.getRegisterAsAddress(AARCH64ThreadContext.PC); if (pc == null) return null; - return new LinuxAARCH64CFrame(dbg, fp, pc); + return new LinuxAARCH64CFrame(dbg, sp, fp, pc); } else if (cpu.equals("riscv64")) { RISCV64ThreadContext context = (RISCV64ThreadContext) thread.getContext(); + Address sp = context.getRegisterAsAddress(RISCV64ThreadContext.SP); + if (sp == null) return null; Address fp = context.getRegisterAsAddress(RISCV64ThreadContext.FP); if (fp == null) return null; Address pc = context.getRegisterAsAddress(RISCV64ThreadContext.PC); if (pc == null) return null; - return new LinuxRISCV64CFrame(dbg, fp, pc); + return new LinuxRISCV64CFrame(dbg, sp, fp, pc); } else { // Runtime exception thrown by LinuxThreadContextFactory if unknown cpu ThreadContext context = thread.getContext(); diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/aarch64/LinuxAARCH64CFrame.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/aarch64/LinuxAARCH64CFrame.java index 93edb43eb82..5f76e6308e9 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/aarch64/LinuxAARCH64CFrame.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/aarch64/LinuxAARCH64CFrame.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2015, Red Hat Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -30,10 +30,14 @@ import sun.jvm.hotspot.debugger.aarch64.*; import sun.jvm.hotspot.debugger.linux.*; import sun.jvm.hotspot.debugger.cdbg.*; import sun.jvm.hotspot.debugger.cdbg.basic.*; +import sun.jvm.hotspot.code.*; +import sun.jvm.hotspot.runtime.*; +import sun.jvm.hotspot.runtime.aarch64.*; public final class LinuxAARCH64CFrame extends BasicCFrame { - public LinuxAARCH64CFrame(LinuxDebugger dbg, Address fp, Address pc) { + public LinuxAARCH64CFrame(LinuxDebugger dbg, Address sp, Address fp, Address pc) { super(dbg.getCDebugger()); + this.sp = sp; this.fp = fp; this.pc = pc; this.dbg = dbg; @@ -55,11 +59,11 @@ public final class LinuxAARCH64CFrame extends BasicCFrame { @Override public CFrame sender(ThreadProxy thread) { - return sender(thread, null, null); + return sender(thread, null, null, null); } @Override - public CFrame sender(ThreadProxy thread, Address nextFP, Address nextPC) { + public CFrame sender(ThreadProxy thread, Address nextSP, Address nextFP, Address nextPC) { // Check fp // Skip if both nextFP and nextPC are given - do not need to load from fp. if (nextFP == null && nextPC == null) { @@ -86,7 +90,32 @@ public final class LinuxAARCH64CFrame extends BasicCFrame { if (nextPC == null) { return null; } - return new LinuxAARCH64CFrame(dbg, nextFP, nextPC); + + if (nextSP == null) { + CodeCache cc = VM.getVM().getCodeCache(); + CodeBlob currentBlob = cc.findBlobUnsafe(pc()); + + // This case is different from HotSpot. See JDK-8371194 for details. + if (currentBlob != null && (currentBlob.isContinuationStub() || currentBlob.isNativeMethod())) { + // Use FP since it should always be valid for these cases. + // TODO: These should be walked as Frames not CFrames. + nextSP = fp.addOffsetTo(2 * ADDRESS_SIZE); + } else { + CodeBlob codeBlob = cc.findBlobUnsafe(nextPC); + boolean useCodeBlob = codeBlob != null && codeBlob.getFrameSize() > 0; + nextSP = useCodeBlob ? nextFP.addOffsetTo((2 * ADDRESS_SIZE) - codeBlob.getFrameSize()) : nextFP; + } + } + if (nextSP == null) { + return null; + } + + return new LinuxAARCH64CFrame(dbg, nextSP, nextFP, nextPC); + } + + @Override + public Frame toFrame() { + return new AARCH64Frame(sp, fp, pc); } // package/class internals only diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/amd64/LinuxAMD64CFrame.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/amd64/LinuxAMD64CFrame.java index 9fa0fc20e99..612203634f3 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/amd64/LinuxAMD64CFrame.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/amd64/LinuxAMD64CFrame.java @@ -29,10 +29,12 @@ import sun.jvm.hotspot.debugger.amd64.*; import sun.jvm.hotspot.debugger.linux.*; import sun.jvm.hotspot.debugger.cdbg.*; import sun.jvm.hotspot.debugger.cdbg.basic.*; +import sun.jvm.hotspot.runtime.*; +import sun.jvm.hotspot.runtime.amd64.*; public final class LinuxAMD64CFrame extends BasicCFrame { - public static LinuxAMD64CFrame getTopFrame(LinuxDebugger dbg, Address rip, ThreadContext context) { + public static LinuxAMD64CFrame getTopFrame(LinuxDebugger dbg, Address rsp, Address rip, ThreadContext context) { Address libptr = dbg.findLibPtrByAddress(rip); Address cfa = context.getRegisterAsAddress(AMD64ThreadContext.RBP); DwarfParser dwarf = null; @@ -45,7 +47,7 @@ public final class LinuxAMD64CFrame extends BasicCFrame { // DWARF processing should succeed when the frame is native // but it might fail if Common Information Entry (CIE) has language // personality routine and/or Language Specific Data Area (LSDA). - return new LinuxAMD64CFrame(dbg, cfa, rip, dwarf, true); + return new LinuxAMD64CFrame(dbg, rsp, cfa, rip, dwarf, true); } cfa = context.getRegisterAsAddress(dwarf.getCFARegister()) @@ -53,19 +55,20 @@ public final class LinuxAMD64CFrame extends BasicCFrame { } return (cfa == null) ? null - : new LinuxAMD64CFrame(dbg, cfa, rip, dwarf); + : new LinuxAMD64CFrame(dbg, rsp, cfa, rip, dwarf); } - private LinuxAMD64CFrame(LinuxDebugger dbg, Address cfa, Address rip, DwarfParser dwarf) { - this(dbg, cfa, rip, dwarf, false); + private LinuxAMD64CFrame(LinuxDebugger dbg, Address rsp, Address cfa, Address rip, DwarfParser dwarf) { + this(dbg, rsp, cfa, rip, dwarf, false); } - private LinuxAMD64CFrame(LinuxDebugger dbg, Address cfa, Address rip, DwarfParser dwarf, boolean finalFrame) { - this(dbg, cfa, rip, dwarf, finalFrame, false); + private LinuxAMD64CFrame(LinuxDebugger dbg, Address rsp, Address cfa, Address rip, DwarfParser dwarf, boolean finalFrame) { + this(dbg, rsp, cfa, rip, dwarf, finalFrame, false); } - private LinuxAMD64CFrame(LinuxDebugger dbg, Address cfa, Address rip, DwarfParser dwarf, boolean finalFrame, boolean use1ByteBeforeToLookup) { + private LinuxAMD64CFrame(LinuxDebugger dbg, Address rsp, Address cfa, Address rip, DwarfParser dwarf, boolean finalFrame, boolean use1ByteBeforeToLookup) { super(dbg.getCDebugger()); + this.rsp = rsp; this.cfa = cfa; this.rip = rip; this.dbg = dbg; @@ -107,7 +110,14 @@ public final class LinuxAMD64CFrame extends BasicCFrame { (!isNative || (isNative && nextCFA.greaterThan(cfa))); } - private Address getNextCFA(DwarfParser nextDwarf, ThreadContext context, Address senderFP) { + private Address getNextRSP() { + // next RSP should be previous slot of return address. + var bp = dwarf == null ? cfa.addOffsetTo(ADDRESS_SIZE) // top of BP points callser BP + : cfa.addOffsetTo(dwarf.getReturnAddressOffsetFromCFA()); + return bp.addOffsetTo(ADDRESS_SIZE); + } + + private Address getNextCFA(DwarfParser nextDwarf, ThreadContext context, Address senderFP, Address senderPC) { Address nextCFA; boolean isNative = false; @@ -115,13 +125,17 @@ public final class LinuxAMD64CFrame extends BasicCFrame { senderFP = cfa.getAddressAt(0); // RBP by default } - if (nextDwarf == null) { // Next frame is Java + if (VM.getVM().getCodeCache().contains(senderPC)) { // Next frame is Java nextCFA = (dwarf == null) ? senderFP // Current frame is Java : cfa.getAddressAt(dwarf.getBasePointerOffsetFromCFA()); // Current frame is Native } else { // Next frame is Native - if (dwarf == null) { // Current frame is Java + if (VM.getVM().getCodeCache().contains(pc())) { // Current frame is Java nextCFA = senderFP.addOffsetTo(-nextDwarf.getBasePointerOffsetFromCFA()); } else { // Current frame is Native + if (nextDwarf == null) { // maybe runtime entrypoint (_start()) + throw new DebuggerException("nextDwarf is null even though native call"); + } + isNative = true; int nextCFAReg = nextDwarf.getCFARegister(); if (nextCFAReg == AMD64ThreadContext.RBP) { @@ -130,10 +144,7 @@ public final class LinuxAMD64CFrame extends BasicCFrame { Address nextRBP = rbp.getAddressAt(0); nextCFA = nextRBP.addOffsetTo(-nextDwarf.getBasePointerOffsetFromCFA()); } else if (nextCFAReg == AMD64ThreadContext.RSP) { - // next RSP should be previous slot of return address. - Address nextRSP = cfa.addOffsetTo(dwarf.getReturnAddressOffsetFromCFA()) - .addOffsetTo(ADDRESS_SIZE); - nextCFA = nextRSP.addOffsetTo(nextDwarf.getCFAOffset()); + nextCFA = getNextRSP().addOffsetTo(nextDwarf.getCFAOffset()); } else { throw new DebuggerException("Unsupported CFA register: " + nextCFAReg); } @@ -153,17 +164,22 @@ public final class LinuxAMD64CFrame extends BasicCFrame { @Override public CFrame sender(ThreadProxy th) { - return sender(th, null, null); + return sender(th, null, null, null); } @Override - public CFrame sender(ThreadProxy th, Address fp, Address pc) { + public CFrame sender(ThreadProxy th, Address sp, Address fp, Address pc) { if (finalFrame) { return null; } ThreadContext context = th.getContext(); + Address nextRSP = sp != null ? sp : getNextRSP(); + if (nextRSP == null) { + return null; + } + Address nextPC = pc != null ? pc : getNextPC(dwarf != null); if (nextPC == null) { return null; @@ -183,13 +199,16 @@ public final class LinuxAMD64CFrame extends BasicCFrame { // DWARF processing should succeed when the frame is native // but it might fail if Common Information Entry (CIE) has language // personality routine and/or Language Specific Data Area (LSDA). - return new LinuxAMD64CFrame(dbg, null, nextPC, nextDwarf, true); + return null; } } - Address nextCFA = getNextCFA(nextDwarf, context, fp); - return nextCFA == null ? null - : new LinuxAMD64CFrame(dbg, nextCFA, nextPC, nextDwarf, false, fallback); + try { + Address nextCFA = getNextCFA(nextDwarf, context, fp, nextPC); + return new LinuxAMD64CFrame(dbg, nextRSP, nextCFA, nextPC, nextDwarf, false, fallback); + } catch (DebuggerException _) { + return null; + } } private DwarfParser createDwarfParser(Address pc) throws DebuggerException { @@ -210,8 +229,14 @@ public final class LinuxAMD64CFrame extends BasicCFrame { return nextDwarf; } + @Override + public Frame toFrame() { + return new AMD64Frame(rsp, cfa, rip); + } + // package/class internals only private static final int ADDRESS_SIZE = 8; + private Address rsp; private Address rip; private Address cfa; private LinuxDebugger dbg; diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/ppc64/LinuxPPC64CFrame.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/ppc64/LinuxPPC64CFrame.java index 424766fb1b4..c3724f14c2a 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/ppc64/LinuxPPC64CFrame.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/ppc64/LinuxPPC64CFrame.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, 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,8 @@ import sun.jvm.hotspot.debugger.ppc64.*; import sun.jvm.hotspot.debugger.linux.*; import sun.jvm.hotspot.debugger.cdbg.*; import sun.jvm.hotspot.debugger.cdbg.basic.*; +import sun.jvm.hotspot.runtime.*; +import sun.jvm.hotspot.runtime.ppc64.*; public final class LinuxPPC64CFrame extends BasicCFrame { // package/class internals only @@ -71,6 +73,12 @@ public final class LinuxPPC64CFrame extends BasicCFrame { return new LinuxPPC64CFrame(dbg, nextSP, nextPC, address_size); } + @Override + public Frame toFrame() { + // 2nd arg (raw_fp) would be derived from sp in c'tor of PPC64Frame. + return new PPC64Frame(sp, null, pc); + } + public static int PPC64_STACK_BIAS = 0; private static int address_size; private Address pc; diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/riscv64/LinuxRISCV64CFrame.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/riscv64/LinuxRISCV64CFrame.java index 76f45891c47..65563be59ec 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/riscv64/LinuxRISCV64CFrame.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/riscv64/LinuxRISCV64CFrame.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2015, Red Hat Inc. * Copyright (c) 2021, Huawei Technologies Co., Ltd. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -31,13 +31,17 @@ import sun.jvm.hotspot.debugger.riscv64.*; import sun.jvm.hotspot.debugger.linux.*; import sun.jvm.hotspot.debugger.cdbg.*; import sun.jvm.hotspot.debugger.cdbg.basic.*; +import sun.jvm.hotspot.runtime.*; +import sun.jvm.hotspot.runtime.riscv64.*; public final class LinuxRISCV64CFrame extends BasicCFrame { private static final int C_FRAME_LINK_OFFSET = -2; private static final int C_FRAME_RETURN_ADDR_OFFSET = -1; + private static final int C_FRAME_SENDER_SP_OFFSET = 0; - public LinuxRISCV64CFrame(LinuxDebugger dbg, Address fp, Address pc) { + public LinuxRISCV64CFrame(LinuxDebugger dbg, Address sp, Address fp, Address pc) { super(dbg.getCDebugger()); + this.sp = sp; this.fp = fp; this.pc = pc; this.dbg = dbg; @@ -59,11 +63,11 @@ public final class LinuxRISCV64CFrame extends BasicCFrame { @Override public CFrame sender(ThreadProxy thread) { - return sender(thread, null, null); + return sender(thread, null, null, null); } @Override - public CFrame sender(ThreadProxy thread, Address nextFP, Address nextPC) { + public CFrame sender(ThreadProxy thread, Address nextSP, Address nextFP, Address nextPC) { // Check fp // Skip if both nextFP and nextPC are given - do not need to load from fp. if (nextFP == null && nextPC == null) { @@ -77,6 +81,13 @@ public final class LinuxRISCV64CFrame extends BasicCFrame { } } + if (nextSP == null) { + nextSP = fp.getAddressAt(C_FRAME_SENDER_SP_OFFSET * ADDRESS_SIZE); + } + if (nextSP == null) { + return null; + } + if (nextFP == null) { nextFP = fp.getAddressAt(C_FRAME_LINK_OFFSET * ADDRESS_SIZE); } @@ -91,7 +102,12 @@ public final class LinuxRISCV64CFrame extends BasicCFrame { return null; } - return new LinuxRISCV64CFrame(dbg, nextFP, nextPC); + return new LinuxRISCV64CFrame(dbg, nextSP, nextFP, nextPC); + } + + @Override + public Frame toFrame() { + return new RISCV64Frame(sp, fp, pc); } // package/class internals only diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/aarch64/AARCH64Frame.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/aarch64/AARCH64Frame.java index 5ae4cb703b3..7233d508cbc 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/aarch64/AARCH64Frame.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/aarch64/AARCH64Frame.java @@ -272,9 +272,7 @@ public class AARCH64Frame extends Frame { if (cb != null) { if (cb.isUpcallStub()) { return senderForUpcallStub(map, (UpcallStub)cb); - } else if (cb.isContinuationStub()) { - return senderForContinuationStub(map, cb); - } else { + } else if (cb.getFrameSize() > 0) { return senderForCompiledFrame(map, cb); } } @@ -389,7 +387,11 @@ public class AARCH64Frame extends Frame { if (Assert.ASSERTS_ENABLED) { Assert.that(cb.getFrameSize() > 0, "must have non-zero frame size"); } - Address senderSP = getUnextendedSP().addOffsetTo(cb.getFrameSize()); + + // TODO: senderSP should consider not only PreserveFramePointer but also _sp_is_trusted. + Address senderSP = !VM.getVM().getCommandLineBooleanFlag("PreserveFramePointer") + ? getUnextendedSP().addOffsetTo(cb.getFrameSize()) + : getSenderSP(); // The return_address is always the word on the stack Address senderPC = stripPAC(senderSP.getAddressAt(-1 * VM.getVM().getAddressSize())); diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/amd64/AMD64Frame.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/amd64/AMD64Frame.java index 360f62a253d..fa9d50160e1 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/amd64/AMD64Frame.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/amd64/AMD64Frame.java @@ -272,9 +272,7 @@ public class AMD64Frame extends Frame { if (cb != null) { if (cb.isUpcallStub()) { return senderForUpcallStub(map, (UpcallStub)cb); - } else if (cb.isContinuationStub()) { - return senderForContinuationStub(map, cb); - } else { + } else if (cb.getFrameSize() > 0) { return senderForCompiledFrame(map, cb); } } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/PStack.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/PStack.java index 9865fbbe0f2..29d2954efdc 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/PStack.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/PStack.java @@ -70,7 +70,6 @@ public class PStack extends Tool { if (cdbg != null) { ConcurrentLocksPrinter concLocksPrinter = null; // compute and cache java Vframes. - initJFrameCache(); if (concurrentLocks) { concLocksPrinter = new ConcurrentLocksPrinter(out); } @@ -96,6 +95,7 @@ public class PStack extends Tool { return; } final boolean cdbgCanDemangle = cdbg.canDemangle(); + Map proxyToThread = createProxyToThread();; String fillerForAddress = " ".repeat(2 + 2 * (int) VM.getVM().getAddressSize()) + "\t"; for (Iterator itr = l.iterator() ; itr.hasNext();) { ThreadProxy th = itr.next(); @@ -109,6 +109,7 @@ public class PStack extends Tool { jthread.printThreadInfoOn(out); } while (f != null) { + Address senderSP = null; Address senderFP = null; Address senderPC = null; ClosestSymbol sym = f.closestSymbolToPC(); @@ -131,7 +132,7 @@ public class PStack extends Tool { // check interpreter frame Interpreter interp = VM.getVM().getInterpreter(); if (interp.contains(pc)) { - nameInfo = getJavaNames(th, f.localVariableBase()); + nameInfo = getJavaNames(jthread, f); // print codelet name if we can't determine method if (nameInfo == null || nameInfo.names() == null || nameInfo.names().length == 0) { out.print(" "); @@ -156,7 +157,7 @@ public class PStack extends Tool { } out.println(" (Native method)"); } else { - nameInfo = getJavaNames(th, f.localVariableBase()); + nameInfo = getJavaNames(jthread, f); // just print compiled code, if can't determine method if (nameInfo == null || nameInfo.names() == null || nameInfo.names().length == 0) { out.println(""); @@ -164,6 +165,12 @@ public class PStack extends Tool { } } else { out.println("<" + cb.getName() + ">"); + if (cb.getFrameSize() > 0) { + Frame senderFrame = f.toFrame().sender(jthread.newRegisterMap(true)); + senderSP = senderFrame.getSP(); + senderFP = senderFrame.getFP(); + senderPC = senderFrame.getPC(); + } } } else { printUnknown(out); @@ -180,11 +187,12 @@ public class PStack extends Tool { out.println(nameInfo.names()[i]); } } + senderSP = nameInfo.senderSP(); senderFP = nameInfo.senderFP(); senderPC = nameInfo.senderPC(); } } - f = f.sender(th, senderFP, senderPC); + f = f.sender(th, senderSP, senderFP, senderPC); } } catch (Exception exp) { exp.printStackTrace(); @@ -212,95 +220,74 @@ public class PStack extends Tool { } // -- Internals only below this point - private Map jframeCache; - private Map proxyToThread; private PrintStream out; private boolean verbose; private boolean concurrentLocks; - private void initJFrameCache() { - // cache frames for subsequent reference - jframeCache = new HashMap<>(); - proxyToThread = new HashMap<>(); + private Map createProxyToThread() { + Map proxyToThread = new HashMap<>(); Threads threads = VM.getVM().getThreads(); for (int i = 0; i < threads.getNumberOfThreads(); i++) { - JavaThread cur = threads.getJavaThreadAt(i); - List tmp = new ArrayList<>(10); - try { - for (JavaVFrame vf = cur.getLastJavaVFrameDbg(); vf != null; vf = vf.javaSender()) { - tmp.add(vf); - } - } catch (Exception exp) { - // may be we may get frames for other threads, continue - // after printing stack trace. - exp.printStackTrace(); - } - JavaVFrame[] jvframes = tmp.toArray(new JavaVFrame[0]); - jframeCache.put(cur.getThreadProxy(), jvframes); - proxyToThread.put(cur.getThreadProxy(), cur); + JavaThread jthread = threads.getJavaThreadAt(i); + proxyToThread.put(jthread.getThreadProxy(), jthread); } + return proxyToThread; } private void printUnknown(PrintStream out) { out.println("\t????????"); } - private static record JavaNameInfo(String[] names, Address senderFP, Address senderPC) {}; - - private JavaNameInfo getJavaNames(ThreadProxy th, Address fp) { - if (fp == null) { - return null; - } - JavaVFrame[] jvframes = jframeCache.get(th); - if (jvframes == null) return null; // not a java thread + private static record JavaNameInfo(String[] names, Address senderSP, Address senderFP, Address senderPC) {}; + private JavaNameInfo getJavaNames(JavaThread jthread, CFrame f) { List names = new ArrayList<>(10); - JavaVFrame bottomJVFrame = null; - for (int fCount = 0; fCount < jvframes.length; fCount++) { - JavaVFrame vf = jvframes[fCount]; - Frame f = vf.getFrame(); - if (fp.equals(f.getFP())) { - bottomJVFrame = vf; - StringBuilder sb = new StringBuilder(); - Method method = vf.getMethod(); - // a special char to identify java frames in output - sb.append("* "); - sb.append(method.externalNameAndSignature()); - sb.append(" bci:").append(vf.getBCI()); - int lineNumber = method.getLineNumberFromBCI(vf.getBCI()); - if (lineNumber != -1) { - sb.append(" line:").append(lineNumber); - } - - if (verbose) { - sb.append(" Method*:").append(method.getAddress()); - } - - if (vf.isCompiledFrame()) { - sb.append(" (Compiled frame"); - if (vf.isDeoptimized()) { - sb.append(" [deoptimized]"); - } - } else if (vf.isInterpretedFrame()) { - sb.append(" (Interpreted frame"); - } - if (vf.mayBeImpreciseDbg()) { - sb.append("; information may be imprecise"); - } - sb.append(")"); - names.add(sb.toString()); - } - } - + Address senderSP = null; Address senderFP = null; Address senderPC = null; - if (bottomJVFrame != null) { - Frame senderFrame = bottomJVFrame.getFrame().sender((RegisterMap)bottomJVFrame.getRegisterMap().clone()); + VFrame vf = VFrame.newVFrame(f.toFrame(), jthread.newRegisterMap(true), jthread, true, true); + while (vf != null && vf.isJavaFrame()) { + StringBuilder sb = new StringBuilder(); + Method method = ((JavaVFrame)vf).getMethod(); + // a special char to identify java frames in output + sb.append("* "); + sb.append(method.externalNameAndSignature()); + sb.append(" bci:").append(((JavaVFrame)vf).getBCI()); + int lineNumber = method.getLineNumberFromBCI(((JavaVFrame)vf).getBCI()); + if (lineNumber != -1) { + sb.append(" line:").append(lineNumber); + } + + if (verbose) { + sb.append(" Method*:").append(method.getAddress()); + } + + if (vf.isCompiledFrame()) { + sb.append(" (Compiled frame"); + if (vf.isDeoptimized()) { + sb.append(" [deoptimized]"); + } + } else if (vf.isInterpretedFrame()) { + sb.append(" (Interpreted frame"); + } + if (vf.mayBeImpreciseDbg()) { + sb.append("; information may be imprecise"); + } + sb.append(")"); + names.add(sb.toString()); + + // Keep registers in sender Frame + Frame senderFrame = vf.getFrame() + .sender((RegisterMap)vf.getRegisterMap().clone()); + senderSP = senderFrame.getSP(); senderFP = senderFrame.getFP(); senderPC = senderFrame.getPC(); + + // Get sender VFrame for next stack walking + vf = vf.sender(true); } - return new JavaNameInfo(names.toArray(new String[0]), senderFP, senderPC); + return new JavaNameInfo(names.toArray(new String[0]), senderSP, senderFP, senderPC); } public void setVerbose(boolean verbose) { diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index 423bcdecaa8..a51e8aef5ee 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -143,7 +143,6 @@ serviceability/sa/TestJmapCore.java 8318754 macosx-aarch64 serviceability/sa/TestJmapCoreMetaspace.java 8318754 macosx-aarch64 serviceability/sa/ClhsdbThreadContext.java 8356704 windows-x64 -serviceability/sa/TestJhsdbJstackMixedWithXComp.java 8371194 linux-x64 serviceability/jvmti/stress/StackTrace/NotSuspended/GetStackTraceNotSuspendedStressTest.java 8315980 linux-all,windows-x64 diff --git a/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackMixedWithXComp.java b/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackMixedWithXComp.java index 043a198331e..a26fc4532df 100644 --- a/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackMixedWithXComp.java +++ b/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackMixedWithXComp.java @@ -23,6 +23,7 @@ */ import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import jdk.test.lib.JDKToolLauncher; @@ -32,7 +33,7 @@ import jdk.test.lib.apps.LingeredApp; import jdk.test.lib.process.OutputAnalyzer; /** - * @test + * @test id=xcomp * @bug 8370176 * @requires vm.hasSA * @requires os.family == "linux" @@ -40,6 +41,28 @@ import jdk.test.lib.process.OutputAnalyzer; * @library /test/lib * @run driver TestJhsdbJstackMixedWithXComp */ + +/** + * @test id=xcomp-preserve-frame-pointer + * @bug 8370176 + * @requires vm.hasSA + * @requires os.family == "linux" + * @requires os.arch == "amd64" + * @library /test/lib + * @run driver TestJhsdbJstackMixedWithXComp -XX:+PreserveFramePointer + */ + +/** + * @test id=xcomp-disable-tiered-compilation + * @bug 8370176 + * @requires vm.hasSA + * @requires os.family == "linux" + * @requires os.arch == "amd64" + * @library /test/lib + * @run driver TestJhsdbJstackMixedWithXComp -XX:-TieredCompilation + */ + + public class TestJhsdbJstackMixedWithXComp { private static void runJstack(LingeredApp app) throws Exception { @@ -89,8 +112,12 @@ public class TestJhsdbJstackMixedWithXComp { LingeredApp app = null; try { + List jvmOpts = new ArrayList<>(); + jvmOpts.add("-Xcomp"); + jvmOpts.addAll(Arrays.asList(args)); + app = new LingeredAppWithVirtualThread(); - LingeredApp.startApp(app, "-Xcomp"); + LingeredApp.startApp(app, jvmOpts.toArray(new String[0])); System.out.println("Started LingeredApp with pid " + app.getPid()); runJstack(app); System.out.println("Test Completed"); From 6abf7b6f226adb580718a314dc218d87289c80ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20Sikstr=C3=B6m?= Date: Tue, 2 Dec 2025 12:38:16 +0000 Subject: [PATCH 089/706] 8371986: Remove the default value of InitialRAMPercentage Reviewed-by: shade, aboldtch --- src/hotspot/share/gc/shared/gc_globals.hpp | 2 +- src/hotspot/share/runtime/flags/jvmFlag.cpp | 2 +- src/java.base/share/man/java.md | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/hotspot/share/gc/shared/gc_globals.hpp b/src/hotspot/share/gc/shared/gc_globals.hpp index e86a8744847..d08e95378f7 100644 --- a/src/hotspot/share/gc/shared/gc_globals.hpp +++ b/src/hotspot/share/gc/shared/gc_globals.hpp @@ -291,7 +291,7 @@ "size on systems with small physical memory size") \ range(0.0, 100.0) \ \ - product(double, InitialRAMPercentage, 0.2, \ + product(double, InitialRAMPercentage, 0.0, \ "Percentage of real memory used for initial heap size") \ range(0.0, 100.0) \ \ diff --git a/src/hotspot/share/runtime/flags/jvmFlag.cpp b/src/hotspot/share/runtime/flags/jvmFlag.cpp index 487528c49bd..51517fa49db 100644 --- a/src/hotspot/share/runtime/flags/jvmFlag.cpp +++ b/src/hotspot/share/runtime/flags/jvmFlag.cpp @@ -162,7 +162,7 @@ void JVMFlag::print_on(outputStream* st, bool withComments, bool printRanges) co // uintx ThresholdTolerance = 10 {product} {default} // size_t TLABSize = 0 {product} {default} // uintx SurvivorRatio = 8 {product} {default} - // double InitialRAMPercentage = 1.562500 {product} {default} + // double InitialRAMPercentage = 0.000000 {product} {default} // ccstr CompileCommandFile = MyFile.cmd {product} {command line} // ccstrlist CompileOnly = Method1 // CompileOnly += Method2 {product} {command line} diff --git a/src/java.base/share/man/java.md b/src/java.base/share/man/java.md index 462baa5a4a0..8517e161e3f 100644 --- a/src/java.base/share/man/java.md +++ b/src/java.base/share/man/java.md @@ -2455,8 +2455,7 @@ Java HotSpot VM. `-XX:InitialRAMPercentage=`*percent* : Sets the initial amount of memory that the JVM will use for the Java heap before applying ergonomics heuristics as a percentage of the maximum amount - determined as described in the `-XX:MaxRAM` option. The default value is - 0.2 percent. + determined as described in the `-XX:MaxRAM` option. The following example shows how to set the percentage of the initial amount of memory used for the Java heap: From eecba58c6817dbac129c545604d6286dfdcf951f Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Tue, 2 Dec 2025 13:05:46 +0000 Subject: [PATCH 090/706] 8371587: Final mapping lost in ProcSmapsParser::parse_next Reviewed-by: jsjolen, fandreuzzi --- src/hotspot/os/linux/procMapsParser.cpp | 27 +++-- src/hotspot/os/linux/procMapsParser.hpp | 3 +- .../runtime/test_procMapsParser_linux.cpp | 109 ++++++++++++++++++ 3 files changed, 125 insertions(+), 14 deletions(-) create mode 100644 test/hotspot/gtest/runtime/test_procMapsParser_linux.cpp diff --git a/src/hotspot/os/linux/procMapsParser.cpp b/src/hotspot/os/linux/procMapsParser.cpp index 47c5c6cc594..0663cae61f3 100644 --- a/src/hotspot/os/linux/procMapsParser.cpp +++ b/src/hotspot/os/linux/procMapsParser.cpp @@ -50,7 +50,14 @@ ProcSmapsParser::~ProcSmapsParser() { bool ProcSmapsParser::read_line() { _line[0] = '\0'; - return ::fgets(_line, _linelen, _f) != nullptr; + + if (::fgets(_line, _linelen, _f) == nullptr) { + // On error or EOF, ensure deterministic empty buffer + _line[0] = '\0'; + return false; + } else { + return true; + } } bool ProcSmapsParser::is_header_line() { @@ -101,8 +108,6 @@ void ProcSmapsParser::scan_additional_line(ProcSmapsInfo& out) { } } -// Starts or continues parsing. Returns true on success, -// false on EOF or on error. bool ProcSmapsParser::parse_next(ProcSmapsInfo& out) { // Information about a single mapping reaches across several lines. @@ -117,15 +122,13 @@ bool ProcSmapsParser::parse_next(ProcSmapsInfo& out) { assert(is_header_line(), "Not a header line: \"%s\".", _line); scan_header_line(out); - // Now read until we encounter the next header line or EOF or an error. - bool ok = false, stop = false; - do { - ok = read_line(); - stop = !ok || is_header_line(); - if (!stop) { - scan_additional_line(out); + while (true) { + bool ok = read_line(); + if (!ok || is_header_line()) { + break; // EOF or next header } - } while (!stop); + scan_additional_line(out); + } - return ok; + return true; // always return true if a mapping was parsed } diff --git a/src/hotspot/os/linux/procMapsParser.hpp b/src/hotspot/os/linux/procMapsParser.hpp index 06035333b2f..037af91358f 100644 --- a/src/hotspot/os/linux/procMapsParser.hpp +++ b/src/hotspot/os/linux/procMapsParser.hpp @@ -84,8 +84,7 @@ public: ProcSmapsParser(FILE* f); ~ProcSmapsParser(); - // Starts or continues parsing. Returns true on success, - // false on EOF or on error. + // Starts or continues parsing. Returns true iff a mapping was parsed. bool parse_next(ProcSmapsInfo& out); }; diff --git a/test/hotspot/gtest/runtime/test_procMapsParser_linux.cpp b/test/hotspot/gtest/runtime/test_procMapsParser_linux.cpp new file mode 100644 index 00000000000..0177acda49f --- /dev/null +++ b/test/hotspot/gtest/runtime/test_procMapsParser_linux.cpp @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2025, 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. + * + */ + +#ifdef LINUX + +#include "procMapsParser.hpp" +#include "unittest.hpp" + +#include + +TEST(ProcSmapsParserTest, ParseMappings) { + const char* smaps_content = + "7f5a00000000-7f5a00001000 r--p 00000000 00:00 0 [anon]\n" + "Size: 4 kB\n" + "KernelPageSize: 4 kB\n" + "MMUPageSize: 4 kB\n" + "Rss: 0 kB\n" + "Pss: 0 kB\n" + "Shared_Clean: 0 kB\n" + "Shared_Dirty: 0 kB\n" + "Private_Clean: 0 kB\n" + "Private_Dirty: 0 kB\n" + "Referenced: 0 kB\n" + "Anonymous: 0 kB\n" + "LazyFree: 0 kB\n" + "AnonHugePages: 0 kB\n" + "ShmemPmdMapped: 0 kB\n" + "FilePmdMapped: 0 kB\n" + "Shared_Hugetlb: 0 kB\n" + "Private_Hugetlb: 0 kB\n" + "Swap: 0 kB\n" + "SwapPss: 0 kB\n" + "Locked: 0 kB\n" + "THPeligible: 0\n" + "VmFlags: rd mr mw me ac \n" + "7f5a00001000-7f5a00002000 rw-p 00000000 00:00 0 [anon]\n" + "Size: 4 kB\n" + "KernelPageSize: 4 kB\n" + "MMUPageSize: 4 kB\n" + "Rss: 4 kB\n" + "Pss: 4 kB\n" + "Shared_Clean: 0 kB\n" + "Shared_Dirty: 0 kB\n" + "Private_Clean: 0 kB\n" + "Private_Dirty: 4 kB\n" + "Referenced: 4 kB\n" + "Anonymous: 4 kB\n" + "LazyFree: 0 kB\n" + "AnonHugePages: 0 kB\n" + "ShmemPmdMapped: 0 kB\n" + "FilePmdMapped: 0 kB\n" + "Shared_Hugetlb: 0 kB\n" + "Private_Hugetlb: 0 kB\n" + "Swap: 0 kB\n" + "SwapPss: 0 kB\n" + "Locked: 0 kB\n" + "THPeligible: 0\n" + "VmFlags: rd wr mr mw me ac \n"; + + FILE* f = fmemopen((void*)smaps_content, strlen(smaps_content), "r"); + ASSERT_TRUE(f != nullptr); + + ProcSmapsParser parser(f); + ProcSmapsInfo info; + + // First mapping + ASSERT_TRUE(parser.parse_next(info)); + EXPECT_EQ((uintptr_t)info.from, 0x7f5a00000000ULL); + EXPECT_EQ((uintptr_t)info.to, 0x7f5a00001000ULL); + EXPECT_STREQ(info.prot, "r--p"); + EXPECT_TRUE(info.rd); + EXPECT_FALSE(info.wr); + + // Second mapping + ASSERT_TRUE(parser.parse_next(info)); + EXPECT_EQ((uintptr_t)info.from, 0x7f5a00001000ULL); + EXPECT_EQ((uintptr_t)info.to, 0x7f5a00002000ULL); + EXPECT_STREQ(info.prot, "rw-p"); + EXPECT_TRUE(info.rd); + EXPECT_TRUE(info.wr); + + // End of file + ASSERT_FALSE(parser.parse_next(info)); + + fclose(f); +} + +#endif // LINUX From 6c01d3b08862447983b96daaf34a4c62daf54101 Mon Sep 17 00:00:00 2001 From: Emanuel Peter Date: Tue, 2 Dec 2025 13:10:37 +0000 Subject: [PATCH 091/706] 8372451: C2 SuperWord: "endless loop" assert. Need to implement proper worklist mechanism Reviewed-by: mhaessig, chagedorn --- src/hotspot/share/opto/vtransform.cpp | 115 ++++++++++++------ src/hotspot/share/opto/vtransform.hpp | 51 ++++++-- .../superword/TestLongReductionChain.java | 85 +++++++++++++ 3 files changed, 207 insertions(+), 44 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/loopopts/superword/TestLongReductionChain.java diff --git a/src/hotspot/share/opto/vtransform.cpp b/src/hotspot/share/opto/vtransform.cpp index b437d2e6eac..93aefe0d505 100644 --- a/src/hotspot/share/opto/vtransform.cpp +++ b/src/hotspot/share/opto/vtransform.cpp @@ -40,38 +40,76 @@ void VTransformGraph::add_vtnode(VTransformNode* vtnode) { } \ ) -// This is similar to IGVN optimization. But we are a bit lazy, and don't care about -// notification / worklist, since the list of nodes is rather small, and we don't -// expect optimizations that trickle over the whole graph. -void VTransformGraph::optimize(VTransform& vtransform) { - TRACE_OPTIMIZE( tty->print_cr("\nVTransformGraph::optimize"); ) - - bool progress = true; - DEBUG_ONLY(int pass_count = 0;) - while (progress) { - progress = false; - assert(++pass_count < 10, "ensure we do not have endless loops"); - for (int i = 0; i < _vtnodes.length(); i++) { - VTransformNode* vtn = _vtnodes.at(i); - if (!vtn->is_alive()) { continue; } - progress |= vtn->optimize(_vloop_analyzer, vtransform); - - // Nodes that have no use any more are dead. - if (vtn->out_strong_edges() == 0 && - // There are some exceptions: - // 1. Memory phi uses are not modeled, so they appear to have no use here, but must be kept alive. - // 2. Similarly, some stores may not have their memory uses modeled, but need to be kept alive. - // 3. Outer node with strong inputs: is a use after the loop that we must keep alive. - !(vtn->isa_PhiScalar() != nullptr || - vtn->is_load_or_store_in_loop() || - (vtn->isa_Outer() != nullptr && vtn->has_strong_in_edge()))) { - vtn->mark_dead(); - progress = true; - } - } +void VTransformOptimize::worklist_push(VTransformNode* vtn) { + if (!_worklist_set.test_set(vtn->_idx)) { + _worklist.push(vtn); } } +VTransformNode* VTransformOptimize::worklist_pop() { + VTransformNode* vtn = _worklist.pop(); + _worklist_set.remove(vtn->_idx); + return vtn; +} + +void VTransform::optimize() { + NOT_PRODUCT( if (vloop().is_trace_optimization()) { tty->print_cr("\nVTransform::optimize"); } ) + ResourceMark rm; + VTransformOptimize vtoptimize(_vloop_analyzer, *this); + vtoptimize.optimize(); +} + +void VTransformOptimize::optimize() { + // Initialize: push all nodes to worklist. + for (int i = 0; i < _vtransform.graph().vtnodes().length(); i++) { + VTransformNode* vtn = _vtransform.graph().vtnodes().at(i); + worklist_push(vtn); + } + + // We don't want to iterate too many times. We set some arbitrary limit, + // just to catch infinite loops. + DEBUG_ONLY( int allowed_steps = 100 * _worklist.length(); ) + + // Optimize iteratively. + while (_worklist.is_nonempty()) { + VTransformNode* vtn = worklist_pop(); + optimize_step(vtn); + assert(--allowed_steps > 0, "no endless loop"); + } + + DEBUG_ONLY( verify(); ) +} + +#ifdef ASSERT +void VTransformOptimize::verify() { + for (int i = 0; i < _vtransform.graph().vtnodes().length(); i++) { + VTransformNode* vtn = _vtransform.graph().vtnodes().at(i); + assert(!optimize_step(vtn), "Missed optimization during VTransform::optimize for %s", vtn->name()); + assert(_worklist.is_empty(), "vtnode on worklist despite no progress for %s", vtn->name()); + } +} +#endif + +// Return true if (and only if) we made progress. +bool VTransformOptimize::optimize_step(VTransformNode* vtn) { + if (!vtn->is_alive()) { return false; } + bool progress = vtn->optimize(*this); + + // Nodes that have no use any more are dead. + if (vtn->out_strong_edges() == 0 && + // There are some exceptions: + // 1. Memory phi uses are not modeled, so they appear to have no use here, but must be kept alive. + // 2. Similarly, some stores may not have their memory uses modeled, but need to be kept alive. + // 3. Outer node with strong inputs: is a use after the loop that we must keep alive. + !(vtn->isa_PhiScalar() != nullptr || + vtn->is_load_or_store_in_loop() || + (vtn->isa_Outer() != nullptr && vtn->has_strong_in_edge()))) { + vtn->mark_dead(*this); + return true; + } + return progress; +} + // Compute a linearization of the graph. We do this with a reverse-post-order of a DFS. // This only works if the graph is a directed acyclic graph (DAG). The C2 graph, and // the VLoopDependencyGraph are both DAGs, but after introduction of vectors/packs, the @@ -1141,8 +1179,8 @@ VTransformApplyResult VTransformBoolVectorNode::apply(VTransformApplyState& appl return VTransformApplyResult::make_vector(vn); } -bool VTransformReductionVectorNode::optimize(const VLoopAnalyzer& vloop_analyzer, VTransform& vtransform) { - return optimize_move_non_strict_order_reductions_out_of_loop(vloop_analyzer, vtransform); +bool VTransformReductionVectorNode::optimize(VTransformOptimize& vtoptimize) { + return optimize_move_non_strict_order_reductions_out_of_loop(vtoptimize); } int VTransformReductionVectorNode::vector_reduction_opcode() const { @@ -1213,7 +1251,7 @@ bool VTransformReductionVectorNode::requires_strict_order() const { // become profitable, since the expensive reduction node is moved // outside the loop, and instead cheaper element-wise vector accumulations // are performed inside the loop. -bool VTransformReductionVectorNode::optimize_move_non_strict_order_reductions_out_of_loop_preconditions(VTransform& vtransform) { +bool VTransformReductionVectorNode::optimize_move_non_strict_order_reductions_out_of_loop_preconditions(const VTransform& vtransform) { // We have a phi with a single use. VTransformPhiScalarNode* phi = in_req(1)->isa_PhiScalar(); if (phi == nullptr) { @@ -1260,13 +1298,13 @@ bool VTransformReductionVectorNode::optimize_move_non_strict_order_reductions_ou current_red->element_basic_type() != bt || current_red->vector_length() != vlen) { TRACE_OPTIMIZE( - tty->print(" Cannot move out of loop, other reduction node does not match:"); + tty->print(" Cannot move out of loop, other reduction node does not match: "); print(); tty->print(" other: "); if (current_red != nullptr) { current_red->print(); } else { - tty->print("nullptr"); + tty->print_cr("nullptr"); } ) return false; // not compatible @@ -1314,7 +1352,8 @@ bool VTransformReductionVectorNode::optimize_move_non_strict_order_reductions_ou return true; // success } -bool VTransformReductionVectorNode::optimize_move_non_strict_order_reductions_out_of_loop(const VLoopAnalyzer& vloop_analyzer, VTransform& vtransform) { +bool VTransformReductionVectorNode::optimize_move_non_strict_order_reductions_out_of_loop(VTransformOptimize& vtoptimize) { + VTransform& vtransform = vtoptimize.vtransform(); if (!optimize_move_non_strict_order_reductions_out_of_loop_preconditions(vtransform)) { return false; } @@ -1328,7 +1367,7 @@ bool VTransformReductionVectorNode::optimize_move_non_strict_order_reductions_ou const uint vlen = vector_length(); const BasicType bt = element_basic_type(); const int vopc = VectorNode::opcode(sopc, bt); - PhaseIdealLoop* phase = vloop_analyzer.vloop().phase(); + PhaseIdealLoop* phase = vtoptimize.vloop_analyzer().vloop().phase(); // Create a vector of identity values. Node* identity = ReductionNode::make_identity_con_scalar(phase->igvn(), sopc, bt); @@ -1341,6 +1380,7 @@ bool VTransformReductionVectorNode::optimize_move_non_strict_order_reductions_ou // Look at old scalar phi. VTransformPhiScalarNode* phi_scalar = in_req(1)->isa_PhiScalar(); PhiNode* old_phi = phi_scalar->node(); + vtoptimize.worklist_push(phi_scalar); VTransformNode* init = phi_scalar->in_req(1); TRACE_OPTIMIZE( @@ -1354,6 +1394,7 @@ bool VTransformReductionVectorNode::optimize_move_non_strict_order_reductions_ou phi_vector->init_req(0, phi_scalar->in_req(0)); phi_vector->init_req(1, vtn_identity_vector); // Note: backedge comes later + vtoptimize.worklist_push(phi_vector); // Traverse down the chain of reductions, and replace them with vector_accumulators. VTransformReductionVectorNode* first_red = this; @@ -1365,6 +1406,8 @@ bool VTransformReductionVectorNode::optimize_move_non_strict_order_reductions_ou VTransformVectorNode* vector_accumulator = new (vtransform.arena()) VTransformElementWiseVectorNode(vtransform, 3, current_red->properties(), vopc); vector_accumulator->init_req(1, current_vector_accumulator); vector_accumulator->init_req(2, vector_input); + vtoptimize.worklist_push(current_red); + vtoptimize.worklist_push(vector_accumulator); TRACE_OPTIMIZE( tty->print(" replace "); current_red->print(); diff --git a/src/hotspot/share/opto/vtransform.hpp b/src/hotspot/share/opto/vtransform.hpp index a3e4977494e..b60c71945e1 100644 --- a/src/hotspot/share/opto/vtransform.hpp +++ b/src/hotspot/share/opto/vtransform.hpp @@ -24,6 +24,7 @@ #ifndef SHARE_OPTO_VTRANSFORM_HPP #define SHARE_OPTO_VTRANSFORM_HPP +#include "libadt/vectset.hpp" #include "opto/node.hpp" #include "opto/vectorization.hpp" #include "opto/vectornode.hpp" @@ -192,7 +193,6 @@ public: const GrowableArray& vtnodes() const { return _vtnodes; } const GrowableArray& get_schedule() const { return _schedule; } - void optimize(VTransform& vtransform); bool schedule(); bool has_store_to_load_forwarding_failure(const VLoopAnalyzer& vloop_analyzer) const; float cost_for_vector_loop() const; @@ -257,7 +257,7 @@ public: DEBUG_ONLY( bool has_graph() const { return !_graph.is_empty(); } ) VTransformGraph& graph() { return _graph; } - void optimize() { return _graph.optimize(*this); } + void optimize(); bool schedule() { return _graph.schedule(); } bool is_profitable() const; float cost_for_vector_loop() const { return _graph.cost_for_vector_loop(); } @@ -291,6 +291,36 @@ private: void apply_vectorization() const; }; +// We keep track of the worklist during optimizations. +// The concept is somewhat parallel to IGVN: we keep on +// optimizing vtnodes on the worklist, which may in turn +// add more nodes to the list. We keep on optimizing until +// no more nodes are on the worklist. +class VTransformOptimize : public StackObj { +private: + const VLoopAnalyzer& _vloop_analyzer; + VTransform& _vtransform; + + GrowableArray _worklist; + VectorSet _worklist_set; + +public: + VTransformOptimize(const VLoopAnalyzer& vloop_analyzer, VTransform& vtransform) : + _vloop_analyzer(vloop_analyzer), + _vtransform(vtransform) {} + + const VLoopAnalyzer& vloop_analyzer() const { return _vloop_analyzer; } + VTransform& vtransform() { return _vtransform; } + + void worklist_push(VTransformNode* vtn); + void optimize(); + +private: + VTransformNode* worklist_pop(); + bool optimize_step(VTransformNode* vtn); + DEBUG_ONLY( void verify(); ) +}; + // Keeps track of the state during "VTransform::apply" // -> keep track of the already transformed nodes and the memory state. class VTransformApplyState : public StackObj { @@ -531,10 +561,15 @@ public: bool is_alive() const { return _is_alive; } - void mark_dead() { + void mark_dead(VTransformOptimize& vtoptimize) { _is_alive = false; - // Remove all inputs + // Remove all inputs, and put inputs on worklist in + // case they are also dead. for (uint i = 0; i < req(); i++) { + VTransformNode* in = in_req(i); + if (in != nullptr) { + vtoptimize.worklist_push(in); + } set_req(i, nullptr); } } @@ -558,7 +593,7 @@ public: virtual const VPointer& vpointer() const { ShouldNotReachHere(); } virtual bool is_loop_head_phi() const { return false; } - virtual bool optimize(const VLoopAnalyzer& vloop_analyzer, VTransform& vtransform) { return false; } + virtual bool optimize(VTransformOptimize& vtoptimize) { return false; } virtual float cost(const VLoopAnalyzer& vloop_analyzer) const = 0; @@ -868,7 +903,7 @@ public: VTransformReductionVectorNode(VTransform& vtransform, const VTransformVectorNodeProperties properties) : VTransformVectorNode(vtransform, 3, properties) {} virtual VTransformReductionVectorNode* isa_ReductionVector() override { return this; } - virtual bool optimize(const VLoopAnalyzer& vloop_analyzer, VTransform& vtransform) override; + virtual bool optimize(VTransformOptimize& vtoptimize) override; virtual float cost(const VLoopAnalyzer& vloop_analyzer) const override; virtual VTransformApplyResult apply(VTransformApplyState& apply_state) const override; NOT_PRODUCT(virtual const char* name() const override { return "ReductionVector"; };) @@ -876,8 +911,8 @@ public: private: int vector_reduction_opcode() const; bool requires_strict_order() const; - bool optimize_move_non_strict_order_reductions_out_of_loop_preconditions(VTransform& vtransform); - bool optimize_move_non_strict_order_reductions_out_of_loop(const VLoopAnalyzer& vloop_analyzer, VTransform& vtransform); + bool optimize_move_non_strict_order_reductions_out_of_loop_preconditions(const VTransform& vtransform); + bool optimize_move_non_strict_order_reductions_out_of_loop(VTransformOptimize& vtoptimize); }; class VTransformPhiVectorNode : public VTransformVectorNode { diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestLongReductionChain.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestLongReductionChain.java new file mode 100644 index 00000000000..37dd964048f --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestLongReductionChain.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2025, 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 compiler.loopopts.superword; + +import jdk.test.lib.Utils; +import java.util.Random; + +/* + * @test + * @bug 8372451 + * @summary Test long reduction chain. Triggered bug with long chain of dead ReductionVector + * vtnodes after optimize_move_non_strict_order_reductions_out_of_loop. + * @library /test/lib / + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:LoopUnrollLimit=1000 -XX:MaxVectorSize=8 -Xbatch + * -XX:CompileCommand=compileonly,${test.main.class}::test + * ${test.main.class} + * @run main ${test.main.class} + */ + +public class TestLongReductionChain { + static int RANGE = 1024*8; + private static final Random RANDOM = Utils.getRandomInstance(); + + public static void main(String[] args) { + int[] aI = generateI(); + int[] bI = generateI(); + int gold = test(aI, bI); + + for (int i = 0; i < 1000; i++) { + int result = test(aI, bI); + if (result != gold) { + throw new RuntimeException("wrong value"); + } + } + } + + static int[] generateI() { + int[] a = new int[RANGE]; + for (int i = 0; i < a.length; i++) { + a[i] = RANDOM.nextInt(); + } + return a; + } + + // Test creates a very long reduction chain, especially with -XX:LoopUnrollLimit=1000. + // Limiting the reduction vectors to 2 elements gets us a very long chain -XX:MaxVectorSize=8. + // During VTransform::optimize this means a long chain of nodes needs to be found as dead. + // Before the fix, this took too many rounds, and we hit an assert. + static int test(int[] a, int[] b) { + int s = 0; + for (int i = 0; i < RANGE; i+=8) { + s += a[i+0] * b[i+0]; + s += a[i+1] * b[i+1]; + s += a[i+2] * b[i+2]; + s += a[i+3] * b[i+3]; + + s += a[i+4] & b[i+4]; + s += a[i+5] & b[i+5]; + s += a[i+6] & b[i+6]; + s += a[i+7] & b[i+7]; + } + return s; + } +} From c97d53a9529d9148aacd85a3b31d694f04df0758 Mon Sep 17 00:00:00 2001 From: Christian Stein Date: Tue, 2 Dec 2025 13:32:22 +0000 Subject: [PATCH 092/706] 8371470: Java Launcher does not fail when running compact java-file with private no-arg constructor Reviewed-by: jpai --- .../tools/javac/launcher/SourceLauncher.java | 6 ++++ .../tools/javac/resources/launcher.properties | 6 ++++ .../javac/launcher/SourceLauncherTest.java | 35 +++++++++++++------ 3 files changed, 36 insertions(+), 11 deletions(-) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/launcher/SourceLauncher.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/launcher/SourceLauncher.java index 4d679403ee7..af7d79d4195 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/launcher/SourceLauncher.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/launcher/SourceLauncher.java @@ -226,6 +226,8 @@ public final class SourceLauncher { Object instance = null; + // Similar to sun.launcher.LauncherHelper#checkAndLoadMain, including + // checks performed in LauncherHelper#validateMainMethod if (!isStatic) { if (Modifier.isAbstract(mainClass.getModifiers())) { throw new Fault(Errors.CantInstantiate(mainClassName)); @@ -238,6 +240,10 @@ public final class SourceLauncher { throw new Fault(Errors.CantFindConstructor(mainClassName)); } + if (Modifier.isPrivate(constructor.getModifiers())) { + throw new Fault(Errors.CantUsePrivateConstructor(mainClassName)); + } + try { constructor.setAccessible(true); instance = constructor.newInstance(); diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/launcher.properties b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/launcher.properties index 122e5dca80d..36d50afad0f 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/launcher.properties +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/launcher.properties @@ -124,6 +124,12 @@ launcher.err.cant.access.main.method=\ launcher.err.cant.find.constructor=\ can''t find no argument constructor in class: {0} +# 0: string +launcher.err.cant.use.private.constructor=\ + no non-private zero argument constructor found in class {0}\n\ + remove private from existing constructor or define as:\n\ +\ public {0}() + # 0: string launcher.err.cant.access.constructor=\ can''t access no argument constructor in class: {0} diff --git a/test/langtools/tools/javac/launcher/SourceLauncherTest.java b/test/langtools/tools/javac/launcher/SourceLauncherTest.java index 6b147d32d00..37d50674855 100644 --- a/test/langtools/tools/javac/launcher/SourceLauncherTest.java +++ b/test/langtools/tools/javac/launcher/SourceLauncherTest.java @@ -798,6 +798,22 @@ public class SourceLauncherTest extends TestRunner { } } + @Test + public void testPrivateConstructor(Path base) throws IOException { + tb.writeJavaFiles(base, + """ + class PrivateConstructor { + private PrivateConstructor() {} + void main() {} + } + """); + testError(base.resolve("PrivateConstructor.java"), "", + """ + error: no non-private zero argument constructor found in class PrivateConstructor + remove private from existing constructor or define as: + public PrivateConstructor()"""); + } + @Test public void testAbstractClassInstanceMain(Path base) throws IOException { tb.writeJavaFiles(base, @@ -904,14 +920,6 @@ public class SourceLauncherTest extends TestRunner { } } - void checkContains(String name, String found, String expect) { - expect = expect.replace("\n", tb.lineSeparator); - out.println(name + ": " + found); - if (!found.contains(expect)) { - error("Expected output not found: " + expect); - } - } - void checkEqual(String name, List found, List expect) { out.println(name + ": " + found); tb.checkEqual(expect, found); @@ -939,7 +947,6 @@ public class SourceLauncherTest extends TestRunner { } void checkFault(String name, Throwable found, String expect) { - expect = expect.replace("\n", tb.lineSeparator); out.println(name + ": " + found); if (found == null) { error("No exception thrown; expected Fault"); @@ -947,8 +954,14 @@ public class SourceLauncherTest extends TestRunner { if (!(found instanceof Fault)) { error("Unexpected exception; expected Fault"); } - if (!(found.getMessage().equals(expect))) { - error("Unexpected detail message; expected: " + expect); + String actual = found.getMessage(); + List actualLines = actual.lines().toList(); + List expectLines = expect.lines().toList(); + if (!(actualLines.equals(expectLines))) { + error("Unexpected detail message; expected: \n" + + expect.indent(2) + + "\nactual:\n" + + actual.indent(2)); } } } From 6f2169ff6996e0629ce80455959a21947fd5de2c Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Tue, 2 Dec 2025 13:55:45 +0000 Subject: [PATCH 093/706] 8372755: Remove local suppression of VS C4146 warnings Reviewed-by: ayang --- src/hotspot/os/windows/sharedRuntimeRem.cpp | 4 +--- src/hotspot/share/runtime/atomicAccess.hpp | 2 -- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/hotspot/os/windows/sharedRuntimeRem.cpp b/src/hotspot/os/windows/sharedRuntimeRem.cpp index aae93f701ec..fbcf68a5940 100644 --- a/src/hotspot/os/windows/sharedRuntimeRem.cpp +++ b/src/hotspot/os/windows/sharedRuntimeRem.cpp @@ -50,11 +50,9 @@ double SharedRuntime::fmod_winx64(double x, double y) hx ^= sx; /* |x| */ hy &= 0x7fffffff; /* |y| */ -#pragma warning( disable : 4146 ) /* purge off exception values */ if ((hy | ly) == 0 || (hx >= 0x7ff00000) || /* y=0,or x not finite */ - ((hy | ((ly | -ly) >> 31))>0x7ff00000)) /* or y is NaN */ -#pragma warning( default : 4146 ) + ((hy | ((ly | -ly) >> 31))>0x7ff00000)) /* or y is NaN */ return (x*y) / (x*y); if (hx <= hy) { if ((hx::value || std::is_integral::value); using I = std::conditional_t::value, ptrdiff_t, D>; // Assumes two's complement integer representation. - #pragma warning(suppress: 4146) AtomicAccess::add(dest, I(-1), order); } @@ -652,7 +651,6 @@ inline D AtomicAccess::sub(D volatile* dest, I sub_value, atomic_memory_order or STATIC_ASSERT(sizeof(I) <= sizeof(AddendType)); AddendType addend = sub_value; // Assumes two's complement integer representation. - #pragma warning(suppress: 4146) // In case AddendType is not signed. return AtomicAccess::add(dest, -addend, order); } From a62296d8a0858d63a930e91168254a9927f06783 Mon Sep 17 00:00:00 2001 From: Roland Westrelin Date: Tue, 2 Dec 2025 14:00:21 +0000 Subject: [PATCH 094/706] 8371464: C2: assert(no_dead_loop) failed: dead loop detected Reviewed-by: chagedorn, dfenacci --- src/hotspot/share/opto/cfgnode.cpp | 13 +-- src/hotspot/share/opto/cfgnode.hpp | 2 +- .../compiler/c2/TestDeadLoopAtMergeMem.java | 83 +++++++++++++++++++ 3 files changed, 91 insertions(+), 7 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/c2/TestDeadLoopAtMergeMem.java diff --git a/src/hotspot/share/opto/cfgnode.cpp b/src/hotspot/share/opto/cfgnode.cpp index 0293f42d791..0598f10b880 100644 --- a/src/hotspot/share/opto/cfgnode.cpp +++ b/src/hotspot/share/opto/cfgnode.cpp @@ -326,7 +326,7 @@ bool RegionNode::is_unreachable_region(const PhaseGVN* phase) { // First, cut the simple case of fallthrough region when NONE of // region's phis references itself directly or through a data node. - if (is_possible_unsafe_loop(phase)) { + if (is_possible_unsafe_loop()) { // If we have a possible unsafe loop, check if the region node is actually unreachable from root. if (is_unreachable_from_root(phase)) { _is_unreachable_region = true; @@ -336,7 +336,7 @@ bool RegionNode::is_unreachable_region(const PhaseGVN* phase) { return false; } -bool RegionNode::is_possible_unsafe_loop(const PhaseGVN* phase) const { +bool RegionNode::is_possible_unsafe_loop() const { uint max = outcnt(); uint i; for (i = 0; i < max; i++) { @@ -634,8 +634,8 @@ Node *RegionNode::Ideal(PhaseGVN *phase, bool can_reshape) { } } else if (can_reshape && cnt == 1) { // Is it dead loop? - // If it is LoopNopde it had 2 (+1 itself) inputs and - // one of them was cut. The loop is dead if it was EntryContol. + // If it is LoopNode it had 2 (+1 itself) inputs and + // one of them was cut. The loop is dead if it was EntryControl. // Loop node may have only one input because entry path // is removed in PhaseIdealLoop::Dominators(). assert(!this->is_Loop() || cnt_orig <= 3, "Loop node should have 3 or less inputs"); @@ -1392,7 +1392,7 @@ bool PhiNode::try_clean_memory_phi(PhaseIterGVN* igvn) { } assert(is_diamond_phi() > 0, "sanity"); assert(req() == 3, "same as region"); - const Node* region = in(0); + RegionNode* region = in(0)->as_Region(); for (uint i = 1; i < 3; i++) { Node* phi_input = in(i); if (phi_input != nullptr && phi_input->is_MergeMem() && region->in(i)->outcnt() == 1) { @@ -1400,8 +1400,9 @@ bool PhiNode::try_clean_memory_phi(PhaseIterGVN* igvn) { MergeMemNode* merge_mem = phi_input->as_MergeMem(); uint j = 3 - i; Node* other_phi_input = in(j); - if (other_phi_input != nullptr && other_phi_input == merge_mem->base_memory()) { + if (other_phi_input != nullptr && other_phi_input == merge_mem->base_memory() && !is_data_loop(region, phi_input, igvn)) { // merge_mem is a successor memory to other_phi_input, and is not pinned inside the diamond, so push it out. + // Only proceed if the transformation doesn't create a data loop // This will allow the diamond to collapse completely if there are no other phis left. igvn->replace_node(this, merge_mem); return true; diff --git a/src/hotspot/share/opto/cfgnode.hpp b/src/hotspot/share/opto/cfgnode.hpp index 78ad085e03d..bc0b38e2f97 100644 --- a/src/hotspot/share/opto/cfgnode.hpp +++ b/src/hotspot/share/opto/cfgnode.hpp @@ -84,7 +84,7 @@ private: bool _is_unreachable_region; LoopStatus _loop_status; - bool is_possible_unsafe_loop(const PhaseGVN* phase) const; + bool is_possible_unsafe_loop() const; bool is_unreachable_from_root(const PhaseGVN* phase) const; public: // Node layout (parallels PhiNode): diff --git a/test/hotspot/jtreg/compiler/c2/TestDeadLoopAtMergeMem.java b/test/hotspot/jtreg/compiler/c2/TestDeadLoopAtMergeMem.java new file mode 100644 index 00000000000..5c4dcc76a76 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/TestDeadLoopAtMergeMem.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2025 IBM Corporation. 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 8371464 + * @summary C2: assert(no_dead_loop) failed: dead loop detected + * @run main/othervm -Xcomp -XX:CompileOnly=TestDeadLoopAtMergeMem::test TestDeadLoopAtMergeMem + * @run main TestDeadLoopAtMergeMem + */ + +public class TestDeadLoopAtMergeMem { + static final int N = 400; + static long instanceCount; + boolean bFld; + float fArrFld[]; + static int iArrFld[] = new int[N]; + long vMeth_check_sum; + + public static void main(String[] strArr) { + TestDeadLoopAtMergeMem r = new TestDeadLoopAtMergeMem(); + for (int i = 0; i < 1000; i++) { + r.test((short) 0, instanceCount); + } + } + + void test(short s, long l) { + int i11 = 6, i12, i13 = 6, i14 = 2; + byte byArr2[] = new byte[N]; + init(byArr2, (byte) 4); + helper(66.118169, i11); + for (i12 = 3; i12 < 23; i12++) { + if (bFld) { + instanceCount = 5; + } else if (bFld) { + fArrFld[i12] = s; + do { + try { + i11 = i13 / i12 % i12; + } catch (ArithmeticException a_e) { + } + } while (i14 < 8); + } + } + for (int i15 : iArrFld) { + try { + i11 = 1 / i15; + } catch (ArithmeticException a_e) { + } + } + vMeth_check_sum += i11; + } + + void helper(double d, int i) { + int i1[] = new int[N]; + } + + public static void init(byte[] a, byte seed) { + for (int j = 0; j < a.length; j++) { + a[j] = (byte) ((j % 2 == 0) ? seed + j : seed - j); + } + } +} From ca4ae8063edddda36fafafd06b9b1a88ffbf9d2e Mon Sep 17 00:00:00 2001 From: Quan Anh Mai Date: Tue, 2 Dec 2025 15:44:19 +0000 Subject: [PATCH 095/706] 8371964: C2 compilation asserts with "Unexpected load/store size" Reviewed-by: chagedorn, epeter --- src/hotspot/share/opto/vectornode.cpp | 20 +++++++++++++++++-- .../arraycopy/TestArrayCopyDisjoint.java | 7 +++++-- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/src/hotspot/share/opto/vectornode.cpp b/src/hotspot/share/opto/vectornode.cpp index a49f3d24fd4..57b94205e5e 100644 --- a/src/hotspot/share/opto/vectornode.cpp +++ b/src/hotspot/share/opto/vectornode.cpp @@ -22,6 +22,8 @@ */ #include "memory/allocation.inline.hpp" +#include "opto/c2_globals.hpp" +#include "opto/compile.hpp" #include "opto/connode.hpp" #include "opto/convertnode.hpp" #include "opto/mulnode.hpp" @@ -1145,7 +1147,14 @@ Node* LoadVectorMaskedNode::Ideal(PhaseGVN* phase, bool can_reshape) { if (ty && ty->is_con()) { BasicType mask_bt = Matcher::vector_element_basic_type(in(3)); int load_sz = type2aelembytes(mask_bt) * ty->get_con(); - assert(load_sz <= MaxVectorSize, "Unexpected load size"); + if (load_sz > MaxVectorSize) { + // After loop opts, cast nodes are aggressively removed, if the input is then transformed + // into a constant that is outside the range of the removed cast, we may encounter it here. + // This should be a dead node then. + assert(Compile::current()->post_loop_opts_phase(), "Unexpected load size"); + return phase->C->top(); + } + if (load_sz == MaxVectorSize) { Node* ctr = in(MemNode::Control); Node* mem = in(MemNode::Memory); @@ -1164,7 +1173,14 @@ Node* StoreVectorMaskedNode::Ideal(PhaseGVN* phase, bool can_reshape) { if (ty && ty->is_con()) { BasicType mask_bt = Matcher::vector_element_basic_type(in(4)); int load_sz = type2aelembytes(mask_bt) * ty->get_con(); - assert(load_sz <= MaxVectorSize, "Unexpected store size"); + if (load_sz > MaxVectorSize) { + // After loop opts, cast nodes are aggressively removed, if the input is then transformed + // into a constant that is outside the range of the removed cast, we may encounter it here. + // This should be a dead node then. + assert(Compile::current()->post_loop_opts_phase(), "Unexpected store size"); + return phase->C->top(); + } + if (load_sz == MaxVectorSize) { Node* ctr = in(MemNode::Control); Node* mem = in(MemNode::Memory); diff --git a/test/hotspot/jtreg/compiler/arraycopy/TestArrayCopyDisjoint.java b/test/hotspot/jtreg/compiler/arraycopy/TestArrayCopyDisjoint.java index 162ba20048d..73b1af90548 100644 --- a/test/hotspot/jtreg/compiler/arraycopy/TestArrayCopyDisjoint.java +++ b/test/hotspot/jtreg/compiler/arraycopy/TestArrayCopyDisjoint.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, 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,7 @@ import java.util.Random; /** * @test - * @bug 8251871 8285301 + * @bug 8251871 8285301 8371964 * @summary Optimize arrayCopy using AVX-512 masked instructions. * * @run main/othervm/timeout=600 -XX:-TieredCompilation -Xbatch -XX:+IgnoreUnrecognizedVMOptions @@ -52,6 +52,9 @@ import java.util.Random; * compiler.arraycopy.TestArrayCopyDisjoint * @run main/othervm/timeout=600 -XX:-TieredCompilation -Xbatch -XX:+UnlockExperimentalVMOptions -XX:+AlwaysAtomicAccesses * compiler.arraycopy.TestArrayCopyDisjoint + * @run main/othervm/timeout=600 -XX:-TieredCompilation -Xbatch -XX:+IgnoreUnrecognizedVMOptions + * -XX:+UnlockDiagnosticVMOptions -XX:UseAVX=3 -XX:MaxVectorSize=32 -XX:ArrayOperationPartialInlineSize=32 -XX:+StressIGVN + * compiler.arraycopy.TestArrayCopyDisjoint * */ From 8d5a37b060dd0ecf31f71dfe82ca4a565bc7f6d9 Mon Sep 17 00:00:00 2001 From: Amit Kumar Date: Tue, 2 Dec 2025 16:09:10 +0000 Subject: [PATCH 096/706] 8371188: [s390x] Un-ProblemList TestUnreachableInnerLoop.java Reviewed-by: aph, phubner --- test/hotspot/jtreg/ProblemList.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index a51e8aef5ee..f379f57a8e5 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -49,7 +49,6 @@ compiler/cpuflags/TestAESIntrinsicsOnSupportedConfig.java 8190680 generic-all compiler/runtime/Test8168712.java#with-dtrace 8211769,8211771 generic-ppc64,generic-ppc64le,linux-s390x compiler/runtime/Test8168712.java#without-dtrace 8211769,8211771 generic-ppc64,generic-ppc64le,linux-s390x -compiler/loopopts/TestUnreachableInnerLoop.java 8288981 linux-s390x compiler/c2/Test8004741.java 8235801 generic-all compiler/c2/irTests/TestDuplicateBackedge.java 8318904 generic-all From 37d8e05eccc959b5b5e04b3da848f7de9220b00c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Walln=C3=B6fer?= Date: Tue, 2 Dec 2025 16:22:47 +0000 Subject: [PATCH 097/706] 8372708: Javadoc ignores "-locale" and uses default locale for all messages and texts Reviewed-by: liach --- .../html/resources/standard_en.properties | 28 +++++ .../toolkit/resources/doclets_en.properties | 28 +++++ .../TestSupportedLocales.java | 106 ++++++++++++++++++ 3 files changed, 162 insertions(+) create mode 100644 src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard_en.properties create mode 100644 src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets_en.properties create mode 100644 test/langtools/jdk/javadoc/tool/testLocaleOption/TestSupportedLocales.java diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard_en.properties b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard_en.properties new file mode 100644 index 00000000000..e1312e77aa4 --- /dev/null +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard_en.properties @@ -0,0 +1,28 @@ +# +# Copyright (c) 2025, 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. +# + +# Empty resource bundle to be used with English default bundle as parent. +# This is necessary to make English resources available on systems using +# one of the supported non-English locales as default locale. diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets_en.properties b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets_en.properties new file mode 100644 index 00000000000..e1312e77aa4 --- /dev/null +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets_en.properties @@ -0,0 +1,28 @@ +# +# Copyright (c) 2025, 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. +# + +# Empty resource bundle to be used with English default bundle as parent. +# This is necessary to make English resources available on systems using +# one of the supported non-English locales as default locale. diff --git a/test/langtools/jdk/javadoc/tool/testLocaleOption/TestSupportedLocales.java b/test/langtools/jdk/javadoc/tool/testLocaleOption/TestSupportedLocales.java new file mode 100644 index 00000000000..6d4e24f0c3a --- /dev/null +++ b/test/langtools/jdk/javadoc/tool/testLocaleOption/TestSupportedLocales.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2025, 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 8372708 + * @summary Javadoc ignores "-locale" and uses default locale for all messages and texts + * @library /tools/lib ../../lib + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * jdk.javadoc/jdk.javadoc.internal.tool + * @build toolbox.ToolBox javadoc.tester.* + * @run main TestSupportedLocales + */ + +import java.io.IOException; +import java.nio.file.Path; +import java.util.Locale; + +import javadoc.tester.JavadocTester; +import toolbox.ToolBox; + +public class TestSupportedLocales extends JavadocTester { + + public static void main(String... args) throws Exception { + var tester = new TestSupportedLocales(); + tester.runTests(); + } + + private final ToolBox tb = new ToolBox(); + + // A locale with an associated output message + record LocalizedOutput(Locale locale, String message) {} + + // Console messages are determined by the system default locale + private final LocalizedOutput[] consoleOutput = new LocalizedOutput[] { + new LocalizedOutput(Locale.CHINA, "\u6b63\u5728\u6784\u9020 Javadoc \u4fe1\u606f..."), + new LocalizedOutput(Locale.GERMANY, "Javadoc-Informationen werden erstellt..."), + new LocalizedOutput(Locale.JAPAN, "Javadoc\u60c5\u5831\u3092\u69cb\u7bc9\u3057\u3066\u3044\u307e\u3059..."), + new LocalizedOutput(Locale.US, "Constructing Javadoc information..."), + }; + + // Documentation messages are determined by the -locale option + private final LocalizedOutput[] documentationOutput = new LocalizedOutput[] { + new LocalizedOutput(Locale.CHINA, "\u7c7b\u548c\u63a5\u53e3"), + new LocalizedOutput(Locale.GERMANY, "Klassen und Schnittstellen"), + new LocalizedOutput(Locale.JAPAN, "\u30af\u30e9\u30b9\u3068\u30a4\u30f3\u30bf\u30d5\u30a7\u30fc\u30b9"), + new LocalizedOutput(Locale.US, "Classes and Interfaces"), + }; + + // Test all combinations of system and documentation locales + @Test + public void testSupportedLocales(Path base) throws Exception { + var src = base.resolve("src"); + initSource(src); + for (var console : consoleOutput) { + for (var documentation : documentationOutput) { + test(base, console, documentation); + } + } + } + + void test(Path base, LocalizedOutput console, LocalizedOutput documentation) throws Exception { + var src = base.resolve("src"); + var out = base.resolve(console.locale + "-" + documentation.locale); + Locale.setDefault(console.locale); + javadoc("-d", out.toString(), + "-locale", documentation.locale.toString(), + "--source-path", src.toString(), + "p"); + checkExit(Exit.OK); + checkOutput(Output.OUT, true, console.message); + checkOutput("p/package-summary.html", true, documentation.message); + } + + private void initSource(Path src) throws IOException { + tb.writeJavaFiles(src, """ + package p; + /** + * A class. + */ + public class C { + private C() { } + }"""); + } +} From 153c567a4d3a537277a8c599142511aa4f4f3ae3 Mon Sep 17 00:00:00 2001 From: Leonid Mesnik Date: Tue, 2 Dec 2025 18:06:43 +0000 Subject: [PATCH 098/706] 8370905: Update vm.defmeth tests to use virtual threads Reviewed-by: vlivanov, coleenp, pchilanomate --- .../vm/runtime/defmeth/StressTest.java | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/test/hotspot/jtreg/vmTestbase/vm/runtime/defmeth/StressTest.java b/test/hotspot/jtreg/vmTestbase/vm/runtime/defmeth/StressTest.java index e8fe73cb48b..4106f12587b 100644 --- a/test/hotspot/jtreg/vmTestbase/vm/runtime/defmeth/StressTest.java +++ b/test/hotspot/jtreg/vmTestbase/vm/runtime/defmeth/StressTest.java @@ -44,6 +44,7 @@ import java.util.Arrays; import java.util.List; import java.util.Random; +import jdk.test.lib.thread.TestThreadFactory; import nsk.share.TestFailure; import nsk.share.test.StressOptions; import nsk.share.test.Stresser; @@ -82,16 +83,18 @@ public class StressTest implements Runnable { @Option(name="ignoreTestFailures", default_value="false", description="ignore failures of the executed tests") private boolean ignoreTestFailures; - class Worker extends Thread { + class Worker implements Runnable { private final Random rand; private volatile DefMethTest failedTest; private Throwable reason; private volatile long executedTests = 0; - public Worker(String id, long seed) { - setName(id); - this.rand = new Random(seed); + private final Thread thread; + + Worker(String id, long seed) { + this.rand = new Random(seed); + this.thread = TestThreadFactory.newThread(this, id); } @Override @@ -247,13 +250,13 @@ public class StressTest implements Runnable { } for (Worker worker : workers) { - worker.start(); + worker.thread.start(); } } private void interruptWorkers() { for (Worker worker : workers) { - worker.interrupt(); + worker.thread.interrupt(); } } @@ -261,14 +264,14 @@ public class StressTest implements Runnable { boolean isFailed = false; for (Worker worker : workers) { - while (worker.isAlive()) { + while (worker.thread.isAlive()) { try { - worker.join(); + worker.thread.join(); } catch (InterruptedException e) {} } System.out.printf("%s: %s (executed: %d)\n", - worker.getName(), + worker.thread.getName(), worker.isFailed() ? "FAILED: " + worker.getFailedTest() : "PASSED", worker.getExecutedTests()); @@ -288,7 +291,7 @@ public class StressTest implements Runnable { private boolean workersAlive() { for (Worker worker : workers) { - if (!worker.isAlive()) { + if (!worker.thread.isAlive()) { return false; } } From ac0e6af8f90ba77375b2841a5c8aa05743884a1e Mon Sep 17 00:00:00 2001 From: Phil Race Date: Tue, 2 Dec 2025 18:16:49 +0000 Subject: [PATCH 099/706] 6185110: Undefined behaviour of SampleModel for width, height < 0 Reviewed-by: psadhukhan --- .../java/awt/image/BandedSampleModel.java | 196 ++++------ .../java/awt/image/ComponentSampleModel.java | 200 ++++------- .../image/MultiPixelPackedSampleModel.java | 18 +- .../classes/java/awt/image/SampleModel.java | 171 ++++----- .../image/SinglePixelPackedSampleModel.java | 144 +++----- .../SampleModelGetSamplesAndPixelsTest.java | 337 ++++++++++++++++++ 6 files changed, 616 insertions(+), 450 deletions(-) create mode 100644 test/jdk/java/awt/image/SampleModelGetSamplesAndPixelsTest.java diff --git a/src/java.desktop/share/classes/java/awt/image/BandedSampleModel.java b/src/java.desktop/share/classes/java/awt/image/BandedSampleModel.java index bad9abc6130..229c8a20d35 100644 --- a/src/java.desktop/share/classes/java/awt/image/BandedSampleModel.java +++ b/src/java.desktop/share/classes/java/awt/image/BandedSampleModel.java @@ -293,6 +293,9 @@ public final class BandedSampleModel extends ComponentSampleModel * @param data The DataBuffer containing the image data. * @return the data for the specified pixel. * @see #setDataElements(int, int, Object, DataBuffer) + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates are + * not in bounds, or if {@code obj} is too small to hold the output. */ public Object getDataElements(int x, int y, Object obj, DataBuffer data) { if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { @@ -401,15 +404,10 @@ public final class BandedSampleModel extends ComponentSampleModel } /** - * Returns all samples for the specified pixel in an int array. - * ArrayIndexOutOfBoundsException may be thrown if the coordinates are - * not in bounds. - * @param x The X coordinate of the pixel location - * @param y The Y coordinate of the pixel location - * @param iArray If non-null, returns the samples in this array - * @param data The DataBuffer containing the image data - * @return the samples for the specified pixel. - * @see #setPixel(int, int, int[], DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates are + * not in bounds, or if {@code iArray} is too small to hold the output. */ public int[] getPixel(int x, int y, int[] iArray, DataBuffer data) { if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { @@ -434,26 +432,19 @@ public final class BandedSampleModel extends ComponentSampleModel } /** - * Returns all samples for the specified rectangle of pixels in - * an int array, one sample per data array element. - * ArrayIndexOutOfBoundsException may be thrown if the coordinates are - * not in bounds. - * @param x The X coordinate of the upper left pixel location - * @param y The Y coordinate of the upper left pixel location - * @param w The width of the pixel rectangle - * @param h The height of the pixel rectangle - * @param iArray If non-null, returns the samples in this array - * @param data The DataBuffer containing the image data - * @return the samples for the pixels within the specified region. - * @see #setPixels(int, int, int, int, int[], DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates are + * not in bounds, or {@code w} or {@code h} is negative. + * or if {@code iArray} is too small to hold the output. */ public int[] getPixels(int x, int y, int w, int h, int[] iArray, DataBuffer data) { int x1 = x + w; int y1 = y + h; - if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width || - y < 0 || y >= height || h > height || y1 < 0 || y1 > height) + if (x < 0 || w < 0 || x >= width || w > width || x1 < 0 || x1 > width || + y < 0 || h < 0 || y >= height || h > height || y1 < 0 || y1 > height) { throw new ArrayIndexOutOfBoundsException ("Coordinate out of bounds!"); @@ -484,16 +475,10 @@ public final class BandedSampleModel extends ComponentSampleModel } /** - * Returns as int the sample in a specified band for the pixel - * located at (x,y). - * ArrayIndexOutOfBoundsException may be thrown if the coordinates are - * not in bounds. - * @param x The X coordinate of the pixel location - * @param y The Y coordinate of the pixel location - * @param b The band to return - * @param data The DataBuffer containing the image data - * @return the sample in the specified band for the specified pixel. - * @see #setSample(int, int, int, int, DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * the band index are not in bounds. */ public int getSample(int x, int y, int b, DataBuffer data) { // Bounds check for 'b' will be performed automatically @@ -508,16 +493,10 @@ public final class BandedSampleModel extends ComponentSampleModel } /** - * Returns the sample in a specified band - * for the pixel located at (x,y) as a float. - * ArrayIndexOutOfBoundsException may be thrown if the coordinates are - * not in bounds. - * @param x The X coordinate of the pixel location - * @param y The Y coordinate of the pixel location - * @param b The band to return - * @param data The DataBuffer containing the image data - * @return a float value that represents the sample in the specified - * band for the specified pixel. + * {@inheritDoc} + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * the band index are not in bounds. */ public float getSampleFloat(int x, int y, int b, DataBuffer data) { // Bounds check for 'b' will be performed automatically @@ -532,16 +511,10 @@ public final class BandedSampleModel extends ComponentSampleModel } /** - * Returns the sample in a specified band - * for a pixel located at (x,y) as a double. - * ArrayIndexOutOfBoundsException may be thrown if the coordinates are - * not in bounds. - * @param x The X coordinate of the pixel location - * @param y The Y coordinate of the pixel location - * @param b The band to return - * @param data The DataBuffer containing the image data - * @return a double value that represents the sample in the specified - * band for the specified pixel. + * {@inheritDoc} + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * the band index are not in bounds. */ public double getSampleDouble(int x, int y, int b, DataBuffer data) { // Bounds check for 'b' will be performed automatically @@ -556,25 +529,16 @@ public final class BandedSampleModel extends ComponentSampleModel } /** - * Returns the samples in a specified band for the specified rectangle - * of pixels in an int array, one sample per data array element. - * ArrayIndexOutOfBoundsException may be thrown if the coordinates are - * not in bounds. - * @param x The X coordinate of the upper left pixel location - * @param y The Y coordinate of the upper left pixel location - * @param w The width of the pixel rectangle - * @param h The height of the pixel rectangle - * @param b The band to return - * @param iArray If non-null, returns the samples in this array - * @param data The DataBuffer containing the image data - * @return the samples in the specified band for the pixels within - * the specified region. - * @see #setSamples(int, int, int, int, int, int[], DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * band index are not in bounds, or {@code w} or {@code h} is negative, + * or if {@code iArray} is too small to hold the output. */ public int[] getSamples(int x, int y, int w, int h, int b, int[] iArray, DataBuffer data) { // Bounds check for 'b' will be performed automatically - if ((x < 0) || (y < 0) || (x + w > width) || (y + h > height)) { + if ((x < 0) || (y < 0) || (w < 0) || (h < 0) || (x + w > width) || (y + h > height)) { throw new ArrayIndexOutOfBoundsException ("Coordinate out of bounds!"); } @@ -633,6 +597,9 @@ public final class BandedSampleModel extends ComponentSampleModel * object * @param data The DataBuffer containing the image data * @see #getDataElements(int, int, Object, DataBuffer) + * @throws NullPointerException if {@code obj} or {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates are + * not in bounds, or if {@code obj} is too small to hold the input. */ public void setDataElements(int x, int y, Object obj, DataBuffer data) { if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { @@ -700,14 +667,10 @@ public final class BandedSampleModel extends ComponentSampleModel } /** - * Sets a pixel in the DataBuffer using an int array of samples for input. - * ArrayIndexOutOfBoundsException may be thrown if the coordinates are - * not in bounds. - * @param x The X coordinate of the pixel location - * @param y The Y coordinate of the pixel location - * @param iArray The input samples in an int array - * @param data The DataBuffer containing the image data - * @see #getPixel(int, int, int[], DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code iArray} or {code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates are + * not in bounds, or if {@code iArray} is too small to hold the input. */ public void setPixel(int x, int y, int[] iArray, DataBuffer data) { if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { @@ -722,25 +685,19 @@ public final class BandedSampleModel extends ComponentSampleModel } /** - * Sets all samples for a rectangle of pixels from an int array containing - * one sample per array element. - * ArrayIndexOutOfBoundsException may be thrown if the coordinates are - * not in bounds. - * @param x The X coordinate of the upper left pixel location - * @param y The Y coordinate of the upper left pixel location - * @param w The width of the pixel rectangle - * @param h The height of the pixel rectangle - * @param iArray The input samples in an int array - * @param data The DataBuffer containing the image data - * @see #getPixels(int, int, int, int, int[], DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code iArray} or {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates are + * not in bounds, or {@code w} or {@code h} is negative. + * or if {@code iArray} is too small to hold the input. */ public void setPixels(int x, int y, int w, int h, int[] iArray, DataBuffer data) { int x1 = x + w; int y1 = y + h; - if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width || - y < 0 || y >= height || h > height || y1 < 0 || y1 > height) + if (x < 0 || w < 0 || x >= width || w > width || x1 < 0 || x1 > width || + y < 0 || h < 0 || y >= height || h > height || y1 < 0 || y1 > height) { throw new ArrayIndexOutOfBoundsException ("Coordinate out of bounds!"); @@ -763,16 +720,10 @@ public final class BandedSampleModel extends ComponentSampleModel } /** - * Sets a sample in the specified band for the pixel located at (x,y) - * in the DataBuffer using an int for input. - * ArrayIndexOutOfBoundsException may be thrown if the coordinates are - * not in bounds. - * @param x The X coordinate of the pixel location - * @param y The Y coordinate of the pixel location - * @param b The band to set - * @param s The input sample as an int - * @param data The DataBuffer containing the image data - * @see #getSample(int, int, int, DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * the band index are not in bounds. */ public void setSample(int x, int y, int b, int s, DataBuffer data) { @@ -786,16 +737,10 @@ public final class BandedSampleModel extends ComponentSampleModel } /** - * Sets a sample in the specified band for the pixel located at (x,y) - * in the DataBuffer using a float for input. - * ArrayIndexOutOfBoundsException may be thrown if the coordinates are - * not in bounds. - * @param x The X coordinate of the pixel location - * @param y The Y coordinate of the pixel location - * @param b The band to set - * @param s The input sample as a float - * @param data The DataBuffer containing the image data - * @see #getSample(int, int, int, DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * the band index are not in bounds. */ public void setSample(int x, int y, int b, float s , @@ -810,16 +755,10 @@ public final class BandedSampleModel extends ComponentSampleModel } /** - * Sets a sample in the specified band for the pixel located at (x,y) - * in the DataBuffer using a double for input. - * ArrayIndexOutOfBoundsException may be thrown if the coordinates are - * not in bounds. - * @param x The X coordinate of the pixel location - * @param y The Y coordinate of the pixel location - * @param b The band to set - * @param s The input sample as a double - * @param data The DataBuffer containing the image data - * @see #getSample(int, int, int, DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * the band index are not in bounds. */ public void setSample(int x, int y, int b, double s, @@ -834,23 +773,16 @@ public final class BandedSampleModel extends ComponentSampleModel } /** - * Sets the samples in the specified band for the specified rectangle - * of pixels from an int array containing one sample per data array element. - * ArrayIndexOutOfBoundsException may be thrown if the coordinates are - * not in bounds. - * @param x The X coordinate of the upper left pixel location - * @param y The Y coordinate of the upper left pixel location - * @param w The width of the pixel rectangle - * @param h The height of the pixel rectangle - * @param b The band to set - * @param iArray The input sample array - * @param data The DataBuffer containing the image data - * @see #getSamples(int, int, int, int, int, int[], DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code iArray} or {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * band index are not in bounds, or {@code w} or {@code h} is negative, + * or if {@code iArray} is too small to hold the input. */ public void setSamples(int x, int y, int w, int h, int b, int[] iArray, DataBuffer data) { // Bounds check for 'b' will be performed automatically - if ((x < 0) || (y < 0) || (x + w > width) || (y + h > height)) { + if ((x < 0) || (y < 0) || (w < 0) || (h < 0) || (x + w > width) || (y + h > height)) { throw new ArrayIndexOutOfBoundsException ("Coordinate out of bounds!"); } diff --git a/src/java.desktop/share/classes/java/awt/image/ComponentSampleModel.java b/src/java.desktop/share/classes/java/awt/image/ComponentSampleModel.java index 7a3d67c7e6e..89a72b18dea 100644 --- a/src/java.desktop/share/classes/java/awt/image/ComponentSampleModel.java +++ b/src/java.desktop/share/classes/java/awt/image/ComponentSampleModel.java @@ -600,7 +600,7 @@ public class ComponentSampleModel extends SampleModel * @return the data of the specified pixel * @see #setDataElements(int, int, Object, DataBuffer) * - * @throws NullPointerException if data is null. + * @throws NullPointerException if {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates are * not in bounds, or if obj is too small to hold the output. */ @@ -707,20 +707,10 @@ public class ComponentSampleModel extends SampleModel } /** - * Returns all samples for the specified pixel in an int array, - * one sample per array element. - * An {@code ArrayIndexOutOfBoundsException} might be thrown if - * the coordinates are not in bounds. - * @param x the X coordinate of the pixel location - * @param y the Y coordinate of the pixel location - * @param iArray If non-null, returns the samples in this array - * @param data The DataBuffer containing the image data - * @return the samples of the specified pixel. - * @see #setPixel(int, int, int[], DataBuffer) - * - * @throws NullPointerException if data is null. + * {@inheritDoc} + * @throws NullPointerException if {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates are - * not in bounds, or if iArray is too small to hold the output. + * not in bounds, or if {@code iArray} is too small to hold the output. */ public int[] getPixel(int x, int y, int[] iArray, DataBuffer data) { if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { @@ -742,26 +732,19 @@ public class ComponentSampleModel extends SampleModel } /** - * Returns all samples for the specified rectangle of pixels in - * an int array, one sample per array element. - * An {@code ArrayIndexOutOfBoundsException} might be thrown if - * the coordinates are not in bounds. - * @param x The X coordinate of the upper left pixel location - * @param y The Y coordinate of the upper left pixel location - * @param w The width of the pixel rectangle - * @param h The height of the pixel rectangle - * @param iArray If non-null, returns the samples in this array - * @param data The DataBuffer containing the image data - * @return the samples of the pixels within the specified region. - * @see #setPixels(int, int, int, int, int[], DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates are + * not in bounds, or {@code w} or {@code h} is negative + * or if {@code iArray} is too small to hold the output. */ public int[] getPixels(int x, int y, int w, int h, int[] iArray, DataBuffer data) { int x1 = x + w; int y1 = y + h; - if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width || - y < 0 || y >= height || y > height || y1 < 0 || y1 > height) + if (x < 0 || (w < 0) || x >= width || w > width || x1 < 0 || x1 > width || + y < 0 || (h < 0) || y >= height || y > height || y1 < 0 || y1 > height) { throw new ArrayIndexOutOfBoundsException ("Coordinate out of bounds!"); @@ -790,16 +773,10 @@ public class ComponentSampleModel extends SampleModel } /** - * Returns as int the sample in a specified band for the pixel - * located at (x,y). - * An {@code ArrayIndexOutOfBoundsException} might be thrown if - * the coordinates are not in bounds. - * @param x the X coordinate of the pixel location - * @param y the Y coordinate of the pixel location - * @param b the band to return - * @param data the {@code DataBuffer} containing the image data - * @return the sample in a specified band for the specified pixel - * @see #setSample(int, int, int, int, DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * the band index are not in bounds. */ public int getSample(int x, int y, int b, DataBuffer data) { // Bounds check for 'b' will be performed automatically @@ -814,16 +791,10 @@ public class ComponentSampleModel extends SampleModel } /** - * Returns the sample in a specified band - * for the pixel located at (x,y) as a float. - * An {@code ArrayIndexOutOfBoundsException} might be - * thrown if the coordinates are not in bounds. - * @param x The X coordinate of the pixel location - * @param y The Y coordinate of the pixel location - * @param b The band to return - * @param data The DataBuffer containing the image data - * @return a float value representing the sample in the specified - * band for the specified pixel. + * {@inheritDoc} + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * the band index are not in bounds. */ public float getSampleFloat(int x, int y, int b, DataBuffer data) { // Bounds check for 'b' will be performed automatically @@ -837,18 +808,11 @@ public class ComponentSampleModel extends SampleModel bandOffsets[b]); return sample; } - /** - * Returns the sample in a specified band - * for a pixel located at (x,y) as a double. - * An {@code ArrayIndexOutOfBoundsException} might be - * thrown if the coordinates are not in bounds. - * @param x The X coordinate of the pixel location - * @param y The Y coordinate of the pixel location - * @param b The band to return - * @param data The DataBuffer containing the image data - * @return a double value representing the sample in the specified - * band for the specified pixel. + * {@inheritDoc} + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * the band index are not in bounds. */ public double getSampleDouble(int x, int y, int b, DataBuffer data) { // Bounds check for 'b' will be performed automatically @@ -864,25 +828,16 @@ public class ComponentSampleModel extends SampleModel } /** - * Returns the samples in a specified band for the specified rectangle - * of pixels in an int array, one sample per data array element. - * An {@code ArrayIndexOutOfBoundsException} might be thrown if - * the coordinates are not in bounds. - * @param x The X coordinate of the upper left pixel location - * @param y The Y coordinate of the upper left pixel location - * @param w the width of the pixel rectangle - * @param h the height of the pixel rectangle - * @param b the band to return - * @param iArray if non-{@code null}, returns the samples - * in this array - * @param data the {@code DataBuffer} containing the image data - * @return the samples in the specified band of the specified pixel - * @see #setSamples(int, int, int, int, int, int[], DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * band index are not in bounds, or {@code w} or {@code h} is negative, + * or if {@code iArray} is too small to hold the output. */ public int[] getSamples(int x, int y, int w, int h, int b, int[] iArray, DataBuffer data) { // Bounds check for 'b' will be performed automatically - if ((x < 0) || (y < 0) || (x + w > width) || (y + h > height)) { + if ((x < 0) || (y < 0) || (w < 0) || ( h < 0) || (x + w > width) || (y + h > height)) { throw new ArrayIndexOutOfBoundsException ("Coordinate out of bounds!"); } @@ -943,6 +898,9 @@ public class ComponentSampleModel extends SampleModel * @param obj a primitive array containing pixel data * @param data the DataBuffer containing the image data * @see #getDataElements(int, int, Object, DataBuffer) + * @throws NullPointerException if {@code obj} or {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates are + * not in bounds, or if obj is too small to hold the input. */ public void setDataElements(int x, int y, Object obj, DataBuffer data) { if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { @@ -1011,15 +969,10 @@ public class ComponentSampleModel extends SampleModel } /** - * Sets a pixel in the {@code DataBuffer} using an int array of - * samples for input. An {@code ArrayIndexOutOfBoundsException} - * might be thrown if the coordinates are - * not in bounds. - * @param x The X coordinate of the pixel location - * @param y The Y coordinate of the pixel location - * @param iArray The input samples in an int array - * @param data The DataBuffer containing the image data - * @see #getPixel(int, int, int[], DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code iArray} or {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates are + * not in bounds, or if {@code iArray} is too small to hold the input. */ public void setPixel(int x, int y, int[] iArray, DataBuffer data) { if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { @@ -1034,25 +987,19 @@ public class ComponentSampleModel extends SampleModel } /** - * Sets all samples for a rectangle of pixels from an int array containing - * one sample per array element. - * An {@code ArrayIndexOutOfBoundsException} might be thrown if the - * coordinates are not in bounds. - * @param x The X coordinate of the upper left pixel location - * @param y The Y coordinate of the upper left pixel location - * @param w The width of the pixel rectangle - * @param h The height of the pixel rectangle - * @param iArray The input samples in an int array - * @param data The DataBuffer containing the image data - * @see #getPixels(int, int, int, int, int[], DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code iArray} or {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates are + * not in bounds, or {@code w} or {@code h} is negative + * or if {@code iArray} is too small to hold the input. */ public void setPixels(int x, int y, int w, int h, int[] iArray, DataBuffer data) { int x1 = x + w; int y1 = y + h; - if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width || - y < 0 || y >= height || h > height || y1 < 0 || y1 > height) + if (x < 0 || w < 0 || x >= width || w > width || x1 < 0 || x1 > width || + y < 0 || h < 0 || y >= height || h > height || y1 < 0 || y1 > height) { throw new ArrayIndexOutOfBoundsException ("Coordinate out of bounds!"); @@ -1075,16 +1022,10 @@ public class ComponentSampleModel extends SampleModel } /** - * Sets a sample in the specified band for the pixel located at (x,y) - * in the {@code DataBuffer} using an int for input. - * An {@code ArrayIndexOutOfBoundsException} might be thrown if the - * coordinates are not in bounds. - * @param x The X coordinate of the pixel location - * @param y The Y coordinate of the pixel location - * @param b the band to set - * @param s the input sample as an int - * @param data the DataBuffer containing the image data - * @see #getSample(int, int, int, DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * the band index are not in bounds. */ public void setSample(int x, int y, int b, int s, DataBuffer data) { @@ -1098,16 +1039,10 @@ public class ComponentSampleModel extends SampleModel } /** - * Sets a sample in the specified band for the pixel located at (x,y) - * in the {@code DataBuffer} using a float for input. - * An {@code ArrayIndexOutOfBoundsException} might be thrown if - * the coordinates are not in bounds. - * @param x The X coordinate of the pixel location - * @param y The Y coordinate of the pixel location - * @param b The band to set - * @param s The input sample as a float - * @param data The DataBuffer containing the image data - * @see #getSample(int, int, int, DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * the band index are not in bounds. */ public void setSample(int x, int y, int b, float s , @@ -1123,16 +1058,10 @@ public class ComponentSampleModel extends SampleModel } /** - * Sets a sample in the specified band for the pixel located at (x,y) - * in the {@code DataBuffer} using a double for input. - * An {@code ArrayIndexOutOfBoundsException} might be thrown if - * the coordinates are not in bounds. - * @param x The X coordinate of the pixel location - * @param y The Y coordinate of the pixel location - * @param b The band to set - * @param s The input sample as a double - * @param data The DataBuffer containing the image data - * @see #getSample(int, int, int, DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * the band index are not in bounds. */ public void setSample(int x, int y, int b, double s, @@ -1148,23 +1077,16 @@ public class ComponentSampleModel extends SampleModel } /** - * Sets the samples in the specified band for the specified rectangle - * of pixels from an int array containing one sample per data array element. - * An {@code ArrayIndexOutOfBoundsException} might be thrown if the - * coordinates are not in bounds. - * @param x The X coordinate of the upper left pixel location - * @param y The Y coordinate of the upper left pixel location - * @param w The width of the pixel rectangle - * @param h The height of the pixel rectangle - * @param b The band to set - * @param iArray The input samples in an int array - * @param data The DataBuffer containing the image data - * @see #getSamples(int, int, int, int, int, int[], DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code iArray} or {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * band index are not in bounds, or {@code w} or {@code h} is negative, + * or if {@code iArray} is too small to hold the input. */ public void setSamples(int x, int y, int w, int h, int b, int[] iArray, DataBuffer data) { // Bounds check for 'b' will be performed automatically - if ((x < 0) || (y < 0) || (x + w > width) || (y + h > height)) { + if ((x < 0) || (y < 0) || (w < 0) || (h < 0) || (x + w > width) || (y + h > height)) { throw new ArrayIndexOutOfBoundsException ("Coordinate out of bounds!"); } diff --git a/src/java.desktop/share/classes/java/awt/image/MultiPixelPackedSampleModel.java b/src/java.desktop/share/classes/java/awt/image/MultiPixelPackedSampleModel.java index 9254d9fa717..e40da604887 100644 --- a/src/java.desktop/share/classes/java/awt/image/MultiPixelPackedSampleModel.java +++ b/src/java.desktop/share/classes/java/awt/image/MultiPixelPackedSampleModel.java @@ -343,7 +343,7 @@ public class MultiPixelPackedSampleModel extends SampleModel * coordinates are not in bounds. * @param x the X coordinate of the specified pixel * @param y the Y coordinate of the specified pixel - * @param b the band to return, which is assumed to be 0 + * @param b the band to return, which must be 0 * @param data the {@code DataBuffer} containing the image * data * @return the specified band containing the sample of the specified @@ -374,7 +374,7 @@ public class MultiPixelPackedSampleModel extends SampleModel * coordinates are not in bounds. * @param x the X coordinate of the specified pixel * @param y the Y coordinate of the specified pixel - * @param b the band to return, which is assumed to be 0 + * @param b the band to set, which must be 0 * @param s the input sample as an {@code int} * @param data the {@code DataBuffer} where image data is stored * @throws ArrayIndexOutOfBoundsException if the coordinates are @@ -448,6 +448,9 @@ public class MultiPixelPackedSampleModel extends SampleModel * not in bounds, or if {@code obj} is not {@code null} or * not large enough to hold the pixel data * @see #setDataElements(int, int, Object, DataBuffer) + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates are + * not in bounds, or if {code obj} is too small to hold the output. */ public Object getDataElements(int x, int y, Object obj, DataBuffer data) { if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { @@ -527,8 +530,11 @@ public class MultiPixelPackedSampleModel extends SampleModel * @param data the {@code DataBuffer} where image data is stored * @return an array containing the specified pixel. * @throws ArrayIndexOutOfBoundsException if the coordinates - * are not in bounds + * are not in bounds, or if {@code iArray} is too small to hold the output. * @see #setPixel(int, int, int[], DataBuffer) + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates are + * not in bounds, or if {@code iArray} is too small to hold the output. */ public int[] getPixel(int x, int y, int[] iArray, DataBuffer data) { if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { @@ -588,6 +594,9 @@ public class MultiPixelPackedSampleModel extends SampleModel * @param obj a primitive array containing pixel data * @param data the {@code DataBuffer} containing the image data * @see #getDataElements(int, int, Object, DataBuffer) + * @throws NullPointerException if {@code obj} or {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates are + * not in bounds, or if {@code obj} is too small to hold the input. */ public void setDataElements(int x, int y, Object obj, DataBuffer data) { if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { @@ -638,6 +647,9 @@ public class MultiPixelPackedSampleModel extends SampleModel * @param iArray the input pixel in an {@code int} array * @param data the {@code DataBuffer} containing the image data * @see #getPixel(int, int, int[], DataBuffer) + * @throws NullPointerException if {@code iArray} or {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates are + * not in bounds, or if {@code iArray} is too small to hold the input. */ public void setPixel(int x, int y, int[] iArray, DataBuffer data) { if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { diff --git a/src/java.desktop/share/classes/java/awt/image/SampleModel.java b/src/java.desktop/share/classes/java/awt/image/SampleModel.java index 678925ffd20..0ecd4162c60 100644 --- a/src/java.desktop/share/classes/java/awt/image/SampleModel.java +++ b/src/java.desktop/share/classes/java/awt/image/SampleModel.java @@ -231,9 +231,9 @@ public abstract class SampleModel * @return the samples for the specified pixel. * @see #setPixel(int, int, int[], DataBuffer) * - * @throws NullPointerException if data is null. + * @throws NullPointerException if {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates are - * not in bounds, or if iArray is too small to hold the output. + * not in bounds, or if {@code iArray} is too small to hold the output. */ public int[] getPixel(int x, int y, int[] iArray, DataBuffer data) { @@ -293,9 +293,9 @@ public abstract class SampleModel * @see java.awt.image.DataBuffer * @see #setDataElements(int, int, Object, DataBuffer) * - * @throws NullPointerException if data is null. + * @throws NullPointerException if {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates are - * not in bounds, or if obj is too small to hold the output. + * not in bounds, or if {@code obj} is too small to hold the output. */ public abstract Object getDataElements(int x, int y, Object obj, DataBuffer data); @@ -347,9 +347,10 @@ public abstract class SampleModel * @see #setDataElements(int, int, int, int, Object, DataBuffer) * @see java.awt.image.DataBuffer * - * @throws NullPointerException if data is null. + * @throws NullPointerException if {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates are - * not in bounds, or if obj is too small to hold the output. + * not in bounds, or {@code w} or {@code h} is negative + * or if {@code obj} is too small to hold the output. */ public Object getDataElements(int x, int y, int w, int h, Object obj, DataBuffer data) { @@ -362,8 +363,8 @@ public abstract class SampleModel int x1 = x + w; int y1 = y + h; - if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width || - y < 0 || y >= height || h > height || y1 < 0 || y1 > height) + if (x < 0 || w < 0 || x >= width || w > width || x1 < 0 || x1 > width || + y < 0 || h < 0 || y >= height || h > height || y1 < 0 || y1 > height) { throw new ArrayIndexOutOfBoundsException("Invalid coordinates."); } @@ -528,7 +529,7 @@ public abstract class SampleModel * @see #getDataElements(int, int, Object, DataBuffer) * @see java.awt.image.DataBuffer * - * @throws NullPointerException if data is null. + * @throws NullPointerException if {@code obj} or {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates are * not in bounds, or if obj is too small to hold the input. */ @@ -577,7 +578,7 @@ public abstract class SampleModel * @see #getDataElements(int, int, int, int, Object, DataBuffer) * @see java.awt.image.DataBuffer * - * @throws NullPointerException if data is null. + * @throws NullPointerException if {@code obj} or {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates are * not in bounds, or if obj is too small to hold the input. */ @@ -592,8 +593,8 @@ public abstract class SampleModel int x1 = x + w; int y1 = y + h; - if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width || - y < 0 || y >= height || h > height || y1 < 0 || y1 > height) + if (x < 0 || w < 0 || x >= width || w > width || x1 < 0 || x1 > width || + y < 0 || h < 0 || y >= height || h > height || y1 < 0 || y1 > height) { throw new ArrayIndexOutOfBoundsException("Invalid coordinates."); } @@ -695,9 +696,9 @@ public abstract class SampleModel * @return the samples for the specified pixel. * @see #setPixel(int, int, float[], DataBuffer) * - * @throws NullPointerException if data is null. + * @throws NullPointerException if {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates are - * not in bounds, or if fArray is too small to hold the output. + * not in bounds, or if {@code fArray} is too small to hold the output. */ public float[] getPixel(int x, int y, float[] fArray, DataBuffer data) { @@ -726,9 +727,9 @@ public abstract class SampleModel * @return the samples for the specified pixel. * @see #setPixel(int, int, double[], DataBuffer) * - * @throws NullPointerException if data is null. + * @throws NullPointerException if {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates are - * not in bounds, or if dArray is too small to hold the output. + * not in bounds, or if {@code dArray} is too small to hold the output. */ public double[] getPixel(int x, int y, double[] dArray, DataBuffer data) { @@ -760,9 +761,10 @@ public abstract class SampleModel * @return the samples for the specified region of pixels. * @see #setPixels(int, int, int, int, int[], DataBuffer) * - * @throws NullPointerException if data is null. + * @throws NullPointerException if {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates are - * not in bounds, or if iArray is too small to hold the output. + * not in bounds, or {@code w} or {@code h} is negative + * or if {@code iArray} is too small to hold the output. */ public int[] getPixels(int x, int y, int w, int h, int[] iArray, DataBuffer data) { @@ -772,8 +774,8 @@ public abstract class SampleModel int x1 = x + w; int y1 = y + h; - if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width || - y < 0 || y >= height || h > height || y1 < 0 || y1 > height) + if (x < 0 || w < 0 || x >= width || w > width || x1 < 0 || x1 > width || + y < 0 || h < 0 || y >= height || h > height || y1 < 0 || y1 > height) { throw new ArrayIndexOutOfBoundsException("Invalid coordinates."); } @@ -808,9 +810,10 @@ public abstract class SampleModel * @return the samples for the specified region of pixels. * @see #setPixels(int, int, int, int, float[], DataBuffer) * - * @throws NullPointerException if data is null. + * @throws NullPointerException if {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates are - * not in bounds, or if fArray is too small to hold the output. + * not in bounds, or {@code w} or {@code h} is negative + * or if {@code fArray} is too small to hold the output. */ public float[] getPixels(int x, int y, int w, int h, float[] fArray, DataBuffer data) { @@ -820,8 +823,8 @@ public abstract class SampleModel int x1 = x + w; int y1 = y + h; - if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width || - y < 0 || y >= height || h > height || y1 < 0 || y1 > height) + if (x < 0 || w < 0 || x >= width || w > width || x1 < 0 || x1 > width || + y < 0 || h < 0 || y >= height || h > height || y1 < 0 || y1 > height) { throw new ArrayIndexOutOfBoundsException("Invalid coordinates."); } @@ -856,9 +859,10 @@ public abstract class SampleModel * @return the samples for the specified region of pixels. * @see #setPixels(int, int, int, int, double[], DataBuffer) * - * @throws NullPointerException if data is null. + * @throws NullPointerException if {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates are - * not in bounds, or if dArray is too small to hold the output. + * not in bounds, or {@code w} or {@code h} is negative + * or if {@code dArray} is too small to hold the output. */ public double[] getPixels(int x, int y, int w, int h, double[] dArray, DataBuffer data) { @@ -867,8 +871,8 @@ public abstract class SampleModel int x1 = x + w; int y1 = y + h; - if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width || - y < 0 || y >= height || h > height || y1 < 0 || y1 > height) + if (x < 0 || w < 0 || x >= width || w > width || x1 < 0 || x1 > width || + y < 0 || h < 0 || y >= height || h > height || y1 < 0 || y1 > height) { throw new ArrayIndexOutOfBoundsException("Invalid coordinates."); } @@ -903,7 +907,7 @@ public abstract class SampleModel * @return the sample in a specified band for the specified pixel. * @see #setSample(int, int, int, int, DataBuffer) * - * @throws NullPointerException if data is null. + * @throws NullPointerException if {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates or * the band index are not in bounds. */ @@ -921,7 +925,7 @@ public abstract class SampleModel * @param data The DataBuffer containing the image data. * @return the sample in a specified band for the specified pixel. * - * @throws NullPointerException if data is null. + * @throws NullPointerException if {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates or * the band index are not in bounds. */ @@ -943,7 +947,7 @@ public abstract class SampleModel * @param data The DataBuffer containing the image data. * @return the sample in a specified band for the specified pixel. * - * @throws NullPointerException if data is null. + * @throws NullPointerException if {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates or * the band index are not in bounds. */ @@ -971,10 +975,10 @@ public abstract class SampleModel * of pixels. * @see #setSamples(int, int, int, int, int, int[], DataBuffer) * - * @throws NullPointerException if data is null. + * @throws NullPointerException if {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates or - * the band index are not in bounds, or if iArray is too small to - * hold the output. + * band index are not in bounds, or {@code w} or {@code h} is negative, + * or if {@code iArray} is too small to hold the output. */ public int[] getSamples(int x, int y, int w, int h, int b, int[] iArray, DataBuffer data) { @@ -983,8 +987,8 @@ public abstract class SampleModel int x1 = x + w; int y1 = y + h; - if (x < 0 || x1 < x || x1 > width || - y < 0 || y1 < y || y1 > height) + if (x < 0 || w < 0 || x1 < x || x1 > width || + y < 0 || h < 0 || y1 < y || y1 > height) { throw new ArrayIndexOutOfBoundsException("Invalid coordinates."); } @@ -1019,10 +1023,10 @@ public abstract class SampleModel * of pixels. * @see #setSamples(int, int, int, int, int, float[], DataBuffer) * - * @throws NullPointerException if data is null. + * @throws NullPointerException if {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates or - * the band index are not in bounds, or if fArray is too small to - * hold the output. + * band index are not in bounds, or {@code w} or {@code h} is negative, + * or if {@code iArray} is too small to hold the output. */ public float[] getSamples(int x, int y, int w, int h, int b, float[] fArray, @@ -1032,8 +1036,8 @@ public abstract class SampleModel int x1 = x + w; int y1 = y + h; - if (x < 0 || x1 < x || x1 > width || - y < 0 || y1 < y || y1 > height) + if (x < 0 || w < 0 || x1 < x || x1 > width || + y < 0 || h < 0 || y1 < y || y1 > height) { throw new ArrayIndexOutOfBoundsException("Invalid coordinates"); } @@ -1068,10 +1072,10 @@ public abstract class SampleModel * of pixels. * @see #setSamples(int, int, int, int, int, double[], DataBuffer) * - * @throws NullPointerException if data is null. + * @throws NullPointerException if {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates or - * the band index are not in bounds, or if dArray is too small to - * hold the output. + * band index are not in bounds, or {@code w} or {@code h} is negative, + * or if {@code dArray} is too small to hold the output. */ public double[] getSamples(int x, int y, int w, int h, int b, double[] dArray, @@ -1081,8 +1085,8 @@ public abstract class SampleModel int x1 = x + w; int y1 = y + h; - if (x < 0 || x1 < x || x1 > width || - y < 0 || y1 < y || y1 > height) + if (x < 0 || w < 0 || x1 < x || x1 > width || + y < 0 || h < 0 || y1 < y || y1 > height) { throw new ArrayIndexOutOfBoundsException("Invalid coordinates"); } @@ -1111,9 +1115,9 @@ public abstract class SampleModel * @param data The DataBuffer containing the image data. * @see #getPixel(int, int, int[], DataBuffer) * - * @throws NullPointerException if iArray or data is null. + * @throws NullPointerException if {@code iArray} or {code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates are - * not in bounds, or if iArray is too small to hold the input. + * not in bounds, or if {@code iArray} is too small to hold the input. */ public void setPixel(int x, int y, int[] iArray, DataBuffer data) { @@ -1131,9 +1135,9 @@ public abstract class SampleModel * @param data The DataBuffer containing the image data. * @see #getPixel(int, int, float[], DataBuffer) * - * @throws NullPointerException if fArray or data is null. + * @throws NullPointerException if {@code fArray} or {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates are - * not in bounds, or if fArray is too small to hold the input. + * not in bounds, or if {@code fArray} is too small to hold the input. */ public void setPixel(int x, int y, float[] fArray, DataBuffer data) { @@ -1150,9 +1154,9 @@ public abstract class SampleModel * @param data The DataBuffer containing the image data. * @see #getPixel(int, int, double[], DataBuffer) * - * @throws NullPointerException if dArray or data is null. + * @throws NullPointerException if {@code dArray} or {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates are - * not in bounds, or if fArray is too small to hold the input. + * not in bounds, or if {@code dArray} is too small to hold the input. */ public void setPixel(int x, int y, double[] dArray, DataBuffer data) { @@ -1173,9 +1177,10 @@ public abstract class SampleModel * @param data The DataBuffer containing the image data. * @see #getPixels(int, int, int, int, int[], DataBuffer) * - * @throws NullPointerException if iArray or data is null. + * @throws NullPointerException if {@code iArray} or {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates are - * not in bounds, or if iArray is too small to hold the input. + * not in bounds, or {@code w} or {@code h} is negative + * or if {@code iArray} is too small to hold the input. */ public void setPixels(int x, int y, int w, int h, int[] iArray, DataBuffer data) { @@ -1183,8 +1188,8 @@ public abstract class SampleModel int x1 = x + w; int y1 = y + h; - if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width || - y < 0 || y >= height || h > height || y1 < 0 || y1 > height) + if (x < 0 || w < 0 || x >= width || w > width || x1 < 0 || x1 > width || + y < 0 || h < 0 || y >= height || h > height || y1 < 0 || y1 > height) { throw new ArrayIndexOutOfBoundsException("Invalid coordinates."); } @@ -1211,9 +1216,10 @@ public abstract class SampleModel * @param data The DataBuffer containing the image data. * @see #getPixels(int, int, int, int, float[], DataBuffer) * - * @throws NullPointerException if fArray or data is null. + * @throws NullPointerException if {@code fArray} or {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates are - * not in bounds, or if fArray is too small to hold the input. + * not in bounds, or {@code w} or {@code h} is negative + * or if {@code fArray} is too small to hold the input. */ public void setPixels(int x, int y, int w, int h, float[] fArray, DataBuffer data) { @@ -1221,8 +1227,8 @@ public abstract class SampleModel int x1 = x + w; int y1 = y + h; - if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width|| - y < 0 || y >= height || h > height || y1 < 0 || y1 > height) + if (x < 0 || w < 0 || x >= width || w > width || x1 < 0 || x1 > width || + y < 0 || h < 0 || y >= height || h > height || y1 < 0 || y1 > height) { throw new ArrayIndexOutOfBoundsException("Invalid coordinates."); } @@ -1249,9 +1255,10 @@ public abstract class SampleModel * @param data The DataBuffer containing the image data. * @see #getPixels(int, int, int, int, double[], DataBuffer) * - * @throws NullPointerException if dArray or data is null. + * @throws NullPointerException if {@code dArray} or {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates are - * not in bounds, or if dArray is too small to hold the input. + * not in bounds, or {@code w} or {@code h} is negative + * or if {@code dArray} is too small to hold the input. */ public void setPixels(int x, int y, int w, int h, double[] dArray, DataBuffer data) { @@ -1259,8 +1266,8 @@ public abstract class SampleModel int x1 = x + w; int y1 = y + h; - if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width || - y < 0 || y >= height || h > height || y1 < 0 || y1 > height) + if (x < 0 || w < 0 || x >= width || w > width || x1 < 0 || x1 > width || + y < 0 || h < 0 || y >= height || h > height || y1 < 0 || y1 > height) { throw new ArrayIndexOutOfBoundsException("Invalid coordinates."); } @@ -1286,7 +1293,7 @@ public abstract class SampleModel * @param data The DataBuffer containing the image data. * @see #getSample(int, int, int, DataBuffer) * - * @throws NullPointerException if data is null. + * @throws NullPointerException if {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates or * the band index are not in bounds. */ @@ -1310,7 +1317,7 @@ public abstract class SampleModel * @param data The DataBuffer containing the image data. * @see #getSample(int, int, int, DataBuffer) * - * @throws NullPointerException if data is null. + * @throws NullPointerException if {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates or * the band index are not in bounds. */ @@ -1338,7 +1345,7 @@ public abstract class SampleModel * @param data The DataBuffer containing the image data. * @see #getSample(int, int, int, DataBuffer) * - * @throws NullPointerException if data is null. + * @throws NullPointerException if {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates or * the band index are not in bounds. */ @@ -1364,10 +1371,10 @@ public abstract class SampleModel * @param data The DataBuffer containing the image data. * @see #getSamples(int, int, int, int, int, int[], DataBuffer) * - * @throws NullPointerException if iArray or data is null. + * @throws NullPointerException if {@code iArray} or {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates or - * the band index are not in bounds, or if iArray is too small to - * hold the input. + * band index are not in bounds, or {@code w} or {@code h} is negative, + * or if {@code iArray} is too small to hold the input. */ public void setSamples(int x, int y, int w, int h, int b, int[] iArray, DataBuffer data) { @@ -1375,8 +1382,8 @@ public abstract class SampleModel int Offset=0; int x1 = x + w; int y1 = y + h; - if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width || - y < 0 || y >= height || h > height || y1 < 0 || y1 > height) + if (x < 0 || w < 0 || x >= width || w > width || x1 < 0 || x1 > width || + y < 0 || h < 0 || y >= height || h > height || y1 < 0 || y1 > height) { throw new ArrayIndexOutOfBoundsException("Invalid coordinates."); } @@ -1402,10 +1409,10 @@ public abstract class SampleModel * @param data The DataBuffer containing the image data. * @see #getSamples(int, int, int, int, int, float[], DataBuffer) * - * @throws NullPointerException if fArray or data is null. + * @throws NullPointerException if {@code fArray} or {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates or - * the band index are not in bounds, or if fArray is too small to - * hold the input. + * band index are not in bounds, or {@code w} or {@code h} is negative, + * or if {@code fArray} is too small to hold the input. */ public void setSamples(int x, int y, int w, int h, int b, float[] fArray, DataBuffer data) { @@ -1413,8 +1420,8 @@ public abstract class SampleModel int x1 = x + w; int y1 = y + h; - if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width || - y < 0 || y >= height || h > height || y1 < 0 || y1 > height) + if (x < 0 || w < 0 || x >= width || w > width || x1 < 0 || x1 > width || + y < 0 || h < 0 || y >= height || h > height || y1 < 0 || y1 > height) { throw new ArrayIndexOutOfBoundsException("Invalid coordinates."); } @@ -1440,10 +1447,10 @@ public abstract class SampleModel * @param data The DataBuffer containing the image data. * @see #getSamples(int, int, int, int, int, double[], DataBuffer) * - * @throws NullPointerException if dArray or data is null. + * @throws NullPointerException if {@code dArray} or {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates or - * the band index are not in bounds, or if dArray is too small to - * hold the input. + * band index are not in bounds, or {@code w} or {@code h} is negative, + * or if {@code dArray} is too small to hold the input. */ public void setSamples(int x, int y, int w, int h, int b, double[] dArray, DataBuffer data) { @@ -1452,8 +1459,8 @@ public abstract class SampleModel int y1 = y + h; - if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width || - y < 0 || y >= height || h > height || y1 < 0 || y1 > height) + if (x < 0 || w < 0 || x >= width || w > width || x1 < 0 || x1 > width || + y < 0 || h < 0 || y >= height || h > height || y1 < 0 || y1 > height) { throw new ArrayIndexOutOfBoundsException("Invalid coordinates."); } diff --git a/src/java.desktop/share/classes/java/awt/image/SinglePixelPackedSampleModel.java b/src/java.desktop/share/classes/java/awt/image/SinglePixelPackedSampleModel.java index abb669e02c6..a75b5197c44 100644 --- a/src/java.desktop/share/classes/java/awt/image/SinglePixelPackedSampleModel.java +++ b/src/java.desktop/share/classes/java/awt/image/SinglePixelPackedSampleModel.java @@ -357,6 +357,9 @@ public class SinglePixelPackedSampleModel extends SampleModel * @param data The DataBuffer containing the image data. * @return the data for the specified pixel. * @see #setDataElements(int, int, Object, DataBuffer) + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates are + * not in bounds, or if obj is too small to hold the output. */ public Object getDataElements(int x, int y, Object obj, DataBuffer data) { // Bounds check for 'b' will be performed automatically @@ -416,15 +419,10 @@ public class SinglePixelPackedSampleModel extends SampleModel } /** - * Returns all samples in for the specified pixel in an int array. - * ArrayIndexOutOfBoundsException may be thrown if the coordinates are - * not in bounds. - * @param x The X coordinate of the pixel location. - * @param y The Y coordinate of the pixel location. - * @param iArray If non-null, returns the samples in this array - * @param data The DataBuffer containing the image data. - * @return all samples for the specified pixel. - * @see #setPixel(int, int, int[], DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates are + * not in bounds, or if {@code iArray} is too small to hold the output. */ public int [] getPixel(int x, int y, int[] iArray, DataBuffer data) { if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { @@ -446,26 +444,20 @@ public class SinglePixelPackedSampleModel extends SampleModel } /** - * Returns all samples for the specified rectangle of pixels in - * an int array, one sample per array element. - * ArrayIndexOutOfBoundsException may be thrown if the coordinates are - * not in bounds. - * @param x The X coordinate of the upper left pixel location. - * @param y The Y coordinate of the upper left pixel location. - * @param w The width of the pixel rectangle. - * @param h The height of the pixel rectangle. - * @param iArray If non-null, returns the samples in this array. - * @param data The DataBuffer containing the image data. - * @return all samples for the specified region of pixels. - * @see #setPixels(int, int, int, int, int[], DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates are + * not in bounds, or {@code w} or {@code h} is negative + * or if {@code iArray} is too small to hold the output. */ + @Override public int[] getPixels(int x, int y, int w, int h, int[] iArray, DataBuffer data) { int x1 = x + w; int y1 = y + h; - if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width || - y < 0 || y >= height || h > height || y1 < 0 || y1 > height) + if (x < 0 || w < 0 || x >= width || w > width || x1 < 0 || x1 > width || + y < 0 || h < 0 || y >= height || h > height || y1 < 0 || y1 > height) { throw new ArrayIndexOutOfBoundsException ("Coordinate out of bounds!"); @@ -493,17 +485,10 @@ public class SinglePixelPackedSampleModel extends SampleModel } /** - * Returns as int the sample in a specified band for the pixel - * located at (x,y). - * ArrayIndexOutOfBoundsException may be thrown if the coordinates are - * not in bounds. - * @param x The X coordinate of the pixel location. - * @param y The Y coordinate of the pixel location. - * @param b The band to return. - * @param data The DataBuffer containing the image data. - * @return the sample in a specified band for the specified - * pixel. - * @see #setSample(int, int, int, int, DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * the band index are not in bounds. */ public int getSample(int x, int y, int b, DataBuffer data) { // Bounds check for 'b' will be performed automatically @@ -516,25 +501,16 @@ public class SinglePixelPackedSampleModel extends SampleModel } /** - * Returns the samples for a specified band for the specified rectangle - * of pixels in an int array, one sample per array element. - * ArrayIndexOutOfBoundsException may be thrown if the coordinates are - * not in bounds. - * @param x The X coordinate of the upper left pixel location. - * @param y The Y coordinate of the upper left pixel location. - * @param w The width of the pixel rectangle. - * @param h The height of the pixel rectangle. - * @param b The band to return. - * @param iArray If non-null, returns the samples in this array. - * @param data The DataBuffer containing the image data. - * @return the samples for the specified band for the specified - * region of pixels. - * @see #setSamples(int, int, int, int, int, int[], DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * band index are not in bounds, or {@code w} or {@code h} is negative, + * or if {@code iArray} is too small to hold the output. */ public int[] getSamples(int x, int y, int w, int h, int b, int[] iArray, DataBuffer data) { // Bounds check for 'b' will be performed automatically - if ((x < 0) || (y < 0) || (x + w > width) || (y + h > height)) { + if ((x < 0) || (y < 0) || (w < 0) || (h < 0) || (x + w > width) || (y + h > height)) { throw new ArrayIndexOutOfBoundsException ("Coordinate out of bounds!"); } @@ -592,6 +568,9 @@ public class SinglePixelPackedSampleModel extends SampleModel * @param obj A primitive array containing pixel data. * @param data The DataBuffer containing the image data. * @see #getDataElements(int, int, Object, DataBuffer) + * @throws NullPointerException if {@code obj} or {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates are + * not in bounds, or if obj is too small to hold the input. */ public void setDataElements(int x, int y, Object obj, DataBuffer data) { if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { @@ -624,14 +603,10 @@ public class SinglePixelPackedSampleModel extends SampleModel } /** - * Sets a pixel in the DataBuffer using an int array of samples for input. - * ArrayIndexOutOfBoundsException may be thrown if the coordinates are - * not in bounds. - * @param x The X coordinate of the pixel location. - * @param y The Y coordinate of the pixel location. - * @param iArray The input samples in an int array. - * @param data The DataBuffer containing the image data. - * @see #getPixel(int, int, int[], DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code iArray} or {code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates are + * not in bounds, or if {@code iArray} is too small to hold the input. */ public void setPixel(int x, int y, int[] iArray, @@ -650,25 +625,19 @@ public class SinglePixelPackedSampleModel extends SampleModel } /** - * Sets all samples for a rectangle of pixels from an int array containing - * one sample per array element. - * ArrayIndexOutOfBoundsException may be thrown if the coordinates are - * not in bounds. - * @param x The X coordinate of the upper left pixel location. - * @param y The Y coordinate of the upper left pixel location. - * @param w The width of the pixel rectangle. - * @param h The height of the pixel rectangle. - * @param iArray The input samples in an int array. - * @param data The DataBuffer containing the image data. - * @see #getPixels(int, int, int, int, int[], DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code iArray} or {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates are + * not in bounds, or {@code w} or {@code h} is negative + * or if {@code iArray} is too small to hold the input. */ public void setPixels(int x, int y, int w, int h, int[] iArray, DataBuffer data) { int x1 = x + w; int y1 = y + h; - if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width || - y < 0 || y >= height || h > height || y1 < 0 || y1 > height) + if (x < 0 || w < 0 || x >= width || w > width || x1 < 0 || x1 > width || + y < 0 || h < 0 || y >= height || h > height || y1 < 0 || y1 > height) { throw new ArrayIndexOutOfBoundsException ("Coordinate out of bounds!"); @@ -692,17 +661,11 @@ public class SinglePixelPackedSampleModel extends SampleModel } } - /** - * Sets a sample in the specified band for the pixel located at (x,y) - * in the DataBuffer using an int for input. - * ArrayIndexOutOfBoundsException may be thrown if the coordinates are - * not in bounds. - * @param x The X coordinate of the pixel location. - * @param y The Y coordinate of the pixel location. - * @param b The band to set. - * @param s The input sample as an int. - * @param data The DataBuffer containing the image data. - * @see #getSample(int, int, int, DataBuffer) + /* + * {inheritDoc} + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * the band index are not in bounds. */ public void setSample(int x, int y, int b, int s, DataBuffer data) { @@ -718,23 +681,16 @@ public class SinglePixelPackedSampleModel extends SampleModel } /** - * Sets the samples in the specified band for the specified rectangle - * of pixels from an int array containing one sample per array element. - * ArrayIndexOutOfBoundsException may be thrown if the coordinates are - * not in bounds. - * @param x The X coordinate of the upper left pixel location. - * @param y The Y coordinate of the upper left pixel location. - * @param w The width of the pixel rectangle. - * @param h The height of the pixel rectangle. - * @param b The band to set. - * @param iArray The input samples in an int array. - * @param data The DataBuffer containing the image data. - * @see #getSamples(int, int, int, int, int, int[], DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code iArray} or {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * band index are not in bounds, or {@code w} or {@code h} is negative, + * or if {@code iArray} is too small to hold the input. */ public void setSamples(int x, int y, int w, int h, int b, int[] iArray, DataBuffer data) { // Bounds check for 'b' will be performed automatically - if ((x < 0) || (y < 0) || (x + w > width) || (y + h > height)) { + if ((x < 0) || (y < 0) || (w < 0) || (h < 0) || (x + w > width) || (y + h > height)) { throw new ArrayIndexOutOfBoundsException ("Coordinate out of bounds!"); } diff --git a/test/jdk/java/awt/image/SampleModelGetSamplesAndPixelsTest.java b/test/jdk/java/awt/image/SampleModelGetSamplesAndPixelsTest.java new file mode 100644 index 00000000000..483bbe43d9e --- /dev/null +++ b/test/jdk/java/awt/image/SampleModelGetSamplesAndPixelsTest.java @@ -0,0 +1,337 @@ +/* + * Copyright (c) 2025, 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 6185110 + * @summary Verify get/set/Pixels/Samples APIs for bad parameters. + * + * @run main SampleModelGetSamplesAndPixelsTest + */ + +import java.awt.image.BandedSampleModel; +import java.awt.image.ComponentSampleModel; +import java.awt.image.DataBuffer; +import java.awt.image.MultiPixelPackedSampleModel; +import java.awt.image.PixelInterleavedSampleModel; +import java.awt.image.SampleModel; +import java.awt.image.SinglePixelPackedSampleModel; +import java.util.Vector; + +public class SampleModelGetSamplesAndPixelsTest { + + static final int WIDTH = 100; + static final int HEIGHT = 100; + static final int DATATYPE = DataBuffer.TYPE_BYTE; + static final int NUMBANDS = 4; + static final int[] INTS = new int[WIDTH * HEIGHT + NUMBANDS]; + static final float[] FLOATS = new float[WIDTH * HEIGHT + NUMBANDS]; + static final double[] DOUBLES = new double[WIDTH * HEIGHT + NUMBANDS]; + static final int[][] COORDS = { + { 1, 1, 1, 1, -1 }, // bad band + { 1, 1, 1, 1, NUMBANDS }, // bad band + { 1, 1, -1, 1, 0 }, // negative w + { 1, 1, -1, -1, 0 }, // negative w and h + { -4, 1, 1, 1, 0 }, // negative x + { -4, -4, 1, 1, 0 }, // negative x and y + { WIDTH+10, 0, 1, 1, 0 }, // x > width + { 0, HEIGHT+10, 1, 1, 0 }, // y > height + { WIDTH+10, HEIGHT+10, 1, 1, 0 }, // both x > width and y > height + }; + + public static void main(String[] args) { + Vector> classes = new Vector>(); + + classes.add(ComponentSampleModel.class); + classes.add(MultiPixelPackedSampleModel.class); + classes.add(SinglePixelPackedSampleModel.class); + classes.add(BandedSampleModel.class); + classes.add(PixelInterleavedSampleModel.class); + + for (Class c : classes) { + doTest(c); + } + } + + static void noException(SampleModel sm) { + System.err.println(sm); + throw new RuntimeException("No expected exception"); + } + + private static void doTest(Class c) { + System.out.println("Test for: " + c.getName()); + SampleModel sm = createSampleModel(c); + doTestNull(sm); + for (int i = 0; i < COORDS.length; i++) { + int x = COORDS[i][0]; + int y = COORDS[i][1]; + int w = COORDS[i][2]; + int h = COORDS[i][3]; + int b = COORDS[i][4]; + doTest(sm, x, y, w, h, b); + } + } + + private static void doTestNull(SampleModel sm) { + doTestNull(sm, INTS); + doTestNull(sm, FLOATS); + doTestNull(sm, DOUBLES); + } + + private static void doTestNull(SampleModel sm, int[] INTS) { + try { + sm.getSamples(1, 1, 1, 1, 0, INTS, null); + noException(sm); + } catch (NullPointerException e) { + System.out.println(e.getMessage()); + } + + try { + sm.getSamples(1, 1, 1, 1, 0, INTS, null); + noException(sm); + } catch (NullPointerException e) { + System.out.println(e.getMessage()); + } + + try { + sm.getPixels(1, 1, 1, 1, INTS, null); + noException(sm); + } catch (NullPointerException e) { + System.out.println(e.getMessage()); + } + + try { + sm.setPixels(1, 1, 1, 1, INTS, null); + noException(sm); + } catch (NullPointerException e) { + System.out.println(e.getMessage()); + } + } + + private static void doTestNull(SampleModel sm, float[] FLOATS) { + try { + sm.getSamples(1, 1, 1, 1, 0, FLOATS, null); + noException(sm); + } catch (NullPointerException e) { + System.out.println(e.getMessage()); + } + + try { + sm.getSamples(1, 1, 1, 1, 0, FLOATS, null); + noException(sm); + } catch (NullPointerException e) { + System.out.println(e.getMessage()); + } + + try { + sm.getPixels(1, 1, 1, 1, FLOATS, null); + noException(sm); + } catch (NullPointerException e) { + System.out.println(e.getMessage()); + } + + try { + sm.setPixels(1, 1, 1, 1, FLOATS, null); + noException(sm); + } catch (NullPointerException e) { + System.out.println(e.getMessage()); + } + } + + private static void doTestNull(SampleModel sm, double[] DOUBLES) { + try { + sm.getSamples(1, 1, 1, 1, 0, DOUBLES, null); + noException(sm); + } catch (NullPointerException e) { + System.out.println(e.getMessage()); + } + + try { + sm.getSamples(1, 1, 1, 1, 0, DOUBLES, null); + noException(sm); + } catch (NullPointerException e) { + System.out.println(e.getMessage()); + } + + try { + sm.getPixels(1, 1, 1, 1, DOUBLES, null); + noException(sm); + } catch (NullPointerException e) { + System.out.println(e.getMessage()); + } + + try { + sm.setPixels(1, 1, 1, 1, DOUBLES, null); + noException(sm); + } catch (NullPointerException e) { + System.out.println(e.getMessage()); + } + } + + private static void doTest(SampleModel sm, int x, int y, int w, int h, int b) { + doTest(sm, x, y, w, h, b, INTS); + doTest(sm, x, y, w, h, b, FLOATS); + doTest(sm, x, y, w, h, b, DOUBLES); + } + + private static void doTest(SampleModel sm, int x, int y, int w, int h, int b, int[] INTS) { + + // Now test each API with a non-null buffer and the specified values. + DataBuffer db = sm.createDataBuffer(); + + try { + sm.getSamples(x, y, w, h, b, INTS, db); + noException(sm); + } catch (ArrayIndexOutOfBoundsException e) { + System.out.println(e.getMessage()); + } + + try { + sm.setSamples(x, y, w, h, b, INTS, db); + noException(sm); + } catch (ArrayIndexOutOfBoundsException e) { + System.out.println(e.getMessage()); + } + + if (b < 0 || b >= NUMBANDS) { + return; // Values were to test illegal bands, skip the rest. + } + + try { + sm.getPixels(x, y, w, h, INTS, db); + noException(sm); + } catch (ArrayIndexOutOfBoundsException e) { + System.out.println(e.getMessage()); + } + + try { + sm.setPixels(x, y, w, h, INTS, db); + noException(sm); + } catch (ArrayIndexOutOfBoundsException e) { + System.out.println(e.getMessage()); + } + } + + private static void doTest(SampleModel sm, int x, int y, int w, int h, int b, float[] FLOATS) { + + // Now test each API with a non-null buffer and the specified values. + DataBuffer db = sm.createDataBuffer(); + + try { + sm.getSamples(x, y, w, h, b, FLOATS, db); + noException(sm); + } catch (ArrayIndexOutOfBoundsException e) { + System.out.println(e.getMessage()); + } + + try { + sm.setSamples(x, y, w, h, b, FLOATS, db); + noException(sm); + } catch (ArrayIndexOutOfBoundsException e) { + System.out.println(e.getMessage()); + } + + if (b < 0 || b >= NUMBANDS) { + return; // Values were to test illegal bands, skip the rest. + } + + try { + sm.getPixels(x, y, w, h, FLOATS, db); + noException(sm); + } catch (ArrayIndexOutOfBoundsException e) { + System.out.println(e.getMessage()); + } + + try { + sm.setPixels(x, y, w, h, FLOATS, db); + noException(sm); + } catch (ArrayIndexOutOfBoundsException e) { + System.out.println(e.getMessage()); + } + } + + private static void doTest(SampleModel sm, int x, int y, int w, int h, int b, double[] DOUBLES) { + + // Now test each API with a non-null buffer and the specified values. + DataBuffer db = sm.createDataBuffer(); + + try { + sm.getSamples(x, y, w, h, b, DOUBLES, db); + noException(sm); + } catch (ArrayIndexOutOfBoundsException e) { + System.out.println(e.getMessage()); + } + + try { + sm.setSamples(x, y, w, h, b, DOUBLES, db); + noException(sm); + } catch (ArrayIndexOutOfBoundsException e) { + System.out.println(e.getMessage()); + } + + if (b < 0 || b >= NUMBANDS) { + return; // Values were to test illegal bands, skip the rest. + } + + try { + sm.getPixels(x, y, w, h, DOUBLES, db); + noException(sm); + } catch (ArrayIndexOutOfBoundsException e) { + System.out.println(e.getMessage()); + } + + try { + sm.setPixels(x, y, w, h, DOUBLES, db); + noException(sm); + } catch (ArrayIndexOutOfBoundsException e) { + System.out.println(e.getMessage()); + } + + try { + sm.setDataElements(0, 0, null, db); + noException(sm); + } catch (NullPointerException e) { + System.out.println(e.getMessage()); + } + } + + private static SampleModel createSampleModel(Class cls) { + SampleModel res = null; + + if (cls == ComponentSampleModel.class) { + res = new ComponentSampleModel(DATATYPE, WIDTH, HEIGHT, 4, WIDTH * 4, new int[] { 0, 1, 2, 3 } ); + } else if (cls == MultiPixelPackedSampleModel.class) { + res = new MultiPixelPackedSampleModel(DATATYPE, WIDTH, HEIGHT, 4); + } else if (cls == SinglePixelPackedSampleModel.class) { + res = new SinglePixelPackedSampleModel(DATATYPE, WIDTH, HEIGHT, + new int[]{ 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff }); + } else if (cls == BandedSampleModel.class) { + res = new BandedSampleModel(DATATYPE, WIDTH, HEIGHT, NUMBANDS); + } else if (cls == PixelInterleavedSampleModel.class) { + res = new PixelInterleavedSampleModel(DATATYPE, WIDTH, HEIGHT, 4, WIDTH * 4, new int[] { 0, 1, 2, 3 }); + } else { + throw new RuntimeException("Unknown class " + cls); + } + return res; + } +} From 5627ff2d9165ee1f7354c1ff1626f4949ef7fa3f Mon Sep 17 00:00:00 2001 From: Dean Long Date: Tue, 2 Dec 2025 18:18:56 +0000 Subject: [PATCH 100/706] 8370766: JVM crashes when running compiler/exceptions/TestAccessErrorInCatch.java fails with -XX:+VerifyStack MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Manuel Hässig Reviewed-by: mhaessig, chagedorn --- src/hotspot/share/opto/doCall.cpp | 17 +++++++++++------ .../exceptions/TestAccessErrorInCatch.java | 4 +++- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/hotspot/share/opto/doCall.cpp b/src/hotspot/share/opto/doCall.cpp index 91bb743618b..5533b19897b 100644 --- a/src/hotspot/share/opto/doCall.cpp +++ b/src/hotspot/share/opto/doCall.cpp @@ -1059,14 +1059,19 @@ void Parse::catch_inline_exceptions(SafePointNode* ex_map) { assert(!stopped(), "you should return if you finish the chain"); // Oops, need to call into the VM to resolve the klasses at runtime. - // Note: This call must not deoptimize, since it is not a real at this bci! kill_dead_locals(); - make_runtime_call(RC_NO_LEAF | RC_MUST_THROW, - OptoRuntime::rethrow_Type(), - OptoRuntime::rethrow_stub(), - nullptr, nullptr, - ex_node); + { PreserveReexecuteState preexecs(this); + // When throwing an exception, set the reexecute flag for deoptimization. + // This is mostly needed to pass -XX:+VerifyStack sanity checks. + jvms()->set_should_reexecute(true); + + make_runtime_call(RC_NO_LEAF | RC_MUST_THROW, + OptoRuntime::rethrow_Type(), + OptoRuntime::rethrow_stub(), + nullptr, nullptr, + ex_node); + } // Rethrow is a pure call, no side effects, only a result. // The result cannot be allocated, so we use I_O diff --git a/test/hotspot/jtreg/compiler/exceptions/TestAccessErrorInCatch.java b/test/hotspot/jtreg/compiler/exceptions/TestAccessErrorInCatch.java index 46541d76016..44cfd60cf38 100644 --- a/test/hotspot/jtreg/compiler/exceptions/TestAccessErrorInCatch.java +++ b/test/hotspot/jtreg/compiler/exceptions/TestAccessErrorInCatch.java @@ -23,16 +23,18 @@ /* * @test - * @bug 8367002 + * @bug 8367002 8370766 * @summary Compilers might not generate handlers for recursive exceptions * * @compile IllegalAccessInCatch.jasm * @run main/othervm -Xbatch * -XX:CompileCommand=compileonly,IllegalAccessInCatch*::test + * -XX:+IgnoreUnrecognizedVMOptions -XX:+VerifyStack * -XX:-TieredCompilation * TestAccessErrorInCatch * @run main/othervm -Xbatch * -XX:CompileCommand=compileonly,IllegalAccessInCatch*::test + * -XX:+IgnoreUnrecognizedVMOptions -XX:+VerifyStack * -XX:TieredStopAtLevel=3 * TestAccessErrorInCatch */ From 618732ffc04ef393c9b8a3265c12ba66f31784d9 Mon Sep 17 00:00:00 2001 From: Martin Doerr Date: Tue, 2 Dec 2025 19:36:43 +0000 Subject: [PATCH 101/706] 8371820: Further AES performance improvements for key schedule generation Reviewed-by: rrich, valeriep --- .../cpu/aarch64/stubGenerator_aarch64.cpp | 10 ++--- src/hotspot/cpu/ppc/stubGenerator_ppc.cpp | 2 +- src/hotspot/cpu/riscv/stubGenerator_riscv.cpp | 4 +- .../cpu/x86/stubGenerator_x86_64_aes.cpp | 10 ++--- src/hotspot/share/opto/library_call.cpp | 40 +++++++++---------- src/hotspot/share/opto/library_call.hpp | 2 +- .../com/sun/crypto/provider/AES_Crypt.java | 33 ++++++++------- 7 files changed, 53 insertions(+), 48 deletions(-) diff --git a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp index 8dbc5dbac03..7e2f333ba40 100644 --- a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp @@ -2879,7 +2879,7 @@ class StubGenerator: public StubCodeGenerator { // Inputs: // c_rarg0 - source byte array address // c_rarg1 - destination byte array address - // c_rarg2 - K (key) in little endian int array + // c_rarg2 - sessionKe (key) in little endian int array // address generate_aescrypt_encryptBlock() { __ align(CodeEntryAlignment); @@ -2912,7 +2912,7 @@ class StubGenerator: public StubCodeGenerator { // Inputs: // c_rarg0 - source byte array address // c_rarg1 - destination byte array address - // c_rarg2 - K (key) in little endian int array + // c_rarg2 - sessionKd (key) in little endian int array // address generate_aescrypt_decryptBlock() { assert(UseAES, "need AES cryptographic extension support"); @@ -2946,7 +2946,7 @@ class StubGenerator: public StubCodeGenerator { // Inputs: // c_rarg0 - source byte array address // c_rarg1 - destination byte array address - // c_rarg2 - K (key) in little endian int array + // c_rarg2 - sessionKe (key) in little endian int array // c_rarg3 - r vector byte array address // c_rarg4 - input length // @@ -3051,7 +3051,7 @@ class StubGenerator: public StubCodeGenerator { // Inputs: // c_rarg0 - source byte array address // c_rarg1 - destination byte array address - // c_rarg2 - K (key) in little endian int array + // c_rarg2 - sessionKd (key) in little endian int array // c_rarg3 - r vector byte array address // c_rarg4 - input length // @@ -3178,7 +3178,7 @@ class StubGenerator: public StubCodeGenerator { // Inputs: // c_rarg0 - source byte array address // c_rarg1 - destination byte array address - // c_rarg2 - K (key) in little endian int array + // c_rarg2 - sessionKe (key) in little endian int array // c_rarg3 - counter vector byte array address // c_rarg4 - input length // c_rarg5 - saved encryptedCounter start diff --git a/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp b/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp index 948092bbb9a..e48778a8b9f 100644 --- a/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp +++ b/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp @@ -2956,7 +2956,7 @@ class StubGenerator: public StubCodeGenerator { // Arguments for generated stub: // R3_ARG1 - source byte array address // R4_ARG2 - destination byte array address - // R5_ARG3 - K (key) in little endian int array + // R5_ARG3 - sessionKe (key) in little endian int array address generate_aescrypt_decryptBlock() { assert(UseAES, "need AES instructions and misaligned SSE support"); StubId stub_id = StubId::stubgen_aescrypt_decryptBlock_id; diff --git a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp index e5eb15cb8e4..dff9a3d508e 100644 --- a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp +++ b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp @@ -2463,7 +2463,7 @@ class StubGenerator: public StubCodeGenerator { // Inputs: // c_rarg0 - source byte array address // c_rarg1 - destination byte array address - // c_rarg2 - K (key) in little endian int array + // c_rarg2 - sessionKe (key) in little endian int array // address generate_aescrypt_encryptBlock() { assert(UseAESIntrinsics, "need AES instructions (Zvkned extension) support"); @@ -2542,7 +2542,7 @@ class StubGenerator: public StubCodeGenerator { // Inputs: // c_rarg0 - source byte array address // c_rarg1 - destination byte array address - // c_rarg2 - K (key) in little endian int array + // c_rarg2 - sessionKe (key) in little endian int array // address generate_aescrypt_decryptBlock() { assert(UseAESIntrinsics, "need AES instructions (Zvkned extension) support"); diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp index 1e728ffa279..24de32a6fe7 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp @@ -480,7 +480,7 @@ address StubGenerator::generate_counterMode_VectorAESCrypt() { // Inputs: // c_rarg0 - source byte array address // c_rarg1 - destination byte array address -// c_rarg2 - K (key) in little endian int array +// c_rarg2 - sessionKe (key) in little endian int array // c_rarg3 - counter vector byte array address // Linux // c_rarg4 - input length @@ -1063,7 +1063,7 @@ address StubGenerator::generate_cipherBlockChaining_decryptVectorAESCrypt() { // Inputs: // c_rarg0 - source byte array address // c_rarg1 - destination byte array address -// c_rarg2 - K (key) in little endian int array +// c_rarg2 - sessionKe (key) in little endian int array // address StubGenerator::generate_aescrypt_encryptBlock() { assert(UseAES, "need AES instructions and misaligned SSE support"); @@ -1158,7 +1158,7 @@ address StubGenerator::generate_aescrypt_encryptBlock() { // Inputs: // c_rarg0 - source byte array address // c_rarg1 - destination byte array address -// c_rarg2 - K (key) in little endian int array +// c_rarg2 - sessionKd (key) in little endian int array // address StubGenerator::generate_aescrypt_decryptBlock() { assert(UseAES, "need AES instructions and misaligned SSE support"); @@ -1255,7 +1255,7 @@ address StubGenerator::generate_aescrypt_decryptBlock() { // Inputs: // c_rarg0 - source byte array address // c_rarg1 - destination byte array address -// c_rarg2 - K (key) in little endian int array +// c_rarg2 - sessionKe (key) in little endian int array // c_rarg3 - r vector byte array address // c_rarg4 - input length // @@ -1407,7 +1407,7 @@ address StubGenerator::generate_cipherBlockChaining_encryptAESCrypt() { // Inputs: // c_rarg0 - source byte array address // c_rarg1 - destination byte array address -// c_rarg2 - K (key) in little endian int array +// c_rarg2 - sessionKd (key) in little endian int array // c_rarg3 - r vector byte array address // c_rarg4 - input length // diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index 7a213102efd..dc53cb08396 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -7173,6 +7173,7 @@ Node * LibraryCallKit::field_address_from_object(Node * fromObj, const char * fi bool LibraryCallKit::inline_aescrypt_Block(vmIntrinsics::ID id) { address stubAddr = nullptr; const char *stubName; + bool is_decrypt = false; assert(UseAES, "need AES instruction support"); switch(id) { @@ -7183,6 +7184,7 @@ bool LibraryCallKit::inline_aescrypt_Block(vmIntrinsics::ID id) { case vmIntrinsics::_aescrypt_decryptBlock: stubAddr = StubRoutines::aescrypt_decryptBlock(); stubName = "aescrypt_decryptBlock"; + is_decrypt = true; break; default: break; @@ -7216,7 +7218,7 @@ bool LibraryCallKit::inline_aescrypt_Block(vmIntrinsics::ID id) { // now need to get the start of its expanded key array // this requires a newer class file that has this array as littleEndian ints, otherwise we revert to java - Node* k_start = get_key_start_from_aescrypt_object(aescrypt_object); + Node* k_start = get_key_start_from_aescrypt_object(aescrypt_object, is_decrypt); if (k_start == nullptr) return false; // Call the stub. @@ -7231,7 +7233,7 @@ bool LibraryCallKit::inline_aescrypt_Block(vmIntrinsics::ID id) { bool LibraryCallKit::inline_cipherBlockChaining_AESCrypt(vmIntrinsics::ID id) { address stubAddr = nullptr; const char *stubName = nullptr; - + bool is_decrypt = false; assert(UseAES, "need AES instruction support"); switch(id) { @@ -7242,6 +7244,7 @@ bool LibraryCallKit::inline_cipherBlockChaining_AESCrypt(vmIntrinsics::ID id) { case vmIntrinsics::_cipherBlockChaining_decryptAESCrypt: stubAddr = StubRoutines::cipherBlockChaining_decryptAESCrypt(); stubName = "cipherBlockChaining_decryptAESCrypt"; + is_decrypt = true; break; default: break; @@ -7295,7 +7298,7 @@ bool LibraryCallKit::inline_cipherBlockChaining_AESCrypt(vmIntrinsics::ID id) { aescrypt_object = _gvn.transform(aescrypt_object); // we need to get the start of the aescrypt_object's expanded key array - Node* k_start = get_key_start_from_aescrypt_object(aescrypt_object); + Node* k_start = get_key_start_from_aescrypt_object(aescrypt_object, is_decrypt); if (k_start == nullptr) return false; // similarly, get the start address of the r vector @@ -7319,7 +7322,7 @@ bool LibraryCallKit::inline_cipherBlockChaining_AESCrypt(vmIntrinsics::ID id) { bool LibraryCallKit::inline_electronicCodeBook_AESCrypt(vmIntrinsics::ID id) { address stubAddr = nullptr; const char *stubName = nullptr; - + bool is_decrypt = false; assert(UseAES, "need AES instruction support"); switch (id) { @@ -7330,6 +7333,7 @@ bool LibraryCallKit::inline_electronicCodeBook_AESCrypt(vmIntrinsics::ID id) { case vmIntrinsics::_electronicCodeBook_decryptAESCrypt: stubAddr = StubRoutines::electronicCodeBook_decryptAESCrypt(); stubName = "electronicCodeBook_decryptAESCrypt"; + is_decrypt = true; break; default: break; @@ -7381,7 +7385,7 @@ bool LibraryCallKit::inline_electronicCodeBook_AESCrypt(vmIntrinsics::ID id) { aescrypt_object = _gvn.transform(aescrypt_object); // we need to get the start of the aescrypt_object's expanded key array - Node* k_start = get_key_start_from_aescrypt_object(aescrypt_object); + Node* k_start = get_key_start_from_aescrypt_object(aescrypt_object, is_decrypt); if (k_start == nullptr) return false; // Call the stub, passing src_start, dest_start, k_start, r_start and src_len @@ -7449,7 +7453,7 @@ bool LibraryCallKit::inline_counterMode_AESCrypt(vmIntrinsics::ID id) { Node* aescrypt_object = new CheckCastPPNode(control(), embeddedCipherObj, xtype); aescrypt_object = _gvn.transform(aescrypt_object); // we need to get the start of the aescrypt_object's expanded key array - Node* k_start = get_key_start_from_aescrypt_object(aescrypt_object); + Node* k_start = get_key_start_from_aescrypt_object(aescrypt_object, /* is_decrypt */ false); if (k_start == nullptr) return false; // similarly, get the start address of the r vector Node* obj_counter = load_field_from_object(counterMode_object, "counter", "[B"); @@ -7474,25 +7478,21 @@ bool LibraryCallKit::inline_counterMode_AESCrypt(vmIntrinsics::ID id) { } //------------------------------get_key_start_from_aescrypt_object----------------------- -Node * LibraryCallKit::get_key_start_from_aescrypt_object(Node *aescrypt_object) { -#if defined(PPC64) || defined(S390) || defined(RISCV64) +Node* LibraryCallKit::get_key_start_from_aescrypt_object(Node* aescrypt_object, bool is_decrypt) { // MixColumns for decryption can be reduced by preprocessing MixColumns with round keys. // Intel's extension is based on this optimization and AESCrypt generates round keys by preprocessing MixColumns. // However, ppc64 vncipher processes MixColumns and requires the same round keys with encryption. - // The ppc64 and riscv64 stubs of encryption and decryption use the same round keys (sessionK[0]). - Node* objSessionK = load_field_from_object(aescrypt_object, "sessionK", "[[I"); - assert (objSessionK != nullptr, "wrong version of com.sun.crypto.provider.AES_Crypt"); - if (objSessionK == nullptr) { - return (Node *) nullptr; - } - Node* objAESCryptKey = load_array_element(objSessionK, intcon(0), TypeAryPtr::OOPS, /* set_ctrl */ true); + // The following platform specific stubs of encryption and decryption use the same round keys. +#if defined(PPC64) || defined(S390) || defined(RISCV64) + bool use_decryption_key = false; #else - Node* objAESCryptKey = load_field_from_object(aescrypt_object, "K", "[I"); -#endif // PPC64 - assert (objAESCryptKey != nullptr, "wrong version of com.sun.crypto.provider.AES_Crypt"); + bool use_decryption_key = is_decrypt; +#endif + Node* objAESCryptKey = load_field_from_object(aescrypt_object, use_decryption_key ? "sessionKd" : "sessionKe", "[I"); + assert(objAESCryptKey != nullptr, "wrong version of com.sun.crypto.provider.AES_Crypt"); if (objAESCryptKey == nullptr) return (Node *) nullptr; - // now have the array, need to get the start address of the K array + // now have the array, need to get the start address of the selected key array Node* k_start = array_element_address(objAESCryptKey, intcon(0), T_INT); return k_start; } @@ -8628,7 +8628,7 @@ bool LibraryCallKit::inline_galoisCounterMode_AESCrypt() { Node* aescrypt_object = new CheckCastPPNode(control(), embeddedCipherObj, xtype); aescrypt_object = _gvn.transform(aescrypt_object); // we need to get the start of the aescrypt_object's expanded key array - Node* k_start = get_key_start_from_aescrypt_object(aescrypt_object); + Node* k_start = get_key_start_from_aescrypt_object(aescrypt_object, /* is_decrypt */ false); if (k_start == nullptr) return false; // similarly, get the start address of the r vector Node* cnt_start = array_element_address(counter, intcon(0), T_BYTE); diff --git a/src/hotspot/share/opto/library_call.hpp b/src/hotspot/share/opto/library_call.hpp index fbac1363dae..7dbb57c1e5c 100644 --- a/src/hotspot/share/opto/library_call.hpp +++ b/src/hotspot/share/opto/library_call.hpp @@ -338,7 +338,7 @@ class LibraryCallKit : public GraphKit { Node* inline_cipherBlockChaining_AESCrypt_predicate(bool decrypting); Node* inline_electronicCodeBook_AESCrypt_predicate(bool decrypting); Node* inline_counterMode_AESCrypt_predicate(); - Node* get_key_start_from_aescrypt_object(Node* aescrypt_object); + Node* get_key_start_from_aescrypt_object(Node* aescrypt_object, bool is_decrypt); bool inline_ghash_processBlocks(); bool inline_chacha20Block(); bool inline_kyberNtt(); diff --git a/src/java.base/share/classes/com/sun/crypto/provider/AES_Crypt.java b/src/java.base/share/classes/com/sun/crypto/provider/AES_Crypt.java index 19dceae01af..27429f6a2fd 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/AES_Crypt.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/AES_Crypt.java @@ -54,11 +54,11 @@ final class AES_Crypt extends SymmetricCipher { private int rounds; private byte[] prevKey = null; - // Following two attributes are specific to Intrinsics where sessionK is - // used for PPC64, S390, and RISCV64 architectures, whereas K is used for - // everything else. - private int[][] sessionK = null; - private int[] K = null; + // Following attributes are specific to Intrinsics, where sessionKe is the + // unprocessed key that is also used for decryption on PPC64, S390 and + // RISCV64 architectures. Other ones use sessionKd for decryption. + private int[] sessionKe = null; // key for encryption + private int[] sessionKd = null; // preprocessed key for decryption // Round constant private static final int[] RCON = { @@ -904,7 +904,6 @@ final class AES_Crypt extends SymmetricCipher { */ void init(boolean decrypting, String algorithm, byte[] key) throws InvalidKeyException { - int decrypt = decrypting ? 1 : 0; if (!algorithm.equalsIgnoreCase("AES") && !algorithm.equalsIgnoreCase("Rijndael")) { @@ -920,21 +919,25 @@ final class AES_Crypt extends SymmetricCipher { throw new InvalidKeyException("Invalid key length (" + key.length + ")."); } + if (!MessageDigest.isEqual(prevKey, key)) { - if (sessionK == null) { - sessionK = new int[2][]; - } else { - Arrays.fill(sessionK[0], 0); - Arrays.fill(sessionK[1], 0); + if (sessionKe != null) { + Arrays.fill(sessionKe, 0); + } + sessionKe = genRoundKeys(key, rounds); + if (sessionKd != null) { + Arrays.fill(sessionKd, 0); + sessionKd = null; } - sessionK[0] = genRoundKeys(key, rounds); - sessionK[1] = genInvRoundKeys(sessionK[0], rounds); if (prevKey != null) { Arrays.fill(prevKey, (byte) 0); } prevKey = key.clone(); } - K = sessionK[decrypt]; + + if (decrypting && (sessionKd == null)) { + sessionKd = genInvRoundKeys(sessionKe, rounds); + } } /** @@ -1035,6 +1038,7 @@ final class AES_Crypt extends SymmetricCipher { */ @IntrinsicCandidate private void implEncryptBlock(byte[] p, int po, byte[] c, int co) { + int[] K = sessionKe; int ti0, ti1, ti2, ti3; int a0, a1, a2, a3; int w = K.length - WB; @@ -1213,6 +1217,7 @@ final class AES_Crypt extends SymmetricCipher { */ @IntrinsicCandidate private void implDecryptBlock(byte[] c, int co, byte[] p, int po) { + int[] K = sessionKd; int ti0, ti1, ti2, ti3; int a0, a1, a2, a3; From b97ed667db0bd527461b2b385af3001f53d71c19 Mon Sep 17 00:00:00 2001 From: Xueming Shen Date: Tue, 2 Dec 2025 19:47:18 +0000 Subject: [PATCH 102/706] 8365675: Add String Unicode Case-Folding Support Reviewed-by: rriggs, naoto, ihse --- make/ToolsJdk.gmk | 2 +- .../tools/generatecharacter/CaseFolding.java | 73 ---- .../GenerateCaseFolding.java | 134 +++++++ .../java.base/gensrc/GensrcCharacterData.gmk | 17 + make/modules/java.base/gensrc/GensrcRegex.gmk | 17 - .../share/classes/java/lang/String.java | 161 ++++++++- .../share/classes/java/lang/StringLatin1.java | 124 +++++++ .../share/classes/java/lang/StringUTF16.java | 74 +++- .../classes/java/util/regex/Pattern.java | 2 +- .../internal/lang/CaseFolding.java.template | 208 +++++++++++ .../util/regex/CaseFolding.java.template | 116 ------ .../lang/String/UnicodeCaseFoldingTest.java | 329 ++++++++++++++++++ .../java/lang/StringCompareToFoldCase.java | 200 +++++++++++ 13 files changed, 1245 insertions(+), 212 deletions(-) delete mode 100644 make/jdk/src/classes/build/tools/generatecharacter/CaseFolding.java create mode 100644 make/jdk/src/classes/build/tools/generatecharacter/GenerateCaseFolding.java create mode 100644 src/java.base/share/classes/jdk/internal/lang/CaseFolding.java.template delete mode 100644 src/java.base/share/classes/jdk/internal/util/regex/CaseFolding.java.template create mode 100644 test/jdk/java/lang/String/UnicodeCaseFoldingTest.java create mode 100644 test/micro/org/openjdk/bench/java/lang/StringCompareToFoldCase.java diff --git a/make/ToolsJdk.gmk b/make/ToolsJdk.gmk index 629cadbf83a..b04d7820c91 100644 --- a/make/ToolsJdk.gmk +++ b/make/ToolsJdk.gmk @@ -79,7 +79,7 @@ TOOL_GENERATEEXTRAPROPERTIES = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_too build.tools.generateextraproperties.GenerateExtraProperties TOOL_GENERATECASEFOLDING = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \ - build.tools.generatecharacter.CaseFolding + build.tools.generatecharacter.GenerateCaseFolding TOOL_MAKEZIPREPRODUCIBLE = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \ build.tools.makezipreproducible.MakeZipReproducible diff --git a/make/jdk/src/classes/build/tools/generatecharacter/CaseFolding.java b/make/jdk/src/classes/build/tools/generatecharacter/CaseFolding.java deleted file mode 100644 index 9abc2059b6a..00000000000 --- a/make/jdk/src/classes/build/tools/generatecharacter/CaseFolding.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2025, 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 build.tools.generatecharacter; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.nio.file.StandardOpenOption; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -public class CaseFolding { - - public static void main(String[] args) throws Throwable { - if (args.length != 3) { - System.err.println("Usage: java CaseFolding TemplateFile CaseFolding.txt CaseFolding.java"); - System.exit(1); - } - var templateFile = Paths.get(args[0]); - var caseFoldingTxt = Paths.get(args[1]); - var genSrcFile = Paths.get(args[2]); - var supportedTypes = "^.*; [CTS]; .*$"; - var caseFoldingEntries = Files.lines(caseFoldingTxt) - .filter(line -> !line.startsWith("#") && line.matches(supportedTypes)) - .map(line -> { - String[] cols = line.split("; "); - return new String[] {cols[0], cols[1], cols[2]}; - }) - .filter(cols -> { - // the folding case doesn't map back to the original char. - var cp1 = Integer.parseInt(cols[0], 16); - var cp2 = Integer.parseInt(cols[2], 16); - return Character.toUpperCase(cp2) != cp1 && Character.toLowerCase(cp2) != cp1; - }) - .map(cols -> String.format(" entry(0x%s, 0x%s)", cols[0], cols[2])) - .collect(Collectors.joining(",\n", "", "")); - - // hack, hack, hack! the logic does not pick 0131. just add manually to support 'I's. - // 0049; T; 0131; # LATIN CAPITAL LETTER I - final String T_0x0131_0x49 = String.format(" entry(0x%04x, 0x%04x),\n", 0x0131, 0x49); - - // Generate .java file - Files.write( - genSrcFile, - Files.lines(templateFile) - .map(line -> line.contains("%%%Entries") ? T_0x0131_0x49 + caseFoldingEntries : line) - .collect(Collectors.toList()), - StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING); - } -} diff --git a/make/jdk/src/classes/build/tools/generatecharacter/GenerateCaseFolding.java b/make/jdk/src/classes/build/tools/generatecharacter/GenerateCaseFolding.java new file mode 100644 index 00000000000..2f6a9add5cb --- /dev/null +++ b/make/jdk/src/classes/build/tools/generatecharacter/GenerateCaseFolding.java @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2025, 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 build.tools.generatecharacter; + +import java.nio.file.Files; +import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; +import java.util.Arrays; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +public class GenerateCaseFolding { + + public static void main(String[] args) throws Throwable { + if (args.length != 3) { + System.err.println("Usage: java GenerateCaseFolding TemplateFile CaseFolding.txt CaseFolding.java"); + System.exit(1); + } + var templateFile = Paths.get(args[0]); + var caseFoldingTxt = Paths.get(args[1]); + var genSrcFile = Paths.get(args[2]); + + // java.lang + var supportedTypes = "^.*; [CF]; .*$"; // full/1:M case folding + String[][] caseFoldings = Files.lines(caseFoldingTxt) + .filter(line -> !line.startsWith("#") && line.matches(supportedTypes)) + .map(line -> { + var fields = line.split("; "); + var cp = fields[0]; + fields = fields[2].trim().split(" "); + var folding = new String[fields.length + 1]; + folding[0] = cp; + System.arraycopy(fields, 0, folding, 1, fields.length); + return folding; + }) + .toArray(size -> new String[size][]); + + // util.regex + var expandedSupportedTypes = "^.*; [CTS]; .*$"; + var expanded_caseFoldingEntries = Files.lines(caseFoldingTxt) + .filter(line -> !line.startsWith("#") && line.matches(expandedSupportedTypes)) + .map(line -> { + String[] cols = line.split("; "); + return new String[]{cols[0], cols[1], cols[2]}; + }) + .filter(cols -> { + // the folding case doesn't map back to the original char. + var cp1 = Integer.parseInt(cols[0], 16); + var cp2 = Integer.parseInt(cols[2], 16); + return Character.toUpperCase(cp2) != cp1 && Character.toLowerCase(cp2) != cp1; + }) + .map(cols -> String.format(" entry(0x%s, 0x%s)", cols[0], cols[2])) + .collect(Collectors.joining(",\n", "", "")); + + // hack, hack, hack! the logic does not pick 0131. just add manually to support 'I's. + // 0049; T; 0131; # LATIN CAPITAL LETTER I + final String T_0x0131_0x49 = String.format(" entry(0x%04x, 0x%04x),\n", 0x0131, 0x49); + + Files.write( + genSrcFile, + Files.lines(templateFile) + .map(line -> line.contains("%%%Entries") ? genFoldingEntries(caseFoldings) : line) + .map(line -> line.contains("%%%Expanded_Case_Map_Entries") ? T_0x0131_0x49 + expanded_caseFoldingEntries : line) + .collect(Collectors.toList()), + StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING); + } + + private static long foldingToLong(String[] folding) { + int cp = Integer.parseInt(folding[0], 16); + long value = (long)Integer.parseInt(folding[1], 16); + if (!Character.isSupplementaryCodePoint(cp) && folding.length != 2) { + var shift = 16; + for (int j = 2; j < folding.length; j++) { + value |= (long)Integer.parseInt(folding[j], 16) << shift; + shift <<= 1; + } + value = value | (long) (folding.length - 1) << 48; + } + return value; + } + + private static String genFoldingEntries(String[][] foldings) { + StringBuilder sb = new StringBuilder(); + sb.append(" private static final int[] CASE_FOLDING_CPS = {\n"); + int width = 10; + for (int i = 0; i < foldings.length; i++) { + if (i % width == 0) + sb.append(" "); + sb.append(String.format("0X%s", foldings[i][0])); + if (i < foldings.length - 1) + sb.append(", "); + if (i % width == width - 1 || i == foldings.length - 1) + sb.append("\n"); + } + sb.append(" };\n\n"); + + sb.append(" private static final long[] CASE_FOLDING_VALUES = {\n"); + width = 6; + for (int i = 0; i < foldings.length; i++) { + if (i % width == 0) + sb.append(" "); // indent + sb.append(String.format("0x%013xL", foldingToLong(foldings[i]))); + if (i < foldings.length - 1) + sb.append(", "); + if (i % width == width - 1 || i == foldings.length - 1) { + sb.append("\n"); + } + } + sb.append(" };\n"); + return sb.toString(); + } +} diff --git a/make/modules/java.base/gensrc/GensrcCharacterData.gmk b/make/modules/java.base/gensrc/GensrcCharacterData.gmk index c05b126299b..d7947d907e2 100644 --- a/make/modules/java.base/gensrc/GensrcCharacterData.gmk +++ b/make/modules/java.base/gensrc/GensrcCharacterData.gmk @@ -72,5 +72,22 @@ TARGETS += $(GENSRC_CHARACTERDATA) ################################################################################ + +GENSRC_STRINGCASEFOLDING := $(SUPPORT_OUTPUTDIR)/gensrc/java.base/jdk/internal/lang/CaseFolding.java + +STRINGCASEFOLDING_TEMPLATE := $(MODULE_SRC)/share/classes/jdk/internal/lang/CaseFolding.java.template +CASEFOLDINGTXT := $(MODULE_SRC)/share/data/unicodedata/CaseFolding.txt + +$(GENSRC_STRINGCASEFOLDING): $(BUILD_TOOLS_JDK) $(STRINGCASEFOLDING_TEMPLATE) $(CASEFOLDINGTXT) + $(call LogInfo, Generating $@) + $(call MakeTargetDir) + $(TOOL_GENERATECASEFOLDING) \ + $(STRINGCASEFOLDING_TEMPLATE) \ + $(CASEFOLDINGTXT) \ + $(GENSRC_STRINGCASEFOLDING) + +TARGETS += $(GENSRC_STRINGCASEFOLDING) + + endif # include guard include MakeIncludeEnd.gmk diff --git a/make/modules/java.base/gensrc/GensrcRegex.gmk b/make/modules/java.base/gensrc/GensrcRegex.gmk index a30f22b34d4..c46a029e2c2 100644 --- a/make/modules/java.base/gensrc/GensrcRegex.gmk +++ b/make/modules/java.base/gensrc/GensrcRegex.gmk @@ -50,22 +50,5 @@ TARGETS += $(GENSRC_INDICCONJUNCTBREAK) ################################################################################ -GENSRC_CASEFOLDING := $(SUPPORT_OUTPUTDIR)/gensrc/java.base/jdk/internal/util/regex/CaseFolding.java - -CASEFOLDINGTEMP := $(MODULE_SRC)/share/classes/jdk/internal/util/regex/CaseFolding.java.template -CASEFOLDINGTXT := $(MODULE_SRC)/share/data/unicodedata/CaseFolding.txt - -$(GENSRC_CASEFOLDING): $(BUILD_TOOLS_JDK) $(CASEFOLDINGTEMP) $(CASEFOLDINGTXT) - $(call LogInfo, Generating $@) - $(call MakeTargetDir) - $(TOOL_GENERATECASEFOLDING) \ - $(CASEFOLDINGTEMP) \ - $(CASEFOLDINGTXT) \ - $(GENSRC_CASEFOLDING) - -TARGETS += $(GENSRC_CASEFOLDING) - -################################################################################ - endif # include guard include MakeIncludeEnd.gmk diff --git a/src/java.base/share/classes/java/lang/String.java b/src/java.base/share/classes/java/lang/String.java index 52f908c9e98..d7aef113e15 100644 --- a/src/java.base/share/classes/java/lang/String.java +++ b/src/java.base/share/classes/java/lang/String.java @@ -117,9 +117,38 @@ import sun.nio.cs.UTF_8; * Unicode code points (i.e., characters), in addition to those for * dealing with Unicode code units (i.e., {@code char} values). * - *

    Unless otherwise noted, methods for comparing Strings do not take locale - * into account. The {@link java.text.Collator} class provides methods for - * finer-grain, locale-sensitive String comparison. + *

    String comparison and case-insensitive matching + * + *

    There are several related ways to compare {@code String} values; choose + * the one whose semantics fit your purpose: + * + *

      + *
    • Exact content equality — {@link #equals(Object)} checks that two + * strings contain the identical char sequence of UTF-16 code units. This is + * a strict, case-sensitive comparison suitable for exact matching, hashing + * and any situation that requires bit-for-bit stability.
    • + * + *
    • Simple case-insensitive equality — {@link #equalsIgnoreCase(String)} + * (and the corresponding {@link #compareToIgnoreCase(String)} and {@link #CASE_INSENSITIVE_ORDER}) + * performs a per-code-point, locale-independent comparison using + * {@link Character#toUpperCase(int)} and {@link Character#toLowerCase(int)}. + * It is convenient for many common case-insensitive checks.
    • + * + *
    • Unicode case-folded equivalence — {@link #equalsFoldCase(String)} + * (and the corresponding {@link #compareToFoldCase(String)} and {@link #UNICODE_CASEFOLD_ORDER}) + * implement the Unicode {@index "full case folding"} rules defined in + * Unicode CaseFolding.txt. + * Case folding is locale-independent and language-neutral and may map a single code + * point to multiple code points (1:M mappings). For example, the German sharp + * s ({@code U+00DF}) is folded to the sequence {@code "ss"}. + * Use these methods when you need Unicode-compliant + * + * caseless matching, searching, or ordering.
    • + *
    + * + *

    Unless otherwise noted, methods for comparing Strings do not take locale into + * account. The {@link java.text.Collator} class provides methods for finer-grain, + * locale-sensitive String comparison. * * @implNote The implementation of the string concatenation operator is left to * the discretion of a Java compiler, as long as the compiler ultimately conforms @@ -2179,6 +2208,7 @@ public final class String * false} otherwise * * @see #equals(Object) + * @see #equalsFoldCase(String) * @see #codePoints() */ public boolean equalsIgnoreCase(String anotherString) { @@ -2188,6 +2218,57 @@ public final class String && regionMatches(true, 0, anotherString, 0, length()); } + /** + * Compares this {@code String} to another {@code String} for equality, + * using {@index "Unicode case folding"}. Two strings are considered equal + * by this method if their case-folded forms are identical. + *

    + * Case folding is defined by the Unicode Standard in + * CaseFolding.txt, + * including 1:M mappings. For example, {@code "Fuß".equalsFoldCase("FUSS")} + * returns {@code true}, since the character {@code U+00DF} (sharp s) folds + * to {@code "ss"}. + *

    + * Case folding is locale-independent and language-neutral, unlike + * locale-sensitive transformations such as {@link #toLowerCase()} or + * {@link #toUpperCase()}. It is intended for caseless matching, + * searching, and indexing. + * + * @apiNote + * This method is the Unicode-compliant alternative to + * {@link #equalsIgnoreCase(String)}. It implements full case folding as + * defined by the Unicode Standard, which may differ from the simpler + * per-character mapping performed by {@code equalsIgnoreCase}. + * For example: + * {@snippet lang=java : + * String a = "Fuß"; + * String b = "FUSS"; + * boolean equalsFoldCase = a.equalsFoldCase(b); // returns true + * boolean equalsIgnoreCase = a.equalsIgnoreCase(b); // returns false + * } + * + * @param anotherString + * The {@code String} to compare this {@code String} against + * + * @return {@code true} if the given object is not {@code null} and represents + * the same sequence of characters as this string under Unicode case + * folding; {@code false} otherwise. + * + * @spec https://www.unicode.org/versions/latest/core-spec/chapter-5/#G21790 Unicode Caseless Matching + * @see #compareToFoldCase(String) + * @see #equalsIgnoreCase(String) + * @since 26 + */ + public boolean equalsFoldCase(String anotherString) { + if (this == anotherString) { + return true; + } + if (anotherString == null) { + return false; + } + return UNICODE_CASEFOLD_ORDER.compare(this, anotherString) == 0; + } + /** * Compares two strings lexicographically. * The comparison is based on the Unicode value of each character in @@ -2303,12 +2384,86 @@ public final class String * than this String, ignoring case considerations. * @see java.text.Collator * @see #codePoints() + * @see #compareToFoldCase(String) * @since 1.2 */ public int compareToIgnoreCase(String str) { return CASE_INSENSITIVE_ORDER.compare(this, str); } + /** + * A Comparator that orders {@code String} objects as by + * {@link #compareToFoldCase(String) compareToFoldCase()}. + * + * @see #compareToFoldCase(String) + * @since 26 + */ + public static final Comparator UNICODE_CASEFOLD_ORDER + = new FoldCaseComparator(); + + private static class FoldCaseComparator implements Comparator { + + @Override + public int compare(String s1, String s2) { + byte[] v1 = s1.value; + byte[] v2 = s2.value; + if (s1.coder == s2.coder()) { + return s1.coder == LATIN1 ? StringLatin1.compareToFC(v1, v2) + : StringUTF16.compareToFC(v1, v2); + } + return s1.coder == LATIN1 ? StringLatin1.compareToFC_UTF16(v1, v2) + : StringUTF16.compareToFC_Latin1(v1, v2); + } + } + + /** + * Compares two strings lexicographically using {@index "Unicode case folding"}. + * This method returns an integer whose sign is that of calling {@code compareTo} + * on the Unicode case folded version of the strings. Unicode Case folding + * eliminates differences in case according to the Unicode Standard, using the + * mappings defined in + * CaseFolding.txt, + * including 1:M mappings, such as {@code"ß"} → {@code }"ss"}. + *

    + * Case folding is a locale-independent, language-neutral form of case mapping, + * primarily intended for caseless matching. Unlike {@link #compareToIgnoreCase(String)}, + * which applies a simpler locale-insensitive uppercase mapping. This method + * follows the Unicode {@index "full"} case folding, providing stable and + * consistent results across all environments. + *

    + * Note that this method does not take locale into account, and may + * produce results that differ from locale-sensitive ordering. Use + * {@link java.text.Collator} for locale-sensitive comparison. + * + * @apiNote + * This method is the Unicode-compliant alternative to + * {@link #compareToIgnoreCase(String)}. It implements the + * {@index "full case folding"} as defined by the Unicode Standard, which + * may differ from the simpler per-character mapping performed by + * {@code compareToIgnoreCase}. + * For example: + * {@snippet lang=java : + * String a = "Fuß"; + * String b = "FUSS"; + * int cmpFoldCase = a.compareToFoldCase(b); // returns 0 + * int cmpIgnoreCase = a.compareToIgnoreCase(b); // returns > 0 + * } + * + * @param str the {@code String} to be compared. + * @return a negative integer, zero, or a positive integer as the specified + * String is greater than, equal to, or less than this String, + * ignoring case considerations by case folding. + * + * @spec https://www.unicode.org/versions/latest/core-spec/chapter-5/#G21790 Unicode Caseless Matching + * @see java.text.Collator + * @see #compareToIgnoreCase(String) + * @see #equalsFoldCase(String) + * @since 26 + */ + public int compareToFoldCase(String str) { + return UNICODE_CASEFOLD_ORDER.compare(this, str); + } + /** * Tests if two string regions are equal. *

    diff --git a/src/java.base/share/classes/java/lang/StringLatin1.java b/src/java.base/share/classes/java/lang/StringLatin1.java index 61c62d049bc..21a8b2dd61a 100644 --- a/src/java.base/share/classes/java/lang/StringLatin1.java +++ b/src/java.base/share/classes/java/lang/StringLatin1.java @@ -32,6 +32,8 @@ import java.util.function.Consumer; import java.util.function.IntConsumer; import java.util.stream.Stream; import java.util.stream.StreamSupport; + +import jdk.internal.lang.CaseFolding; import jdk.internal.util.ArraysSupport; import jdk.internal.vm.annotation.IntrinsicCandidate; @@ -179,6 +181,128 @@ final class StringLatin1 { return len1 - len2; } + private static int compareToFC0(byte[] value, int off, int last, byte[] other, int ooff, int olast) { + int k1 = off, k2 = ooff; + boolean lo1 = false, lo2 = false; // true if we have a leftover 's' from u+00df -> ss + while ((k1 < last || lo1) && (k2 < olast || lo2)) { + int c1, c2; + if (lo1) { + c1 = 0x73; // leftover 's' + lo1 = false; + } else { + c1 = getChar(value, k1++); + if (c1 == 0xdf) { + c1 = 0x73; + lo1 = true; + } + } + if (lo2) { + c2 = 0x73; // 's' + lo2 = false; + } else { + c2 = getChar(other, k2++); + if (c2 == 0xdf) { + c2 = 0x73; + lo2 = true; + } + } + if (!CharacterDataLatin1.equalsIgnoreCase((byte)c1, (byte)c2)) { + return Character.toLowerCase(c1) - Character.toLowerCase(c2); + } + } + if (k1 < last || lo1) { + return 1; + } + if (k2 < olast || lo2) { + return -1; + } + return 0; + } + + static int compareToFC(byte[] value, byte[] other) { + int len = value.length; + int olen = other.length; + int lim = Math.min(len, olen); + for (int k = 0; k < lim; k++) { + byte b1 = value[k]; + byte b2 = other[k]; + if (!CharacterDataLatin1.equalsIgnoreCase(b1, b2)) { + int c1 = b1 & 0xff; + int c2 = b2 & 0xff; + if (c1 == 0xdf || c2 == 0xdf) { // 0xdf is the only 1:M in latin1 range + return compareToFC0(value, k, len, other, k, olen); + } + return Character.toLowerCase(c1) - Character.toLowerCase(c2); + } + } + return len - olen; + } + + private static int compareToFC0_UTF16(byte[] value, int off, int last, byte[] other, int ooff, int olast) { + int f1 = 0, f2 = 0; + int k1 = off, k2 = ooff; + while ((k1 < last || f1 != 0) && (k2 < olast || f2 != 0)) { + int c1, c2; + if (f1 != 0) { + c1 = (f1 & 0xffff); f1 >>>= 16; + } else { + c1 = getChar(value, k1++); + var f = CaseFolding.fold(c1); + if (CaseFolding.isSingleCodePoint(f)) { + c1 = (int)(f & 0xfffff); + } else { + c1 = (int)f & 0xffff; + f1 = (int)(f >>> 16); + } + } + if (f2 != 0) { + c2 = f2 & 0xffff; f2 >>>= 16; + } else { + c2 = StringUTF16.codePointAt(other, k2, olast, true); + k2 += Character.charCount(c2); + var f = CaseFolding.fold(c2); + if (CaseFolding.isSingleCodePoint(f)) { + c2 = (int)(f & 0xfffff); + } else { + c2 = (int)(f & 0xffff); + f2 = (int)(f >>> 16); + } + } + if (c1 != c2) { + return c1 - c2; + } + } + if (k1 < last || f1 != 0) { + return 1; + } + if (k2 < olast || f2 != 0) { + return -1; + } + return 0; + } + + // latin1 vs utf16 + static int compareToFC_UTF16(byte[] value, byte[] other) { + int last = length(value); + int olast = StringUTF16.length(other); + int lim = Math.min(last, olast); + for (int k = 0; k < lim; k++) { + int cp1 = getChar(value, k); + int cp2 = StringUTF16.codePointAt(other, k, olast, true); + if (cp1 != cp2) { + long cf1 = CaseFolding.fold(cp1); + long cf2 = CaseFolding.fold(cp2); + if (cf1 != cf2) { + if (!CaseFolding.isSingleCodePoint(cf1) || !CaseFolding.isSingleCodePoint(cf2)) { + return compareToFC0_UTF16(value, k, last, other, k, olast); + } + return (int)(cf1 - cf2); + } + } + } + return last - olast; + } + static int hashCode(byte[] value) { return ArraysSupport.hashCodeOfUnsigned(value, 0, value.length, 0); } diff --git a/src/java.base/share/classes/java/lang/StringUTF16.java b/src/java.base/share/classes/java/lang/StringUTF16.java index 4e31c9728e9..75c9e8239ba 100644 --- a/src/java.base/share/classes/java/lang/StringUTF16.java +++ b/src/java.base/share/classes/java/lang/StringUTF16.java @@ -34,6 +34,7 @@ import java.util.function.IntConsumer; import java.util.stream.Stream; import java.util.stream.StreamSupport; +import jdk.internal.lang.CaseFolding; import jdk.internal.misc.Unsafe; import jdk.internal.util.ArraysSupport; import jdk.internal.vm.annotation.ForceInline; @@ -93,7 +94,7 @@ final class StringUTF16 { return value.length >> 1; } - private static int codePointAt(byte[] value, int index, int end, boolean checked) { + static int codePointAt(byte[] value, int index, int end, boolean checked) { assert index < end; if (checked) { checkIndex(index, value); @@ -592,6 +593,77 @@ final class StringUTF16 { return -StringLatin1.compareToCI_UTF16(other, value); } + public static int compareToFC_Latin1(byte[] value, byte[] other) { + return -StringLatin1.compareToFC_UTF16(other, value); + } + + private static int compareToFC0(byte[] value, int off, int last, byte[] other, int ooff, int olast) { + int f1 = 0, f2 = 0; + int k1 = off, k2 = ooff; + while ((k1 < last || f1 != 0) && (k2 < olast || f2 != 0)) { + int c1, c2; + if (f1 != 0) { + c1 = f1 & 0xffff; f1 >>>= 16; + } else { + c1 = StringUTF16.codePointAt(value, k1, last, true); + k1 += Character.charCount(c1); + var f = CaseFolding.fold(c1); + if (CaseFolding.isSingleCodePoint(f)) { + c1 = (int)(f & 0xfffff); + } else { + c1 = (int)(f & 0xffff); + f1 = (int)(f >> 16); + } + } + if (f2 != 0) { + c2 = f2 & 0xffff; f2 >>>= 16; + } else { + c2 = StringUTF16.codePointAt(other, k2, olast, true); + k2 += Character.charCount(c2); + var f = CaseFolding.fold(c2); + if (CaseFolding.isSingleCodePoint(f)) { + c2 = (int)(f & 0xfffff); + } else { + c2 = (int)(f & 0xffff); + f2 = (int)(f >>> 16); + } + } + if (c1 != c2) { + return c1 - c2; + } + } + if (k1 < last || f1 != 0) { + return 1; + } + if (k2 < olast || f2 != 0) { + return -1; + } + return 0; + } + + public static int compareToFC(byte[] value, byte[] other) { + int tlast = length(value); + int olast = length(other); + int lim = Math.min(tlast, olast); + int k = 0; + while (k < lim) { + int cp1 = codePointAt(value, k, tlast, true); + int cp2 = codePointAt(other, k, olast, true); + if (cp1 != cp2) { + long cf1 = CaseFolding.fold(cp1); + long cf2 = CaseFolding.fold(cp2); + if (cf1 != cf2) { + if (!CaseFolding.isSingleCodePoint(cf1) || !CaseFolding.isSingleCodePoint(cf2)) { + return compareToFC0(value, k, tlast, other, k, olast); + } + return (int) cf1 - (int) cf2; + } + } + k += Character.charCount(cp1); + } + return tlast - olast; + } + static int hashCode(byte[] value) { return ArraysSupport.hashCodeOfUTF16(value, 0, value.length >> 1, 0); } diff --git a/src/java.base/share/classes/java/util/regex/Pattern.java b/src/java.base/share/classes/java/util/regex/Pattern.java index 2908370acd5..58c9186924b 100644 --- a/src/java.base/share/classes/java/util/regex/Pattern.java +++ b/src/java.base/share/classes/java/util/regex/Pattern.java @@ -43,8 +43,8 @@ import java.util.function.Predicate; import java.util.stream.Stream; import java.util.stream.StreamSupport; +import jdk.internal.lang.CaseFolding; import jdk.internal.util.ArraysSupport; -import jdk.internal.util.regex.CaseFolding; import jdk.internal.util.regex.Grapheme; /** diff --git a/src/java.base/share/classes/jdk/internal/lang/CaseFolding.java.template b/src/java.base/share/classes/jdk/internal/lang/CaseFolding.java.template new file mode 100644 index 00000000000..24a183c8da0 --- /dev/null +++ b/src/java.base/share/classes/jdk/internal/lang/CaseFolding.java.template @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2025, 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.lang; + +import java.util.Arrays; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +import static java.util.Map.entry; + +/** + * Utility class that handles Unicode case folding properties defined in + * CasingFolding.txt, including 1:M full case folding. + */ +public final class CaseFolding { + + private CaseFolding() {} + + /** + * Tests whether the specified code point has a folding mapping entry defined. + * + * @param cp + * the Unicode code point to test + * @return {@code true} if the given code point has a case folding mapping entry + * defined in (@code caseFoldingMap}, {@code false} otherwise + */ + public static boolean isDefined(int cp) { + return getDefined(cp) != -1; + } + + /** + * Returns the case-folded form of the specified code point according + * to the Unicode case folding mappings. + *

    + * If the code point has no case folding mapping defined, this method returns + * the original code point. + * + * Possible combinations of the returning case-folding form as a long value + * + * +---+---------+--------+---------+--------+--------+ + * | 1:1 mapping | 0000 | 0000 | 000x | xxxx | 0041 => 0061 or 1E921 => 1E943 + * +---+---------+--------+---------+--------+--------+ + * | 1:2 mapping | 0002 | 0000 | xxxx | xxxx | FB02 => 0066 006C + * +---+---------+--------+---------+--------+--------+ + * | 1:3 mapping | 0003 | xxxx | xxxx | xxxx | FB03 => 0066 0066 0069 + * +---+---------+--------+---------+--------+--------+ + * + * @param cp + * the Unicode code point to fold + * @return a long value representing the case-folded form of the input + * code point, encoded as TBD + */ + public static long fold(int cp) { + var fold = getDefined(cp); + return fold == -1 ? cp : fold; + } + + public static boolean isSingleCodePoint(long fold) { + return (fold >> 48) == 0; + } + + /** + * Returns an expansion set to "close" a given regex Unicode character class range for case-sensitive + * matching, according to the + * Simple Loose Matches + * rule defined in Unicode Technical Standard #18: Unicode Regular Expressions. + *

    + * To conform with Level 1 of UTS #18, specifically RL1.5: Simple Loose Matches, simple case folding must + * be applied to literals and (optionally) to character classes. When applied to character classes, each + * character class is expected to be closed under simple case folding. See the standard for the + * detailed explanation and example of "closed". + *

    + * RL1.5 states: To meet this requirement, an implementation that supports case-sensitive matching should + *

      + *
    1. Provide at least the simple, default Unicode case-insensitive matching, and
    2. + *
    3. Specify which character properties or constructs are closed under the matching.
    4. + *
    + *

    + * In the {@code Pattern} implementation, 5 types of constructs maybe case-sensitive when matching: + * back-refs, string slice (sequences), single, family(char-property) and class range. Single and + * family may appears independently or within a class. + *

    + * For loose/case-insensitive matching, the back-refs, slices and singles apply {@code toUpperCase} and + * {@code toLowerCase} to both the pattern and the input string. This effectively 'close' the class for + * matching. + *

    + * The family/char-properties are not "closed" and should remain unchanged. This is acceptable per RL1.5, + * if their behavior is clearly specified. + *

    + * This method addresses that requirement for the "range" construct within in character class by computing + * the additional characters that should be included to close the range under simple case folding: + *

    + * For each character in the input range {@code [start, end]} (inclusive), if the character has a simple + * case folding mapping in Unicode's CaseFolding.txt, the mapping is not a round-trip map, and the mapped + * character is not already in the range, then that mapped character (typically lowercase) is added to + * the expansion set. + *

    + * This allows regex character class "range" implementation to use the returned expansion set to support + * additional case-insensitive matching, without duplicating characters already covered by the existing + * regex range implementation. The expectation is the matching is done using both the uppercase and + * lowercase forms of the input character, for example + * + *

    {@code
    +    *
    +    *     ch -> inRange(lower, Character.toUpperCase(ch), upper) ||
    +    *           inRange(lower, Character.toLower(ch), upper) ||
    +    *           additionalClosingCharacters.contains(Character.toUpperCase(ch)) ||
    +    *           additionalClosingCharacters.contains(Character.toUpperCase(ch))
    +    * }
    + * + * @param start the starting code point of the character range + * @param end the ending code point of the character range + * @return a {@code int[]} containing the all simple case equivalents of characters in the range, excluding + * those already in the range + * @spec https://www.unicode.org/reports/tr18/#Simple_Loose_Matches + */ + public static int[] getClassRangeClosingCharacters(int start, int end) { + int[] expanded = new int[expanded_case_cps.length]; + int off = 0; + for (int cp : expanded_case_cps) { + if (cp >= start && cp <= end) { + int folding = expanded_case_map.get(cp); + if (folding < start || folding > end) { + expanded[off++] = folding; + } + } + } + return Arrays.copyOf(expanded, off); + } + + private static final Map expanded_case_map = Map.ofEntries( +%%%Expanded_Case_Map_Entries + ); + + private static final int[] expanded_case_cps = expanded_case_map.keySet() + .stream() + .mapToInt(Integer::intValue) + .toArray(); + + private static final int HASH_CP = 0; + private static final int HASH_INDEX = 1; + private static final int HASH_NEXT = 2; + + private static int[][] hashKeys(int[] keys) { + var hashes = new int[keys.length << 1][3]; // cp + hash + next + var off = keys.length; + for (int i = 0; i < keys.length; i++) { + var cp = keys[i]; + var hash = cp % keys.length; + while (hashes[hash][HASH_CP] != 0) { + var next = hashes[hash][HASH_NEXT]; + if (next == 0) { + hashes[hash][HASH_NEXT] = off; + hash = off++; + break; + } else { + hash = next; + } + } + hashes[hash][HASH_CP] = cp; + hashes[hash][HASH_INDEX] = i; + } + return Arrays.copyOf(hashes, off); + } + + private static long getDefined(int cp) { + var hashes = CASE_FOLDING_HASHES; + var length = CASE_FOLDING_CPS.length; // hashed based on total defined. + var hash = cp % length; + while (hashes[hash][HASH_CP] != cp) { + var next = hashes[hash][HASH_NEXT]; + if (next == 0) { + return -1; // hash miss + } + hash = next; + } + var index = hashes[hash][HASH_INDEX]; + return CASE_FOLDING_VALUES[index]; + } + +%%%Entries + + private static final int[][] CASE_FOLDING_HASHES = hashKeys(CASE_FOLDING_CPS); +} diff --git a/src/java.base/share/classes/jdk/internal/util/regex/CaseFolding.java.template b/src/java.base/share/classes/jdk/internal/util/regex/CaseFolding.java.template deleted file mode 100644 index 8ffbde6c535..00000000000 --- a/src/java.base/share/classes/jdk/internal/util/regex/CaseFolding.java.template +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (c) 2025, 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.util.regex; - -import java.util.Arrays; -import java.util.Map; -import java.util.Objects; - -import static java.util.Map.entry; - -public final class CaseFolding { - - private static final Map expanded_case_map = Map.ofEntries( -%%%Entries - ); - - private static final int[] expanded_case_cps = expanded_case_map.keySet() - .stream() - .mapToInt(Integer::intValue) - .toArray(); - - private CaseFolding() {} - - /** - * Returns an expansion set to "close" a given regex Unicode character class range for case-sensitive - * matching, according to the - * Simple Loose Matches - * rule defined in Unicode Technical Standard #18: Unicode Regular Expressions. - *

    - * To conform with Level 1 of UTS #18, specifically RL1.5: Simple Loose Matches, simple case folding must - * be applied to literals and (optionally) to character classes. When applied to character classes, each - * character class is expected to be closed under simple case folding. See the standard for the - * detailed explanation and example of "closed". - *

    - * RL1.5 states: To meet this requirement, an implementation that supports case-sensitive matching should - *

      - *
    1. Provide at least the simple, default Unicode case-insensitive matching, and
    2. - *
    3. Specify which character properties or constructs are closed under the matching.
    4. - *
    - *

    - * In the {@code Pattern} implementation, 5 types of constructs maybe case-sensitive when matching: - * back-refs, string slice (sequences), single, family(char-property) and class range. Single and - * family may appears independently or within a class. - *

    - * For loose/case-insensitive matching, the back-refs, slices and singles apply {code toUpperCase} and - * {@code toLowerCase} to both the pattern and the input string. This effectively 'close' the class for - * matching. - *

    - * The family/char-properties are not "closed" and should remain unchanged. This is acceptable per RL1.5, - * if their behavior is clearly specified. - *

    - * This method addresses that requirement for the "range" construct within in character class by computing - * the additional characters that should be included to close the range under simple case folding: - *

    - * For each character in the input range {@code [start, end]} (inclusive), if the character has a simple - * case folding mapping in Unicode's CaseFolding.txt, the mapping is not a round-trip map, and the mapped - * character is not already in the range, then that mapped character (typically lowercase) is added to - * the expansion set. - *

    - * This allows regex character class "range" implementation to use the returned expansion set to support - * additional case-insensitive matching, without duplicating characters already covered by the existing - * regex range implementation. The expectation is the matching is done using both the uppercase and - * lowercase forms of the input character, for example - * - *

    {@code
    -     *
    -     *     ch -> inRange(lower, Character.toUpperCase(ch), upper) ||
    -     *           inRange(lower, Character.toLower(ch), upper) ||
    -     *           additionalClosingCharacters.contains(Character.toUpperCase(ch)) ||
    -     *           additionalClosingCharacters.contains(Character.toUpperCase(ch))
    -     * }
    - * - *

    - * @spec https://www.unicode.org/reports/tr18/#Simple_Loose_Matches - * @param start the starting code point of the character range - * @param end the ending code point of the character range - * @return a {@code int[]} containing the all simple case equivalents of characters in the range, excluding - * those already in the range - */ - public static int[] getClassRangeClosingCharacters(int start, int end) { - int[] expanded = new int[expanded_case_cps.length]; - int off = 0; - for (int cp : expanded_case_cps) { - if (cp >= start && cp <= end) { - int folding = expanded_case_map.get(cp); - if (folding < start || folding > end) { - expanded[off++] = folding; - } - } - } - return Arrays.copyOf(expanded, off); - } -} diff --git a/test/jdk/java/lang/String/UnicodeCaseFoldingTest.java b/test/jdk/java/lang/String/UnicodeCaseFoldingTest.java new file mode 100644 index 00000000000..86b3fba0a27 --- /dev/null +++ b/test/jdk/java/lang/String/UnicodeCaseFoldingTest.java @@ -0,0 +1,329 @@ +/* + * Copyright (c) 2025, 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 + * @summary tests unicode case-folding based String comparison and equality + * @bug 4397357 + * @library /lib/testlibrary/java/lang + * @modules java.base/jdk.internal.lang:+open + * @run junit/othervm + * UnicodeCaseFoldingTest + */ + +import java.nio.file.Files; +import java.util.stream.Stream; +import java.util.stream.Collectors; +import java.util.ArrayList; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import jdk.internal.lang.CaseFolding; + +public class UnicodeCaseFoldingTest { + + @Test + void testAllCommnFullCodePointsListedInCaseFoldinigTxt() throws Throwable { + var filter = "^.*; [CF]; .*$"; // C=common, F=full, for full case folding + var results = Files.lines(UCDFiles.CASEFOLDING) + .filter(line -> !line.startsWith("#") && line.matches(filter)) + .map(line -> { + var fields = line.split("; "); + var cp = Integer.parseInt(fields[0], 16); + fields = fields[2].trim().split(" "); + var folding = new int[fields.length]; + for (int i = 0; i < folding.length; i++) { + folding[i] = Integer.parseInt(fields[i], 16); + } + var source = new String(Character.toChars(cp)); + var expected = new String(folding, 0, folding.length); + // (1) Verify the folding result matches expected + assertEquals(expected, foldCase(source), "CaseFolding.fold(): "); + + // (2) Verify compareToFoldCase() result + assertEquals(0, source.compareToFoldCase(expected), "source.compareToFoldCase(expected)"); + assertEquals(0, expected.compareToFoldCase(source), "expected.compareToFoldCase(source)"); + + // (3) Verify equalsFoldCase() result + assertEquals(true, source.equalsFoldCase(expected), "source.equalsFoldCase(expected)"); + assertEquals(true, expected.equalsFoldCase(source), "expected.equalsFoldCase(source)"); + return null; + }) + .filter(error -> error != null) + .toArray(); + assertEquals(0, results.length); + } + + @Test + void testAllSimpleCodePointsListedInCaseFoldinigTxt() throws Throwable { + // S=simple, for simple case folding. The simple case folding should still matches + var filter = "^.*; [S]; .*$"; + var results = Files.lines(UCDFiles.CASEFOLDING) + .filter(line -> !line.startsWith("#") && line.matches(filter)) + .map(line -> { + var fields = line.split("; "); + var cp = Integer.parseInt(fields[0], 16); + fields = fields[2].trim().split(" "); + var folding = new int[fields.length]; + for (int i = 0; i < folding.length; i++) { + folding[i] = Integer.parseInt(fields[i], 16); + } + var source = new String(Character.toChars(cp)); + var expected = new String(folding, 0, folding.length); + + // (1) Verify compareToFoldCase() result + assertEquals(0, source.compareToFoldCase(expected), "source.compareToFoldCase(expected)"); + assertEquals(0, expected.compareToFoldCase(source), "expected.compareToFoldCase(source)"); + + // (2) Verify equalsFoldCase() result + assertEquals(true, source.equalsFoldCase(expected), "source.equalsFoldCase(expected)"); + assertEquals(true, expected.equalsFoldCase(source), "expected.equalsFoldCase(source)"); + return null; + }) + .filter(error -> error != null) + .toArray(); + assertEquals(0, results.length); + } + + @Test + public void testAllCodePointsFoldToThemselvesIfNotListed() throws Exception { + // Collect all code points that appear in CaseFolding.txt + var listed = Files.lines(UCDFiles.CASEFOLDING) + .filter(line -> !line.startsWith("#") && line.matches("^.*; [CF]; .*$")) + .map(line -> Integer.parseInt(line.split("; ")[0], 16)) + .collect(Collectors.toSet()); + + var failures = new ArrayList(); + + // Scan BMP + Supplementary Plane 1 (U+0000..U+1FFFF) + for (int cp = Character.MIN_CODE_POINT; cp <= 0x1FFFF; cp++) { + if (!Character.isDefined(cp)) { + continue; // skip undefined + } + if (Character.isSurrogate((char) cp)) { + continue; // skip surrogate code units + } + if (listed.contains(cp)) { + continue; // already tested separately + } + String s = new String(Character.toChars(cp)); + String folded = foldCase(s); + if (!s.equals(folded)) { + failures.add(String.format("Unexpected folding: U+%04X '%s' → '%s'", cp, s, folded)); + } + } + + assertEquals(0, failures.size(), + () -> "Some unlisted code points folded unexpectedly:\n" + + String.join("\n", failures)); + } + + @ParameterizedTest(name = "CaseFold \"{0}\" → \"{1}\"") + @MethodSource("caseFoldTestCases") + void testIndividualCaseFolding(String input, String expected) { + assertEquals(expected, foldCase(input)); + } + + static Stream caseFoldTestCases() { + return Stream.of( + // ASCII simple cases + Arguments.of("ABC", "abc"), + Arguments.of("already", "already"), + Arguments.of("MiXeD123", "mixed123"), + // --- Latin-1 to non-Latin-1 fold --- + Arguments.of("aBc\u00B5Efg", "abc\u03BCefg"), // "µ" → "μ" + Arguments.of("test\u00B5\ud801\udc00X", "test\u03bc\ud801\udc28x"), + // German Eszett + Arguments.of("Stra\u00DFe", "strasse"), // "Straße" + Arguments.of("\u1E9E", "ss"), // "ẞ" capital sharp S + // Turkish dotted I / dotless i + Arguments.of("I", "i"), + Arguments.of("\u0130", "i\u0307"), // capital dotted I → "i + dot above" + Arguments.of("\u0069\u0307", "i\u0307"), // small i + dot above remains + Arguments.of("\u0131", "\u0131"), // "ı" (dotless i stays dotless) + + // Greek special cases --- + Arguments.of("\u039F\u03A3", "\u03BF\u03C3"), // "ΟΣ" → "οσ" final sigma always folds to normal sigma + Arguments.of("\u1F88", "\u1F00\u03B9"), // "ᾈ" → "ἀι" Alpha with psili + ypogegrammeni + Arguments.of("\u039C\u03AC\u03CA\u03BF\u03C2", "\u03BC\u03AC\u03CA\u03BF\u03C3"), // "Μάϊος" → "μάϊοσ" + Arguments.of("\u1F08", "\u1F00"), // Ἀ (Capital Alpha with psili) → ἀ + + // Supplementary Plane characters + Arguments.of("\uD801\uDC00", "\uD801\uDC28"), // Deseret Capital Letter Long I → Small + Arguments.of("\uD801\uDC01", "\uD801\uDC29"), // Deseret Capital Letter Long E → Small + + // Supplementary inside ASCII + Arguments.of("abc\uD801\uDC00def", "abc\uD801\uDC28def"), + // Ligatures and compatibility folds + Arguments.of("\uFB00", "ff"), // ff → ff + Arguments.of("\uFB03", "ffi"), // ffi → ffi + Arguments.of("\u212A", "k"), // Kelvin sign → k + + Arguments.of("abc\uFB00def", "abcffdef"), // ff → ff + Arguments.of("abc\uFB03def", "abcffidef"), // ffi → ffi + Arguments.of("abc\u212Adef", "abckdef"), // Kelvin sign → k + + // --- Fullwidth --- + Arguments.of("\uFF21\uFF22\uFF23", "\uFF41\uFF42\uFF43"), // "ABC" → "abc" + + // --- Armenian --- + Arguments.of("\u0531", "\u0561"), // "Ա" → "ա" + + // --- Cherokee --- + Arguments.of("\u13A0", "\u13A0"), // Capital Cherokee A folds to itself + Arguments.of("\uAB70", "\u13A0") // Small Cherokee A folds Capital Cherokee A + ); + } + + static Stream caseFoldEqualProvider() { + return Stream.of( + Arguments.of("abc", "ABC"), + Arguments.of("aBcDe", "AbCdE"), + Arguments.of("\u00C0\u00E7", "\u00E0\u00C7"), // Àç vs àÇ + Arguments.of("straße", "STRASSE"), // ß → ss + Arguments.of("\uD83C\uDDE6", "\uD83C\uDDE6"), // 🇦 vs 🇦 + Arguments.of("\u1E9E", "ss"), // ẞ (capital sharp S) + Arguments.of("\u03A3", "\u03C3"), // Σ vs σ (Greek Sigma) + Arguments.of("\u03C3", "\u03C2"), // σ vs ς (Greek sigma/final sigma) + Arguments.of("\u212B", "\u00E5"), // Å (Angstrom sign) vs å + Arguments.of("\uFB00", "ff"), // ff (ligature) + Arguments.of("\u01C5", "\u01C5"), // Dž (Latin capital D with small z with caron) + Arguments.of("Caf\u00E9", "CAF\u00C9"), // Café vs CAFÉ + Arguments.of("\u03BA\u03B1\u03BB\u03B7\u03BC\u03AD\u03C1\u03B1", "\u039A\u0391\u039B\u0397\u039C\u0388\u03A1\u0391"), // καλημέρα vs ΚΑΛΗΜΕΡΑ + Arguments.of("\u4E2D\u56FD", "\u4E2D\u56FD"), // 中国 + Arguments.of("\u03B1", "\u0391"), // α vs Α (Greek alpha) + Arguments.of("\u212B", "\u00C5"), // Å vs Å + // from StringCompareToIgnoreCase + Arguments.of("\u0100\u0102\u0104\u0106\u0108", "\u0100\u0102\u0104\u0106\u0109"), // ĀĂĄĆĈ vs ĀĂĄĆĉ + Arguments.of("\u0101\u0103\u0105\u0107\u0109", "\u0100\u0102\u0104\u0106\u0109"), // āăąćĉ vs ĀĂĄĆĉ + Arguments.of("\ud801\udc00\ud801\udc01\ud801\udc02\ud801\udc03\ud801\udc04", + "\ud801\udc00\ud801\udc01\ud801\udc02\ud801\udc03\ud801\udc2c"), // 𐐀𐐁𐐂𐐃𐐄 vs 𐐀𐐁𐐂𐐃𐐬 + Arguments.of("\ud801\udc28\ud801\udc29\ud801\udc2a\ud801\udc2b\ud801\udc2c", + "\ud801\udc00\ud801\udc01\ud801\udc02\ud801\udc03\ud801\udc2c") // 𐐨𐐩𐐪𐐫𐐬 vs 𐐀𐐁𐐂𐐃𐐬 + ); + } + + @ParameterizedTest + @MethodSource("caseFoldEqualProvider") + void testcompareToFoldCaseEquals(String s1, String s2) { + assertEquals(0, s1.compareToFoldCase(s2)); + assertEquals(0, s2.compareToFoldCase(s1)); + assertEquals(true, s1.equalsFoldCase(s2)); + assertEquals(true, s2.equalsFoldCase(s1)); + assertEquals(foldCase(s1), foldCase(s2)); + } + + static Stream caseFoldOrderingProvider() { + return Stream.of( + Arguments.of("asa", "aß", -1), // ß → ss → "asa" < "ass" + Arguments.of("aß", "asa", +1), + Arguments.of("a\u00DF", "ass", 0), // aß vs ass + Arguments.of("\uFB03", "ffi", 0), // ffi (ligature) + Arguments.of("\u00C5", "Z", 1), // Å vs Z + Arguments.of("A", "\u00C0", -1), // A vs À + Arguments.of("\u03A9", "\u03C9", 0), // Ω vs ω + Arguments.of("\u03C2", "\u03C3", 0), // ς vs σ + Arguments.of("\uD835\uDD23", "R", 1), // 𝔯 (fraktur r) vs R + Arguments.of("\uFF26", "E", 1), // F (full-width F) vs E + Arguments.of("\u00C9clair", "Eclair", 1), // Éclair vs Eclair + Arguments.of("\u03bc\u00df", "\u00b5s", 1), + Arguments.of("\u00b5s", "\u03bc\u00df", -1) + ); + } + + @ParameterizedTest + @MethodSource("caseFoldOrderingProvider") + void testcompareToFoldCaseOrdering(String s1, String s2, int expectedSign) { + int cmp = s1.compareToFoldCase(s2); + assertEquals(expectedSign, Integer.signum(cmp)); + } + + static Stream roundTripProvider() { + return Stream.of( + Arguments.of("abc"), + Arguments.of("ABC"), + Arguments.of("straße"), + Arguments.of("Àç"), + Arguments.of("aß"), + Arguments.of("\uFB02uff"), // fluff (ligature in "fluff") + Arguments.of("\u00C9COLE") // ÉCOLE + ); + } + + @ParameterizedTest + @MethodSource("roundTripProvider") + void testCaseFoldRoundTrip(String s) { + String folded = foldCase(s); + assertEquals(0, s.compareToFoldCase(folded)); + assertEquals(0, folded.compareToFoldCase(s)); + assertEquals(true, s.equalsFoldCase(folded)); + assertEquals(true, folded.equalsFoldCase(s)); + } + + // helper to test the integrity of folding mapping + private static int[] longToFolding(long value) { + int len = (int) (value >>> 48); + if (len == 0) { + return new int[]{(int) (value & 0xFFFFF)}; + } else { + var folding = new int[len]; + for (int i = 0; i < len; i++) { + folding[i] = (int) (value & 0xFFFF); + value >>= 16; + } + return folding; + } + } + + private static String foldCase(String s) { + int first; + int len = s.length(); + int cpCnt = 1; + for (first = 0; first < len; first += cpCnt) { + int cp = s.codePointAt(first); + if (CaseFolding.isDefined(cp)) { + break; + } + cpCnt = Character.charCount(cp); + } + if (first == len) { + return s; + } + StringBuilder sb = new StringBuilder(len); + sb.append(s, 0, first); + for (int i = first; i < len; i += cpCnt) { + int cp = s.codePointAt(i); + int[] folded = longToFolding(CaseFolding.fold(cp)); + for (int f : folded) { + sb.appendCodePoint(f); + } + cpCnt = Character.charCount(cp); + } + return sb.toString(); + } +} diff --git a/test/micro/org/openjdk/bench/java/lang/StringCompareToFoldCase.java b/test/micro/org/openjdk/bench/java/lang/StringCompareToFoldCase.java new file mode 100644 index 00000000000..dff4d874705 --- /dev/null +++ b/test/micro/org/openjdk/bench/java/lang/StringCompareToFoldCase.java @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2025, 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.java.lang; + +import org.openjdk.jmh.annotations.*; +import java.util.concurrent.TimeUnit; + +/* + * This benchmark naively explores String::compareToFoldCase performance + */ +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@State(Scope.Thread) +@Warmup(iterations = 5, time = 1) +@Measurement(iterations = 5, time = 1) +@Fork(3) +public class StringCompareToFoldCase { + + private String asciiUpper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + private String asciiUpperLower = "ABCDEFGHIJKLMNOpqrstuvwxyz"; + private String asciiLower = "abcdefghijklmnopqrstuvwxyz"; + + private String asciiWithDF = "abcdßßßßßßßßßßßßßßßßWXYZ"; + private String asciiWithDFSS = "abcdssssssssssssssssßßßßßßßßWXYZ"; + + private String asciiLatine1 = "ABCDEFGHIJKLMNOpqrstuvwxyz0"; + private String asciiLatin1UTF16 = "abcdefghijklmnopqrstuvwxyz\u0391"; + + private String greekUpper = "\u0391\u0392\u0393\u0394\u0395\u0391\u0392\u0393\u0394\u0395"; // ΑΒΓΔΕ + private String greekUpperLower = "\u0391\u0392\u0393\u0394\u0395\u0391\u0392\u0393\u0394\u03B5"; // ΑΒΓΔε + private String greekLower = "\u03B1\u03B2\u03B3\u03B4\u03B5\u03B1\u03B2\u03B3\u03B4\u03B5"; // αβγδε + + public String supUpper = "\ud801\udc00\ud801\udc01\ud801\udc02\ud801\udc03\ud801\udc04"; + public String supUpperLower = "\ud801\udc00\ud801\udc01\ud801\udc02\ud801\udc03\ud801\udc2c"; + public String supLower = "\ud801\udc28\ud801\udc29\ud801\udc2a\ud801\udc2b\ud801\udc2c"; + + @Benchmark + public int asciiUpperLower() { + return asciiUpper.compareToIgnoreCase(asciiUpperLower); + } + + @Benchmark + public int asciiLower() { + return asciiUpper.compareToIgnoreCase(asciiLower); + } + + @Benchmark + public int greekUpperLower() { + return greekUpper.compareToIgnoreCase(greekUpperLower); + } + + @Benchmark + public int greekLower() { + return greekUpper.compareToIgnoreCase(greekLower); + } + + @Benchmark + public int latin1UTF16() { + return asciiLatine1.compareToIgnoreCase(asciiLatin1UTF16); + } + + @Benchmark + public int supUpperLower() { + return supUpper.compareToIgnoreCase(supUpperLower); + } + + @Benchmark + public int supLower() { + return supUpper.compareToIgnoreCase(supLower); + } + + @Benchmark + public int asciiUpperLowerFC() { + return asciiUpper.compareToFoldCase(asciiUpperLower); + } + + @Benchmark + public int asciiLowerFC() { + return asciiUpper.compareToFoldCase(asciiLower); + } + + @Benchmark + public int asciiWithDFFC() { + return asciiWithDF.compareToFoldCase(asciiWithDFSS); + } + + @Benchmark + public int greekUpperLowerFC() { + return greekUpper.compareToFoldCase(greekUpperLower); + } + + @Benchmark + public int greekLowerFC() { + return greekUpper.compareToFoldCase(greekLower); + } + + @Benchmark + public int latin1UTF16FC() { + return asciiLatine1.compareToFoldCase(asciiLatin1UTF16); } + + @Benchmark + public int supUpperLowerFC() { + return supUpper.compareToFoldCase(supUpperLower); + } + + @Benchmark + public int supLowerFC() { + return supUpper.compareToFoldCase(supLower); + } + + @Benchmark + public boolean asciiUpperLowerEQ() { + return asciiUpper.equalsIgnoreCase(asciiUpperLower); + } + + @Benchmark + public boolean asciiLowerEQ() { + return asciiUpper.equalsIgnoreCase(asciiLower); + } + + @Benchmark + public boolean greekUpperLowerEQ() { + return greekUpper.equalsIgnoreCase(greekUpperLower); + } + + @Benchmark + public boolean greekLowerEQ() { + return greekUpper.equalsIgnoreCase(greekLower); + } + + @Benchmark + public boolean latin1UTF16EQ() { + return asciiLatine1.equalsIgnoreCase(asciiLatin1UTF16); + } + + @Benchmark + public boolean supUpperLowerEQ() { + return supUpper.equalsIgnoreCase(supUpperLower); + } + + @Benchmark + public boolean supLowerEQ() { + return supUpper.equalsIgnoreCase(supLower); + } + + @Benchmark + public boolean asciiUpperLowerEQFC() { + return asciiUpper.equalsFoldCase(asciiUpperLower); + } + + @Benchmark + public boolean asciiLowerEQFC() { + return asciiUpper.equalsFoldCase(asciiLower); + } + + @Benchmark + public boolean greekUpperLowerEQFC() { + return greekUpper.equalsFoldCase(greekUpperLower); + } + + @Benchmark + public boolean greekLowerEQFC() { + return greekUpper.equalsFoldCase(greekLower); + } + + @Benchmark + public boolean latin1UTF16EQFC() { + return asciiLatine1.equalsFoldCase(asciiLatin1UTF16); + } + + @Benchmark + public boolean supUpperLowerEQFC() { + return supUpper.equalsFoldCase(supUpperLower); + } + + @Benchmark + public boolean supLowerEQFC() { + return supUpper.equalsFoldCase(supLower); + } + } From 5a60e22bc415b3335cbb6a63873b1b44ff2bf9d0 Mon Sep 17 00:00:00 2001 From: Sergey Bylokhov Date: Tue, 2 Dec 2025 20:09:09 +0000 Subject: [PATCH 103/706] 8369618: Remove outdated reference to JDK 1.1 in the spec of BufferedImage.TYPE_INT_ARGB Reviewed-by: azvegint, kizune, prr --- .../share/classes/java/awt/image/BufferedImage.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/java.desktop/share/classes/java/awt/image/BufferedImage.java b/src/java.desktop/share/classes/java/awt/image/BufferedImage.java index 09c96a6560f..52bf8a8c4bf 100644 --- a/src/java.desktop/share/classes/java/awt/image/BufferedImage.java +++ b/src/java.desktop/share/classes/java/awt/image/BufferedImage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, 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 @@ -100,10 +100,7 @@ public class BufferedImage extends java.awt.Image * Represents an image with 8-bit RGBA color components packed into * integer pixels. The image has a {@code DirectColorModel} * with alpha. The color data in this image is considered not to be - * premultiplied with alpha. When this type is used as the - * {@code imageType} argument to a {@code BufferedImage} - * constructor, the created image is consistent with images - * created in the JDK1.1 and earlier releases. + * premultiplied with alpha. */ public static final int TYPE_INT_ARGB = 2; From 0bead70651ea3bf8dccf9942ef8d1bf3fb78c2ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20Sikstr=C3=B6m?= Date: Tue, 2 Dec 2025 20:49:28 +0000 Subject: [PATCH 104/706] 8372961: [BACKOUT] Remove the default value of InitialRAMPercentage Reviewed-by: stefank --- src/hotspot/share/gc/shared/gc_globals.hpp | 2 +- src/hotspot/share/runtime/flags/jvmFlag.cpp | 2 +- src/java.base/share/man/java.md | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/gc/shared/gc_globals.hpp b/src/hotspot/share/gc/shared/gc_globals.hpp index d08e95378f7..e86a8744847 100644 --- a/src/hotspot/share/gc/shared/gc_globals.hpp +++ b/src/hotspot/share/gc/shared/gc_globals.hpp @@ -291,7 +291,7 @@ "size on systems with small physical memory size") \ range(0.0, 100.0) \ \ - product(double, InitialRAMPercentage, 0.0, \ + product(double, InitialRAMPercentage, 0.2, \ "Percentage of real memory used for initial heap size") \ range(0.0, 100.0) \ \ diff --git a/src/hotspot/share/runtime/flags/jvmFlag.cpp b/src/hotspot/share/runtime/flags/jvmFlag.cpp index 51517fa49db..487528c49bd 100644 --- a/src/hotspot/share/runtime/flags/jvmFlag.cpp +++ b/src/hotspot/share/runtime/flags/jvmFlag.cpp @@ -162,7 +162,7 @@ void JVMFlag::print_on(outputStream* st, bool withComments, bool printRanges) co // uintx ThresholdTolerance = 10 {product} {default} // size_t TLABSize = 0 {product} {default} // uintx SurvivorRatio = 8 {product} {default} - // double InitialRAMPercentage = 0.000000 {product} {default} + // double InitialRAMPercentage = 1.562500 {product} {default} // ccstr CompileCommandFile = MyFile.cmd {product} {command line} // ccstrlist CompileOnly = Method1 // CompileOnly += Method2 {product} {command line} diff --git a/src/java.base/share/man/java.md b/src/java.base/share/man/java.md index 8517e161e3f..462baa5a4a0 100644 --- a/src/java.base/share/man/java.md +++ b/src/java.base/share/man/java.md @@ -2455,7 +2455,8 @@ Java HotSpot VM. `-XX:InitialRAMPercentage=`*percent* : Sets the initial amount of memory that the JVM will use for the Java heap before applying ergonomics heuristics as a percentage of the maximum amount - determined as described in the `-XX:MaxRAM` option. + determined as described in the `-XX:MaxRAM` option. The default value is + 0.2 percent. The following example shows how to set the percentage of the initial amount of memory used for the Java heap: From a2ad5ca93ef82797ecf3141d00216ef639a9e92d Mon Sep 17 00:00:00 2001 From: Nizar Benalla Date: Tue, 2 Dec 2025 20:51:52 +0000 Subject: [PATCH 105/706] 8372939: Update JDK 26 spec URLs Reviewed-by: liach --- .../share/classes/java/lang/reflect/ClassFileFormatVersion.java | 2 +- .../share/classes/javax/lang/model/SourceVersion.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/java.base/share/classes/java/lang/reflect/ClassFileFormatVersion.java b/src/java.base/share/classes/java/lang/reflect/ClassFileFormatVersion.java index 16fe000091c..a4009915922 100644 --- a/src/java.base/share/classes/java/lang/reflect/ClassFileFormatVersion.java +++ b/src/java.base/share/classes/java/lang/reflect/ClassFileFormatVersion.java @@ -379,7 +379,7 @@ public enum ClassFileFormatVersion { * @since 26 * * @see + * href="https://docs.oracle.com/en/java/javase/26/docs/specs/jvms/index.html"> * The Java Virtual Machine Specification, Java SE 26 Edition */ RELEASE_26(70), 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 6b4ae119504..1a46df64ffb 100644 --- a/src/java.compiler/share/classes/javax/lang/model/SourceVersion.java +++ b/src/java.compiler/share/classes/javax/lang/model/SourceVersion.java @@ -476,7 +476,7 @@ public enum SourceVersion { * @since 26 * * @see + * href="https://docs.oracle.com/en/java/javase/26/docs/specs/jls/index.html"> * The Java Language Specification, Java SE 26 Edition */ RELEASE_26, From 0fe1ffdc485e742eb3937f9fb26d14d6a11a76c4 Mon Sep 17 00:00:00 2001 From: Nizar Benalla Date: Tue, 2 Dec 2025 20:52:23 +0000 Subject: [PATCH 106/706] 8372940: Update symbol data script references Reviewed-by: liach, darcy --- bin/generate-symbol-data.sh | 2 +- doc/starting-next-release.md | 2 +- src/jdk.compiler/share/data/symbols/README | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/generate-symbol-data.sh b/bin/generate-symbol-data.sh index 283757a6918..14d8763ad81 100644 --- a/bin/generate-symbol-data.sh +++ b/bin/generate-symbol-data.sh @@ -38,7 +38,7 @@ # directory. # - open a terminal program and run these commands: # cd "${JDK_CHECKOUT}"/src/jdk.compiler/share/data/symbols -# bash ../../../../../make/scripts/generate-symbol-data.sh "${JDK_N_INSTALL}" +# bash ../../../../../bin/generate-symbol-data.sh "${JDK_N_INSTALL}" # - this command will generate or update data for "--release N" into the ${JDK_CHECKOUT}/src/jdk.compiler/share/data/symbols # directory, updating all registration necessary. If the goal was to update the data, and there are no # new or changed files in the ${JDK_CHECKOUT}/src/jdk.compiler/share/data/symbols directory after running this script, diff --git a/doc/starting-next-release.md b/doc/starting-next-release.md index 10bc364a3e4..5bb9c5839a4 100644 --- a/doc/starting-next-release.md +++ b/doc/starting-next-release.md @@ -65,4 +65,4 @@ to be updated for a particular release. * `test/langtools/tools/javac/lib/JavacTestingAbstractProcessor.java` update annotation processor extended by `javac` tests to cover the new source version * `test/langtools/tools/javac/preview/classReaderTest/Client.nopreview.out` and `test/langtools/tools/javac/preview/classReaderTest/Client.preview.out`: update expected messages for preview errors and warnings - +* `test/langtools/tools/javac/versions/Versions.java`: add new source version to the set of valid sources and add new enum constant for the new class file version. diff --git a/src/jdk.compiler/share/data/symbols/README b/src/jdk.compiler/share/data/symbols/README index 4c9f38f77b0..50f68bbe2f2 100644 --- a/src/jdk.compiler/share/data/symbols/README +++ b/src/jdk.compiler/share/data/symbols/README @@ -1,3 +1,3 @@ This directory contains history data for -release. -Please see $JDK_TOP_DIR/make/scripts/generate-symbol-data.sh for main usage. +Please see $JDK_TOP_DIR/bin/generate-symbol-data.sh for main usage. From 8a28a76451b2bbde49c1c051cb66c784f9e3cdd2 Mon Sep 17 00:00:00 2001 From: Nizar Benalla Date: Tue, 2 Dec 2025 20:52:39 +0000 Subject: [PATCH 107/706] 8372937: Abbreviate list of supported releases Reviewed-by: liach --- .../com/sun/tools/javac/main/Option.java | 63 ++++++++++++++----- .../tools/javac/resources/javac.properties | 6 +- .../options/HelpOutputColumnWidthTest.java | 2 +- 3 files changed, 52 insertions(+), 19 deletions(-) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Option.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Option.java index c14767a7a8c..664ebc4c9c6 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Option.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Option.java @@ -33,6 +33,8 @@ import java.nio.file.InvalidPathException; import java.nio.file.Path; import java.nio.file.Paths; import java.text.Collator; +import java.util.Collection; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; @@ -45,7 +47,6 @@ import java.util.ServiceLoader; import java.util.Set; import java.util.StringJoiner; import java.util.TreeMap; -import java.util.TreeSet; import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -323,12 +324,13 @@ public enum Option { @Override protected void help(Log log) { - StringJoiner sj = new StringJoiner(", "); + List releases = new ArrayList<>(); for(Source source : Source.values()) { if (source.isSupported()) - sj.add(source.name); + releases.add(source.name); } - super.help(log, log.localize(PrefixKind.JAVAC, descrKey, sj.toString())); + String formatted = formatAbbreviatedList(releases); + super.help(log, log.localize(PrefixKind.JAVAC, descrKey, formatted)); } }, @@ -344,12 +346,13 @@ public enum Option { @Override protected void help(Log log) { - StringJoiner sj = new StringJoiner(", "); + List releases = new ArrayList<>(); for(Target target : Target.values()) { if (target.isSupported()) - sj.add(target.name); + releases.add(target.name); } - super.help(log, log.localize(PrefixKind.JAVAC, descrKey, sj.toString())); + String formatted = formatAbbreviatedList(releases); + super.help(log, log.localize(PrefixKind.JAVAC, descrKey, formatted)); } }, @@ -364,15 +367,8 @@ public enum Option { false)) .collect(Collectors.toCollection(LinkedHashSet :: new)); - StringBuilder targets = new StringBuilder(); - String delim = ""; - for (String platform : platforms) { - targets.append(delim); - targets.append(platform); - delim = ", "; - } - - super.help(log, log.localize(PrefixKind.JAVAC, descrKey, targets.toString())); + String formatted = formatAbbreviatedList(platforms); + super.help(log, log.localize(PrefixKind.JAVAC, descrKey, formatted)); } }, @@ -1369,6 +1365,41 @@ public enum Option { log.printRawLines(WriterKind.STDOUT, LARGE_INDENT + descr.replace("\n", "\n" + LARGE_INDENT)); } + /** + * Formats a collection of values as an abbreviated, comma separated list + * for use in javac help output. + * + * This helper assumes that the supported values form a dense sequence + * between the fourth and the (n - 3)rd entries. + * That matches the current policy for these values but is not + * guaranteed, and should be reconsidered if the structure of the values changes. + * + * @param values the values to format + * @return a comma separated representation of the values + */ + private static String formatAbbreviatedList(Collection values) { + List list = (values instanceof List) + ? (List) values + : new ArrayList<>(values); + + int size = list.size(); + if (size == 0) { + return ""; + } + if (size <= 6) { + return String.join(", ", list); + } + StringJoiner sj = new StringJoiner(", "); + for (int i = 0; i < 3; i++) { + sj.add(list.get(i)); + } + sj.add("..."); + for (int i = size - 3; i < size; i++) { + sj.add(list.get(i)); + } + return sj.toString(); + } + /** * Composes the initial synopsis of one of the forms for this option. * @param name the name of this form of the option diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/javac.properties b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/javac.properties index d5ee9469d22..7824772b1f3 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/javac.properties +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/javac.properties @@ -100,7 +100,8 @@ javac.opt.arg.Werror=\ (,)* javac.opt.Werror.custom=\ Specify lint categories for which warnings should terminate compilation,\n\ - separated by comma. Precede a key by ''-'' to exclude the specified category.\n\ + separated by comma.\n\ + Precede a key by ''-'' to exclude the specified category.\n\ Use --help-lint to see the supported keys. javac.opt.A=\ Options to pass to annotation processors @@ -358,7 +359,8 @@ javac.opt.prefer=\ are found for an implicitly compiled class # L10N: do not localize: ''preview'' javac.opt.preview=\ - Enable preview language features. Also disables the ''preview'' lint category.\n\ + Enable preview language features.\n\ + Also disables the ''preview'' lint category.\n\ To be used in conjunction with either -source or --release. javac.opt.AT=\ Read options and filenames from file diff --git a/test/langtools/tools/javac/options/HelpOutputColumnWidthTest.java b/test/langtools/tools/javac/options/HelpOutputColumnWidthTest.java index 4cef7e1916b..f46ef0219b5 100644 --- a/test/langtools/tools/javac/options/HelpOutputColumnWidthTest.java +++ b/test/langtools/tools/javac/options/HelpOutputColumnWidthTest.java @@ -47,7 +47,7 @@ import toolbox.Task; public class HelpOutputColumnWidthTest extends TestRunner { - public static final int MAX_COLUMNS = 84; + public static final int MAX_COLUMNS = 80; protected ToolBox tb; From 37cd8d6ca0bc4638d81e9a3c1e0bc785861ffbef Mon Sep 17 00:00:00 2001 From: Sergey Bylokhov Date: Tue, 2 Dec 2025 20:59:49 +0000 Subject: [PATCH 108/706] 8371501: Change IAE to NPE in java.awt.image.Kernel when data is null Reviewed-by: prr, azvegint, aivanov --- .../share/classes/java/awt/image/Kernel.java | 7 ++- .../ConvolveOp/KernelInitialisationTest.java | 51 ++++++++++++------- 2 files changed, 35 insertions(+), 23 deletions(-) diff --git a/src/java.desktop/share/classes/java/awt/image/Kernel.java b/src/java.desktop/share/classes/java/awt/image/Kernel.java index d2b9760aba5..67f62e79b9e 100644 --- a/src/java.desktop/share/classes/java/awt/image/Kernel.java +++ b/src/java.desktop/share/classes/java/awt/image/Kernel.java @@ -25,6 +25,7 @@ package java.awt.image; +import java.util.Objects; /** * The {@code Kernel} class defines a matrix that describes how a @@ -59,7 +60,7 @@ public class Kernel implements Cloneable { * @param width width of the kernel * @param height height of the kernel * @param data kernel data in row major order - * @throws IllegalArgumentException if {@code data} is null + * @throws NullPointerException if {@code data} is null * @throws IllegalArgumentException if {@code width} or {@code height} * is not positive * @throws IllegalArgumentException if product of {@code width} and @@ -69,9 +70,7 @@ public class Kernel implements Cloneable { * {@code height} */ public Kernel(int width, int height, float[] data) { - if (data == null) { - throw new IllegalArgumentException("Data must not be null"); - } + Objects.requireNonNull(data, "Data must not be null"); if ((width <= 0) || (height <= 0)) { throw new IllegalArgumentException("Invalid width or height"); } diff --git a/test/jdk/java/awt/image/ConvolveOp/KernelInitialisationTest.java b/test/jdk/java/awt/image/ConvolveOp/KernelInitialisationTest.java index 607f0a7a8dc..0d58472385c 100644 --- a/test/jdk/java/awt/image/ConvolveOp/KernelInitialisationTest.java +++ b/test/jdk/java/awt/image/ConvolveOp/KernelInitialisationTest.java @@ -25,36 +25,49 @@ * @test * @bug 8368729 * @summary Tests that passing invalid values to Kernel constructor - * throws only IllegalArgumentException + * throws only IllegalArgumentException or NullPointerException */ import java.awt.image.Kernel; public class KernelInitialisationTest { - private static void expectIllegalArgumentException(Runnable code) { + + private static void test(int width, int height, float[] data, + Class expected) + { + System.out.printf("Testing for width: %d, height: %d, data: %s%n", + width, height, data == null ? "null" : "not null"); + Class actual = null; try { - code.run(); - throw new RuntimeException("Expected IllegalArgumentException" + - " but no exception was thrown"); - } catch (IllegalArgumentException e) { - // we expect IllegalArgumentException + new Kernel(width, height, data); + } catch (Exception e) { + actual = e.getClass(); + } + if (actual != expected) { + System.err.println("Expected: " + expected); + System.err.println("Actual: " + actual); + throw new RuntimeException("Test failed"); } } - private static void testKernel(int width, int height, float[] data) { - System.out.println("Testing for width: " + width + ", height: " - + height + ", data: " + (data == null ? "null" : "not null")); - expectIllegalArgumentException(() -> new Kernel(width, height, data)); + private static void testIAE(int width, int height, int len) { + test(width, height, new float[len], IllegalArgumentException.class); + } + + private static void testNPE(int width, int height) { + test(width, height, null, NullPointerException.class); } public static void main(String[] args) { - testKernel(-1, 1, new float[100]); - testKernel(1, -1, new float[100]); - testKernel(-1, -1, new float[100]); - testKernel(1, 1, null); - - int width = 50; - int height = Integer.MAX_VALUE; - testKernel(width, height, new float[100]); + int[][] sizes = {{-1, 1}, {1, -1}, {-1, -1}, {50, Integer.MAX_VALUE}}; + int[] lens = {1, 100}; + for (int[] kernelSize : sizes) { + for (int len : lens) { + testIAE(kernelSize[0], kernelSize[1], len); + } + testNPE(kernelSize[0], kernelSize[1]); + } + testNPE(10, 10); // NPE on valid width and height + testIAE(10, 10, 10); // IAE on valid width and height but small data } } From 8f0cb57e439df87dee4c0ba7bbff0b981ebc3541 Mon Sep 17 00:00:00 2001 From: Henry Jen Date: Tue, 2 Dec 2025 22:11:38 +0000 Subject: [PATCH 109/706] 8347831: Re-examine version check when cross linking Co-authored-by: Magnus Ihse Bursie Reviewed-by: erikj, alanb --- make/modules/java.base/Gensrc.gmk | 22 ++++++ make/modules/java.base/Java.gmk | 2 +- .../misc/resources/release.txt.template | 1 + .../jdk/tools/jlink/internal/JlinkTask.java | 69 +++++++++++++------ .../tools/jlink/resources/jlink.properties | 4 +- 5 files changed, 75 insertions(+), 23 deletions(-) create mode 100644 src/java.base/share/classes/jdk/internal/misc/resources/release.txt.template diff --git a/make/modules/java.base/Gensrc.gmk b/make/modules/java.base/Gensrc.gmk index 79db438934e..e8236f0b0e4 100644 --- a/make/modules/java.base/Gensrc.gmk +++ b/make/modules/java.base/Gensrc.gmk @@ -120,3 +120,25 @@ $(INTPOLY_GEN_DONE): $(INTPLOY_HEADER) $(BUILD_TOOLS_JDK) TARGETS += $(INTPOLY_GEN_DONE) ################################################################################ + +RELEASE_FILE_TEMPLATE := $(TOPDIR)/src/java.base/share/classes/jdk/internal/misc/resources/release.txt.template +RELEASE_FILE_TARGET := $(SUPPORT_OUTPUTDIR)/gensrc/$(MODULE)/jdk/internal/misc/resources/release.txt + +RELEASE_FILE_VARDEPS := $(COMPANY_NAME) $(VERSION_STRING) $(VERSION_DATE) +RELEASE_FILE_VARDEPS_FILE := $(call DependOnVariable, RELEASE_FILE_VARDEPS, \ + $(SUPPORT_OUTPUTDIR)/gensrc/$(MODULE)/jlink_release_txt.vardeps) + +$(eval $(call SetupTextFileProcessing, BUILD_RELEASE_FILE, \ + SOURCE_FILES := $(RELEASE_FILE_TEMPLATE), \ + OUTPUT_FILE := $(RELEASE_FILE_TARGET), \ + REPLACEMENTS := \ + @@COMPANY_NAME@@ => $(COMPANY_NAME) ; \ + @@VERSION_STRING@@ => $(VERSION_STRING) ; \ + @@VERSION_DATE@@ => $(VERSION_DATE) , \ +)) + +$(BUILD_RELEASE_FILE): $(RELEASE_FILE_VARDEPS_FILE) + +TARGETS += $(BUILD_RELEASE_FILE) + +################################################################################ diff --git a/make/modules/java.base/Java.gmk b/make/modules/java.base/Java.gmk index fc091377456..e20db38297d 100644 --- a/make/modules/java.base/Java.gmk +++ b/make/modules/java.base/Java.gmk @@ -34,7 +34,7 @@ DOCLINT += -Xdoclint:all/protected \ '-Xdoclint/package:java.*,javax.*' JAVAC_FLAGS += -XDstringConcat=inline -COPY += .icu .dat .spp .nrm content-types.properties \ +COPY += .icu .dat .spp .nrm .txt content-types.properties \ hijrah-config-Hijrah-umalqura_islamic-umalqura.properties CLEAN += intrinsic.properties diff --git a/src/java.base/share/classes/jdk/internal/misc/resources/release.txt.template b/src/java.base/share/classes/jdk/internal/misc/resources/release.txt.template new file mode 100644 index 00000000000..2d46f8f0e60 --- /dev/null +++ b/src/java.base/share/classes/jdk/internal/misc/resources/release.txt.template @@ -0,0 +1 @@ +@@COMPANY_NAME@@-@@VERSION_STRING@@-@@VERSION_DATE@@ diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java index 928b9a47934..03b9611c179 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java @@ -27,9 +27,11 @@ package jdk.tools.jlink.internal; import static jdk.tools.jlink.internal.TaskHelper.JLINK_BUNDLE; import java.io.BufferedInputStream; +import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.io.InputStreamReader; import java.io.PrintWriter; import java.io.UncheckedIOException; import java.lang.module.Configuration; @@ -56,6 +58,7 @@ import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.NoSuchElementException; import java.util.Objects; import java.util.Optional; import java.util.Set; @@ -238,6 +241,27 @@ public class JlinkTask { } public static final String OPTIONS_RESOURCE = "jdk/tools/jlink/internal/options"; + // Release information stored in the java.base module + private static final String JDK_RELEASE_RESOURCE = "jdk/internal/misc/resources/release.txt"; + + /** + * Read the release.txt from the module. + */ + private static Optional getReleaseInfo(ModuleReference mref) { + try { + Optional release = mref.open().open(JDK_RELEASE_RESOURCE); + + if (release.isEmpty()) { + return Optional.empty(); + } + + try (var r = new BufferedReader(new InputStreamReader(release.get()))) { + return Optional.of(r.readLine()); + } + } catch (IOException ioe) { + throw new UncheckedIOException(ioe); + } + } int run(String[] args) { if (log == null) { @@ -410,7 +434,8 @@ public class JlinkTask { // Sanity check version if we use JMODs if (!isLinkFromRuntime) { - checkJavaBaseVersion(finder); + assert(finder.find("java.base").isPresent()); + checkJavaBaseVersion(finder.find("java.base").get()); } // Determine the roots set @@ -561,32 +586,34 @@ public class JlinkTask { return finder; } + private static String getCurrentRuntimeVersion() { + ModuleReference current = ModuleLayer.boot() + .configuration() + .findModule("java.base") + .get() + .reference(); + // This jlink runtime should always have the release.txt + return getReleaseInfo(current).get(); + } + /* - * Checks the version of the module descriptor of java.base for compatibility - * with the current runtime version. + * Checks the release information of the java.base used for target image + * for compatibility with the java.base used by jlink. * - * @throws IllegalArgumentException the descriptor of java.base has no - * version or the java.base version is not the same as the current runtime's - * version. + * @throws IllegalArgumentException If the `java.base` module reference `target` + * is not compatible with this jlink. */ - private static void checkJavaBaseVersion(ModuleFinder finder) { - assert finder.find("java.base").isPresent(); + private static void checkJavaBaseVersion(ModuleReference target) { + String currentRelease = getCurrentRuntimeVersion(); - // use the version of java.base module, if present, as - // the release version for multi-release JAR files - ModuleDescriptor.Version v = finder.find("java.base").get() - .descriptor().version().orElseThrow(() -> - new IllegalArgumentException("No version in java.base descriptor") - ); + String targetRelease = getReleaseInfo(target).orElseThrow(() -> new IllegalArgumentException( + taskHelper.getMessage("err.jlink.version.missing", currentRelease))); - Runtime.Version version = Runtime.Version.parse(v.toString()); - if (Runtime.version().feature() != version.feature() || - Runtime.version().interim() != version.interim()) { - // jlink version and java.base version do not match. - // We do not (yet) support this mode. + if (!currentRelease.equals(targetRelease)) { + // Current runtime image and the target runtime image are not compatible build throw new IllegalArgumentException(taskHelper.getMessage("err.jlink.version.mismatch", - Runtime.version().feature(), Runtime.version().interim(), - version.feature(), version.interim())); + currentRelease, + targetRelease)); } } diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/jlink.properties b/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/jlink.properties index 080d51506a6..374ed78f608 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/jlink.properties +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/jlink.properties @@ -130,7 +130,9 @@ err.runtime.link.patched.module=jlink does not support linking from the run-time err.no.module.path=--module-path option must be specified with --add-modules ALL-MODULE-PATH err.empty.module.path=No module found in module path ''{0}'' with --add-modules ALL-MODULE-PATH err.limit.modules=--limit-modules not allowed with --add-modules ALL-MODULE-PATH -err.jlink.version.mismatch=jlink version {0}.{1} does not match target java.base version {2}.{3} +err.jlink.version.mismatch=jlink build ''{0}'' does not match target java.base build ''{1}'' +err.jlink.version.missing=jlink build ''{0}'' cannot find the build signature\ +\ in the java.base specified on module path, likely from an earlier build. err.automatic.module:automatic module cannot be used with jlink: {0} from {1} err.unknown.byte.order:unknown byte order {0} err.launcher.main.class.empty:launcher main class name cannot be empty: {0} From b0a758f2180a8305c05e9640192818bbb31d7922 Mon Sep 17 00:00:00 2001 From: Leonid Mesnik Date: Tue, 2 Dec 2025 22:27:54 +0000 Subject: [PATCH 110/706] 8372552: unhandled oop in the JvmtiEventController::set_user_enabled Reviewed-by: cjplummer, amenkov, sspitsyn --- src/hotspot/share/prims/jvmtiEventController.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/hotspot/share/prims/jvmtiEventController.cpp b/src/hotspot/share/prims/jvmtiEventController.cpp index 169ccbe035f..9df3bbb4b3e 100644 --- a/src/hotspot/share/prims/jvmtiEventController.cpp +++ b/src/hotspot/share/prims/jvmtiEventController.cpp @@ -1077,10 +1077,6 @@ JvmtiEventController::is_global_event(jvmtiEvent event_type) { void JvmtiEventController::set_user_enabled(JvmtiEnvBase *env, JavaThread *thread, oop thread_oop, jvmtiEvent event_type, bool enabled) { - if (event_type == JVMTI_EVENT_OBJECT_FREE) { - JvmtiEventControllerPrivate::flush_object_free_events(env); - } - if (Threads::number_of_threads() == 0) { // during early VM start-up locks don't exist, but we are safely single threaded, // call the functionality without holding the JvmtiThreadState_lock. @@ -1089,6 +1085,11 @@ JvmtiEventController::set_user_enabled(JvmtiEnvBase *env, JavaThread *thread, oo Thread* current = Thread::current(); HandleMark hmi(current); Handle thread_oop_h = Handle(current, thread_oop); + + if (event_type == JVMTI_EVENT_OBJECT_FREE) { + JvmtiEventControllerPrivate::flush_object_free_events(env); + } + MutexLocker mu(JvmtiThreadState_lock); JvmtiEventControllerPrivate::set_user_enabled(env, thread, thread_oop_h, event_type, enabled); } @@ -1238,4 +1239,4 @@ JvmtiEventController::vm_death() { break; } } -} \ No newline at end of file +} From f5e4cd7f0d12fd21399b192b32a5c9abfe8a3564 Mon Sep 17 00:00:00 2001 From: Leonid Mesnik Date: Tue, 2 Dec 2025 23:48:58 +0000 Subject: [PATCH 111/706] 8372039: post_sampled_object_alloc is called while lock is handled Reviewed-by: sspitsyn, eosterlund, amenkov --- .../share/cds/aotStreamedHeapLoader.cpp | 1 + src/hotspot/share/cds/aotThread.cpp | 2 +- src/hotspot/share/prims/jvmtiExport.cpp | 26 ++--- src/hotspot/share/prims/jvmtiExport.hpp | 25 +---- src/hotspot/share/runtime/javaThread.cpp | 1 + src/hotspot/share/runtime/javaThread.hpp | 12 ++- .../SamplingDuringInit.java | 46 +++++++++ .../libSamplingDuringInit.cpp | 95 +++++++++++++++++++ 8 files changed, 164 insertions(+), 44 deletions(-) create mode 100644 test/hotspot/jtreg/serviceability/jvmti/events/SampledObjectAlloc/SamplingDuringInit/SamplingDuringInit.java create mode 100644 test/hotspot/jtreg/serviceability/jvmti/events/SampledObjectAlloc/SamplingDuringInit/libSamplingDuringInit.cpp diff --git a/src/hotspot/share/cds/aotStreamedHeapLoader.cpp b/src/hotspot/share/cds/aotStreamedHeapLoader.cpp index 9b6974bb48d..6719f9bf898 100644 --- a/src/hotspot/share/cds/aotStreamedHeapLoader.cpp +++ b/src/hotspot/share/cds/aotStreamedHeapLoader.cpp @@ -184,6 +184,7 @@ static size_t archive_object_size(oopDesc* archive_object) { oop AOTStreamedHeapLoader::allocate_object(oopDesc* archive_object, markWord mark, size_t size, TRAPS) { assert(!archive_object->is_stackChunk(), "no such objects are archived"); + NoJvmtiEventsMark njem; oop heap_object; Klass* klass = archive_object->klass(); diff --git a/src/hotspot/share/cds/aotThread.cpp b/src/hotspot/share/cds/aotThread.cpp index 26a6f4291cd..113a751d2a1 100644 --- a/src/hotspot/share/cds/aotThread.cpp +++ b/src/hotspot/share/cds/aotThread.cpp @@ -63,7 +63,7 @@ void AOTThread::initialize() { // This is important because this thread runs before JVMTI monitors are set up appropriately. // Therefore, callbacks would not work as intended. JVMTI has no business peeking at how we // materialize primordial objects from the AOT cache. - thread->toggle_is_disable_suspend(); + thread->disable_jvmti_events(); #endif JavaThread::vm_exit_on_osthread_failure(thread); diff --git a/src/hotspot/share/prims/jvmtiExport.cpp b/src/hotspot/share/prims/jvmtiExport.cpp index 69d1fa2c974..14b7d886bce 100644 --- a/src/hotspot/share/prims/jvmtiExport.cpp +++ b/src/hotspot/share/prims/jvmtiExport.cpp @@ -3159,31 +3159,19 @@ void JvmtiObjectAllocEventCollector::record_allocation(oop obj) { _allocated->push(OopHandle(JvmtiExport::jvmti_oop_storage(), obj)); } -// Disable collection of VMObjectAlloc events -NoJvmtiVMObjectAllocMark::NoJvmtiVMObjectAllocMark() : _collector(nullptr) { - // a no-op if VMObjectAlloc event is not enabled - if (!JvmtiExport::should_post_vm_object_alloc()) { - return; - } +NoJvmtiEventsMark::NoJvmtiEventsMark() { Thread* thread = Thread::current_or_null(); if (thread != nullptr && thread->is_Java_thread()) { JavaThread* current_thread = JavaThread::cast(thread); - JvmtiThreadState *state = current_thread->jvmti_thread_state(); - if (state != nullptr) { - JvmtiVMObjectAllocEventCollector *collector; - collector = state->get_vm_object_alloc_event_collector(); - if (collector != nullptr && collector->is_enabled()) { - _collector = collector; - _collector->set_enabled(false); - } - } + current_thread->disable_jvmti_events(); } } -// Re-Enable collection of VMObjectAlloc events (if previously enabled) -NoJvmtiVMObjectAllocMark::~NoJvmtiVMObjectAllocMark() { - if (was_enabled()) { - _collector->set_enabled(true); +NoJvmtiEventsMark::~NoJvmtiEventsMark() { + Thread* thread = Thread::current_or_null(); + if (thread != nullptr && thread->is_Java_thread()) { + JavaThread* current_thread = JavaThread::cast(thread); + current_thread->enable_jvmti_events(); } }; diff --git a/src/hotspot/share/prims/jvmtiExport.hpp b/src/hotspot/share/prims/jvmtiExport.hpp index 66f5413c8f6..f6c9f3a74d5 100644 --- a/src/hotspot/share/prims/jvmtiExport.hpp +++ b/src/hotspot/share/prims/jvmtiExport.hpp @@ -585,29 +585,12 @@ class JvmtiSampledObjectAllocEventCollector : public JvmtiObjectAllocEventCollec static bool object_alloc_is_safe_to_sample() NOT_JVMTI_RETURN_(false); }; -// Marker class to disable the posting of VMObjectAlloc events -// within its scope. -// -// Usage :- -// -// { -// NoJvmtiVMObjectAllocMark njm; -// : -// // VMObjAlloc event will not be posted -// JvmtiExport::vm_object_alloc_event_collector(obj); -// : -// } - -class NoJvmtiVMObjectAllocMark : public StackObj { - private: - // enclosing collector if enabled, null otherwise - JvmtiVMObjectAllocEventCollector *_collector; - - bool was_enabled() { return _collector != nullptr; } +// Marker class to temporary disable posting of jvmti events. +class NoJvmtiEventsMark : public StackObj { public: - NoJvmtiVMObjectAllocMark() NOT_JVMTI_RETURN; - ~NoJvmtiVMObjectAllocMark() NOT_JVMTI_RETURN; + NoJvmtiEventsMark() NOT_JVMTI_RETURN; + ~NoJvmtiEventsMark() NOT_JVMTI_RETURN; }; diff --git a/src/hotspot/share/runtime/javaThread.cpp b/src/hotspot/share/runtime/javaThread.cpp index 28bc47c4c74..a81a687a9c0 100644 --- a/src/hotspot/share/runtime/javaThread.cpp +++ b/src/hotspot/share/runtime/javaThread.cpp @@ -451,6 +451,7 @@ JavaThread::JavaThread(MemTag mem_tag) : _is_in_VTMS_transition(false), _is_disable_suspend(false), _is_in_java_upcall(false), + _jvmti_events_disabled(0), _VTMS_transition_mark(false), _on_monitor_waited_event(false), _contended_entered_monitor(nullptr), diff --git a/src/hotspot/share/runtime/javaThread.hpp b/src/hotspot/share/runtime/javaThread.hpp index b0cd6fb3e4f..ba2aa42132f 100644 --- a/src/hotspot/share/runtime/javaThread.hpp +++ b/src/hotspot/share/runtime/javaThread.hpp @@ -325,6 +325,7 @@ class JavaThread: public Thread { bool _is_in_VTMS_transition; // thread is in virtual thread mount state transition bool _is_disable_suspend; // JVMTI suspend is temporarily disabled; used on current thread only bool _is_in_java_upcall; // JVMTI is doing a Java upcall, so JVMTI events must be hidden + int _jvmti_events_disabled; // JVMTI events disabled manually bool _VTMS_transition_mark; // used for sync between VTMS transitions and disablers bool _on_monitor_waited_event; // Avoid callee arg processing for enterSpecial when posting waited event ObjectMonitor* _contended_entered_monitor; // Monitor for pending monitor_contended_entered callback @@ -748,10 +749,13 @@ public: void set_is_in_VTMS_transition(bool val); bool is_disable_suspend() const { return _is_disable_suspend; } - void toggle_is_disable_suspend() { _is_disable_suspend = !_is_disable_suspend; }; + void toggle_is_disable_suspend() { _is_disable_suspend = !_is_disable_suspend; } bool is_in_java_upcall() const { return _is_in_java_upcall; } - void toggle_is_in_java_upcall() { _is_in_java_upcall = !_is_in_java_upcall; }; + void toggle_is_in_java_upcall() { _is_in_java_upcall = !_is_in_java_upcall; } + + void disable_jvmti_events() { _jvmti_events_disabled++; } + void enable_jvmti_events() { _jvmti_events_disabled--; } bool VTMS_transition_mark() const { return AtomicAccess::load(&_VTMS_transition_mark); } void set_VTMS_transition_mark(bool val) { AtomicAccess::store(&_VTMS_transition_mark, val); } @@ -760,7 +764,9 @@ public: // - is in a VTMS transition (_is_in_VTMS_transition) // - is in an interruptLock or similar critical section (_is_disable_suspend) // - JVMTI is making a Java upcall (_is_in_java_upcall) - bool should_hide_jvmti_events() const { return _is_in_VTMS_transition || _is_disable_suspend || _is_in_java_upcall; } + bool should_hide_jvmti_events() const { + return _is_in_VTMS_transition || _is_disable_suspend || _is_in_java_upcall || _jvmti_events_disabled != 0; + } bool on_monitor_waited_event() { return _on_monitor_waited_event; } void set_on_monitor_waited_event(bool val) { _on_monitor_waited_event = val; } diff --git a/test/hotspot/jtreg/serviceability/jvmti/events/SampledObjectAlloc/SamplingDuringInit/SamplingDuringInit.java b/test/hotspot/jtreg/serviceability/jvmti/events/SampledObjectAlloc/SamplingDuringInit/SamplingDuringInit.java new file mode 100644 index 00000000000..1dc885180c1 --- /dev/null +++ b/test/hotspot/jtreg/serviceability/jvmti/events/SampledObjectAlloc/SamplingDuringInit/SamplingDuringInit.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2025, 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 8372039 + * @summary The test verifies that object allocation sampling is disabled during AOT. + * + * Don't remove 'modules' line, it triggers the crash. + * @modules java.management + * + * @run main/othervm/native -agentlib:SamplingDuringInit SamplingDuringInit + * @run main/othervm/native -agentlib:SamplingDuringInit -XX:-UseCompressedOops SamplingDuringInit + */ + +public class SamplingDuringInit { + + public static Object[] tmp = new Object[1000]; + public static void main(String[] args) throws Exception { + // Allocate some objects to trigger Sampling even if + // all JDK classes are preloaded. + for (int i = 0; i < tmp.length; i++) { + tmp[i] = new String("tmp" + i); + } + } +} diff --git a/test/hotspot/jtreg/serviceability/jvmti/events/SampledObjectAlloc/SamplingDuringInit/libSamplingDuringInit.cpp b/test/hotspot/jtreg/serviceability/jvmti/events/SampledObjectAlloc/SamplingDuringInit/libSamplingDuringInit.cpp new file mode 100644 index 00000000000..709012dfb57 --- /dev/null +++ b/test/hotspot/jtreg/serviceability/jvmti/events/SampledObjectAlloc/SamplingDuringInit/libSamplingDuringInit.cpp @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2025, 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. + */ + +#include "jvmti.h" +#include "jvmti_common.hpp" + +#include + +extern "C" { + +// SampledObjectAlloc event might be triggered on any thread +static std::atomic events_counter(0); + +JNIEXPORT void JNICALL +SampledObjectAlloc(jvmtiEnv *jvmti, JNIEnv* jni, jthread thread, jobject object, jclass object_klass, jlong size) { + events_counter++; + LOG("Sampled object, events_counter = %d\n", events_counter.load()); +} + +void JNICALL +VMDeath(jvmtiEnv *jvmti, JNIEnv* jni) { + if (events_counter == 0) { + fatal(jni, "SampledObjectAlloc events counter shouldn't be zero"); + } +} + +jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { + jvmtiEnv* jvmti = nullptr; + jvmtiCapabilities caps; + jvmtiEventCallbacks callbacks; + jvmtiError err; + jint res; + + LOG("AGENT INIT"); + res = jvm->GetEnv((void **) &jvmti, JVMTI_VERSION_9); + if (res != JNI_OK || jvmti == nullptr) { + LOG("Wrong result of a valid call to GetEnv!\n"); + return JNI_ERR; + } + + memset(&caps, 0, sizeof(caps)); + caps.can_generate_sampled_object_alloc_events = 1; + if (jvmti->AddCapabilities(&caps) != JVMTI_ERROR_NONE) { + return JNI_ERR; + } + + memset(&callbacks, 0, sizeof(callbacks)); + callbacks.SampledObjectAlloc = &SampledObjectAlloc; + callbacks.VMDeath = &VMDeath; + + err = jvmti->SetEventCallbacks(&callbacks, sizeof(callbacks)); + check_jvmti_error(err, "SetEventCallbacks"); + /* + * Interval should be small enough to triggger sampling event while objects are init by VM. + */ + err = jvmti->SetHeapSamplingInterval(10); + check_jvmti_error(err, "SetHeapSamplingInterval"); + + err = jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_VM_DEATH, nullptr); + check_jvmti_error(err, "SetEventNotificationMode"); + + err = jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_SAMPLED_OBJECT_ALLOC, nullptr); + check_jvmti_error(err, "SetEventNotificationMode"); + + return JNI_OK; +} + +JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) { + return Agent_Initialize(jvm, options, reserved); +} + +JNIEXPORT jint JNICALL Agent_OnAttach(JavaVM *jvm, char *options, void *reserved) { + return Agent_Initialize(jvm, options, reserved); +} +} From 1f206e5e1268cd0a7f477ed2d2f49103b8a99db6 Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Wed, 3 Dec 2025 00:27:42 +0000 Subject: [PATCH 112/706] 8372850: Update comment in SourceVersion for language evolution history for changes in 26 Reviewed-by: liach --- .../share/classes/javax/lang/model/SourceVersion.java | 4 ++++ 1 file changed, 4 insertions(+) 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 1a46df64ffb..e21e9e1db9a 100644 --- a/src/java.compiler/share/classes/javax/lang/model/SourceVersion.java +++ b/src/java.compiler/share/classes/javax/lang/model/SourceVersion.java @@ -83,6 +83,10 @@ public enum SourceVersion { * preview, flexible constructor bodies in third preview) * 25: module import declarations, compact source files and * instance main methods, and flexible constructor bodies + * (primitive Types in Patterns, instanceof, and switch in + * third preview) + * 26: no changes (primitive Types in Patterns, instanceof, and + * switch in in fourth preview) */ /** From 530493fed4066b1efcf3ec22253b110495767eca Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Wed, 3 Dec 2025 02:46:02 +0000 Subject: [PATCH 113/706] 8364146: JList getScrollableUnitIncrement return 0 Reviewed-by: prr, tr --- .../share/classes/javax/swing/JList.java | 13 ++- test/jdk/javax/swing/JList/JListTest.java | 86 +++++++++++++++++++ 2 files changed, 95 insertions(+), 4 deletions(-) create mode 100644 test/jdk/javax/swing/JList/JListTest.java diff --git a/src/java.desktop/share/classes/javax/swing/JList.java b/src/java.desktop/share/classes/javax/swing/JList.java index 301813533d7..8d4497d6f9a 100644 --- a/src/java.desktop/share/classes/javax/swing/JList.java +++ b/src/java.desktop/share/classes/javax/swing/JList.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, 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 @@ -2497,6 +2497,9 @@ public class JList extends JComponent implements Scrollable, Accessible /** * Returns the distance to scroll to expose the next or previous * row (for vertical scrolling) or column (for horizontal scrolling). + * The scrolling distance returned will be positive, + * unless scrolling for the specified parameters is already + * at its furthest extent, in which case it will return zero. *

    * For horizontal scrolling, if the layout orientation is {@code VERTICAL}, * then the list's font size is returned (or {@code 1} if the font is @@ -2507,8 +2510,9 @@ public class JList extends JComponent implements Scrollable, Accessible * {@code SwingConstants.VERTICAL} * @param direction less or equal to zero to scroll up/back, * greater than zero for down/forward - * @return the "unit" increment for scrolling in the specified direction; - * always positive + * @return the non-negative "unit" increment + * for scrolling in the specified direction + * * @see #getScrollableBlockIncrement * @see Scrollable#getScrollableUnitIncrement * @throws IllegalArgumentException if {@code visibleRect} is {@code null}, or @@ -2529,7 +2533,8 @@ public class JList extends JComponent implements Scrollable, Accessible /* Scroll Down */ if (direction > 0) { Rectangle r = getCellBounds(row, row); - return (r == null) ? 0 : r.height - (visibleRect.y - r.y); + return (r == null) ? 0 : + ((r.height - (visibleRect.y - r.y)) < 0) ? 0 : r.height - (visibleRect.y - r.y); } /* Scroll Up */ else { diff --git a/test/jdk/javax/swing/JList/JListTest.java b/test/jdk/javax/swing/JList/JListTest.java new file mode 100644 index 00000000000..fbc9bda69e3 --- /dev/null +++ b/test/jdk/javax/swing/JList/JListTest.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2025, 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 8364146 + * @key headful + * @summary Verifies JList getScrollableUnitIncrement return non-negative number + * @run main JListTest + */ + +import java.awt.Dimension; +import java.awt.Rectangle; +import javax.swing.JFrame; +import javax.swing.JList; +import javax.swing.JScrollPane; +import javax.swing.SwingConstants; +import javax.swing.SwingUtilities; +public class JListTest { + + private static JFrame f; + + public static void main(String[] argv) throws Exception { + + SwingUtilities.invokeAndWait(() -> { + try { + f = new JFrame(); + String[] data = {"One", "Two", "Three", "Four", "Five", "Six ", + "Seven", "Eight", "Nine", "Ten", "Eleven", "Twelv"}; + JList list = new JList<>(data); + list.setLayoutOrientation(JList.HORIZONTAL_WRAP); + + JScrollPane sp = new JScrollPane(list); + sp.setPreferredSize(new Dimension(200, 200)); + f.add(sp); + f.pack(); + f.setVisible(true); + + Rectangle cell = list.getCellBounds(1, data.length); + System.out.println(cell); + cell.y = list.getHeight() + 10; + int unit = list.getScrollableUnitIncrement( + cell, + SwingConstants.VERTICAL, + -1); + System.out.println("Scrollable unit increment: " + unit); + + if (unit < 0) { + throw new RuntimeException("JList scrollable unit increment should be greater than 0."); + } + unit = list.getScrollableUnitIncrement( + cell, + SwingConstants.VERTICAL, + 1); + System.out.println("Scrollable unit increment: " + unit); + if (unit < 0) { + throw new RuntimeException("JList scrollable unit increment should be greater than 0."); + } + } finally { + if (f != null) { + f.dispose(); + } + } + }); + } +} From 8f3d0ade11ddb45bb1719b6818e1b51df237a59b Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Wed, 3 Dec 2025 08:06:15 +0000 Subject: [PATCH 114/706] 8371893: [macOS] use dead_strip linker option to reduce binary size Reviewed-by: erikj, lucy, serb --- make/autoconf/flags-ldflags.m4 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/make/autoconf/flags-ldflags.m4 b/make/autoconf/flags-ldflags.m4 index 572790b567b..18ec04d92b7 100644 --- a/make/autoconf/flags-ldflags.m4 +++ b/make/autoconf/flags-ldflags.m4 @@ -108,6 +108,9 @@ AC_DEFUN([FLAGS_SETUP_LDFLAGS_HELPER], # Setup OS-dependent LDFLAGS if test "x$OPENJDK_TARGET_OS" = xmacosx && test "x$TOOLCHAIN_TYPE" = xclang; then + if test x$DEBUG_LEVEL = xrelease; then + BASIC_LDFLAGS_JDK_ONLY="$BASIC_LDFLAGS_JDK_ONLY -Wl,-dead_strip" + fi # FIXME: We should really generalize SetSharedLibraryOrigin instead. OS_LDFLAGS_JVM_ONLY="-Wl,-rpath,@loader_path/. -Wl,-rpath,@loader_path/.." OS_LDFLAGS="-mmacosx-version-min=$MACOSX_VERSION_MIN -Wl,-reproducible" From 2139c8c6e6e5c5f2c64ed3ad9ad8bd148a86efae Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Wed, 3 Dec 2025 08:08:14 +0000 Subject: [PATCH 115/706] 8372571: ResourceHashTable for some AOT data structures miss placement operator when allocating Reviewed-by: aboldtch, jsjolen, kvn --- src/hotspot/share/cds/aotMappedHeapWriter.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/cds/aotMappedHeapWriter.cpp b/src/hotspot/share/cds/aotMappedHeapWriter.cpp index 98f400c989c..edd0aede246 100644 --- a/src/hotspot/share/cds/aotMappedHeapWriter.cpp +++ b/src/hotspot/share/cds/aotMappedHeapWriter.cpp @@ -86,9 +86,9 @@ void AOTMappedHeapWriter::init() { if (CDSConfig::is_dumping_heap()) { Universe::heap()->collect(GCCause::_java_lang_system_gc); - _buffer_offset_to_source_obj_table = new BufferOffsetToSourceObjectTable(/*size (prime)*/36137, /*max size*/1 * M); + _buffer_offset_to_source_obj_table = new (mtClassShared) BufferOffsetToSourceObjectTable(/*size (prime)*/36137, /*max size*/1 * M); _dumped_interned_strings = new (mtClass)DumpedInternedStrings(INITIAL_TABLE_SIZE, MAX_TABLE_SIZE); - _fillers = new FillersTable(); + _fillers = new (mtClassShared) FillersTable(); _requested_bottom = nullptr; _requested_top = nullptr; From a1e8694109ad87690e18fc03d17b6b9519092d81 Mon Sep 17 00:00:00 2001 From: Dean Long Date: Wed, 3 Dec 2025 09:01:40 +0000 Subject: [PATCH 116/706] 8371306: JDK-8367002 behavior might not match existing HotSpot behavior. Reviewed-by: thartmann, dholmes --- src/hotspot/share/runtime/sharedRuntime.cpp | 8 ++++++-- .../jtreg/compiler/exceptions/IllegalAccessInCatch.jasm | 1 + .../jtreg/compiler/exceptions/TestAccessErrorInCatch.java | 7 ++++++- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/runtime/sharedRuntime.cpp b/src/hotspot/share/runtime/sharedRuntime.cpp index e277e1fb569..3a7c60cf83e 100644 --- a/src/hotspot/share/runtime/sharedRuntime.cpp +++ b/src/hotspot/share/runtime/sharedRuntime.cpp @@ -809,6 +809,8 @@ address SharedRuntime::compute_compiled_exc_handler(nmethod* nm, address ret_pc, // determine handler bci, if any EXCEPTION_MARK; + Handle orig_exception(THREAD, exception()); + int handler_bci = -1; int scope_depth = 0; if (!force_unwind) { @@ -830,7 +832,7 @@ address SharedRuntime::compute_compiled_exc_handler(nmethod* nm, address ret_pc, // thrown (bugs 4307310 and 4546590). Set "exception" reference // argument to ensure that the correct exception is thrown (4870175). recursive_exception_occurred = true; - exception = Handle(THREAD, PENDING_EXCEPTION); + exception.replace(PENDING_EXCEPTION); CLEAR_PENDING_EXCEPTION; if (handler_bci >= 0) { bci = handler_bci; @@ -859,8 +861,10 @@ address SharedRuntime::compute_compiled_exc_handler(nmethod* nm, address ret_pc, // If the compiler did not anticipate a recursive exception, resulting in an exception // thrown from the catch bci, then the compiled exception handler might be missing. - // This is rare. Just deoptimize and let the interpreter handle it. + // This is rare. Just deoptimize and let the interpreter rethrow the original + // exception at the original bci. if (t == nullptr && recursive_exception_occurred) { + exception.replace(orig_exception()); // restore original exception bool make_not_entrant = false; return Deoptimization::deoptimize_for_missing_exception_handler(nm, make_not_entrant); } diff --git a/test/hotspot/jtreg/compiler/exceptions/IllegalAccessInCatch.jasm b/test/hotspot/jtreg/compiler/exceptions/IllegalAccessInCatch.jasm index beeffa69a97..78be0bbb177 100644 --- a/test/hotspot/jtreg/compiler/exceptions/IllegalAccessInCatch.jasm +++ b/test/hotspot/jtreg/compiler/exceptions/IllegalAccessInCatch.jasm @@ -46,6 +46,7 @@ super class IllegalAccessInCatch idiv; endtry t0; ireturn; + catch t0 java/lang/IllegalAccessError; catch t0 jdk/internal/agent/AgentConfigurationError; // loadable but not accessible from unnamed module stack_frame_type full; stack_map class java/lang/Throwable; diff --git a/test/hotspot/jtreg/compiler/exceptions/TestAccessErrorInCatch.java b/test/hotspot/jtreg/compiler/exceptions/TestAccessErrorInCatch.java index 44cfd60cf38..fa81fa93f11 100644 --- a/test/hotspot/jtreg/compiler/exceptions/TestAccessErrorInCatch.java +++ b/test/hotspot/jtreg/compiler/exceptions/TestAccessErrorInCatch.java @@ -64,6 +64,11 @@ public class TestAccessErrorInCatch { } private static int invoke(MethodHandle mh) throws Throwable { - return (int) mh.invokeExact(); + int expected = 1; + int ret = (int) mh.invokeExact(); + if (ret != expected) { + throw new RuntimeException("Returned " + ret + " but expected " + expected); + } + return ret; } } From b3e063c2c34ac12ae2a566617560ecc52253262d Mon Sep 17 00:00:00 2001 From: root Date: Wed, 3 Dec 2025 09:04:11 +0000 Subject: [PATCH 117/706] 8372710: Update ProcessBuilder/Basic regex Reviewed-by: shade, amitkumar --- test/jdk/java/lang/ProcessBuilder/Basic.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/jdk/java/lang/ProcessBuilder/Basic.java b/test/jdk/java/lang/ProcessBuilder/Basic.java index 4377752650d..7034174f85c 100644 --- a/test/jdk/java/lang/ProcessBuilder/Basic.java +++ b/test/jdk/java/lang/ProcessBuilder/Basic.java @@ -85,8 +85,8 @@ public class Basic { static final String libpath = System.getenv("LIBPATH"); /* Used for regex String matching for long error messages */ - static final String PERMISSION_DENIED_ERROR_MSG = "(Permission denied|error=13)"; - static final String NO_SUCH_FILE_ERROR_MSG = "(No such file|error=2)"; + static final String PERMISSION_DENIED_ERROR_MSG = "(Permission denied|error:13)"; + static final String NO_SUCH_FILE_ERROR_MSG = "(No such file|error:2)"; static final String SPAWNHELPER_FAILURE_MSG = "(Possible reasons:)"; /** From e65fd45dc7c9383a77fbd5171b541c2a003d30d2 Mon Sep 17 00:00:00 2001 From: Jaikiran Pai Date: Wed, 3 Dec 2025 09:17:08 +0000 Subject: [PATCH 118/706] 8366101: Replace the use of ThreadTracker with ScopedValue in java.util.jar.JarFile Reviewed-by: vyazici, alanb --- .../share/classes/java/util/jar/JarFile.java | 36 +++++++++---------- 1 file changed, 16 insertions(+), 20 deletions(-) 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 dc2d65bcc99..d1a8f1310a9 100644 --- a/src/java.base/share/classes/java/util/jar/JarFile.java +++ b/src/java.base/share/classes/java/util/jar/JarFile.java @@ -27,7 +27,6 @@ package java.util.jar; import jdk.internal.access.SharedSecrets; import jdk.internal.access.JavaUtilZipFileAccess; -import jdk.internal.misc.ThreadTracker; import sun.security.util.ManifestEntryVerifier; import sun.security.util.SignatureFileVerifier; @@ -213,6 +212,9 @@ public class JarFile extends ZipFile { */ static final String INDEX_NAME = "META-INF/INDEX.LIST"; + // this will be set when the thread is initializing a JAR verifier + private static final ScopedValue IN_VERIFIER_INIT = ScopedValue.newInstance(); + /** * Returns the version that represents the unversioned configuration of a * multi-release jar file. @@ -1025,36 +1027,30 @@ public class JarFile extends ZipFile { } } - private static class ThreadTrackHolder { - static final ThreadTracker TRACKER = new ThreadTracker(); - } - - private static Object beginInit() { - return ThreadTrackHolder.TRACKER.begin(); - } - - private static void endInit(Object key) { - ThreadTrackHolder.TRACKER.end(key); - } - synchronized void ensureInitialization() { try { maybeInstantiateVerifier(); } catch (IOException e) { throw new RuntimeException(e); } - if (jv != null && !jvInitialized) { - Object key = beginInit(); - try { + if (jv == null || jvInitialized) { + return; + } + // mark the current thread as initializing + // the JAR verifier + ScopedValue.where(IN_VERIFIER_INIT, true).run(new Runnable() { + @Override + public void run() { initializeVerifier(); jvInitialized = true; - } finally { - endInit(key); } - } + }); } + /** + * {@return true if the current thread is initializing a JAR verifier, false otherwise} + */ static boolean isInitializing() { - return ThreadTrackHolder.TRACKER.contains(Thread.currentThread()); + return IN_VERIFIER_INIT.isBound(); } } From a25e6f6462a5d77a2cb0dcec4f74e5e25d8565c4 Mon Sep 17 00:00:00 2001 From: Ramkumar Sunderbabu Date: Wed, 3 Dec 2025 09:22:13 +0000 Subject: [PATCH 119/706] 8319158: Parallel: Make TestObjectTenuringFlags use createTestJavaProcessBuilder Reviewed-by: stefank, aboldtch --- .../jtreg/gc/arguments/TestObjectTenuringFlags.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/test/hotspot/jtreg/gc/arguments/TestObjectTenuringFlags.java b/test/hotspot/jtreg/gc/arguments/TestObjectTenuringFlags.java index 1590d7ac967..ed087480815 100644 --- a/test/hotspot/jtreg/gc/arguments/TestObjectTenuringFlags.java +++ b/test/hotspot/jtreg/gc/arguments/TestObjectTenuringFlags.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, 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 gc.arguments; /* * @test TestObjectTenuringFlags * @bug 6521376 - * @requires vm.gc.Parallel + * @requires vm.gc.Parallel & vm.opt.NeverTenure == null & vm.opt.AlwaysTenure == null + * & vm.opt.MaxTenuringThreshold == null & vm.opt.InitialTenuringThreshold == null * @summary Tests argument processing for NeverTenure, AlwaysTenure, * and MaxTenuringThreshold * @library /test/lib @@ -161,7 +162,7 @@ public class TestObjectTenuringFlags { } Collections.addAll(vmOpts, "-XX:+UseParallelGC", "-XX:+PrintFlagsFinal", "-version"); - OutputAnalyzer output = GCArguments.executeLimitedTestJava(vmOpts); + OutputAnalyzer output = GCArguments.executeTestJava(vmOpts); if (shouldFail) { output.shouldHaveExitValue(1); From 177f3404dfb146be724d952f8c88b4d070e36b52 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Wed, 3 Dec 2025 09:24:33 +0000 Subject: [PATCH 120/706] 8372733: GHA: Bump to Ubuntu 24.04 Reviewed-by: erikj, ayang --- .github/workflows/build-alpine-linux.yml | 2 +- .github/workflows/build-cross-compile.yml | 2 +- .github/workflows/build-linux.yml | 20 ++++++++++++++++---- .github/workflows/main.yml | 6 +++--- 4 files changed, 21 insertions(+), 9 deletions(-) diff --git a/.github/workflows/build-alpine-linux.yml b/.github/workflows/build-alpine-linux.yml index 0d366a4bdd0..a39b342a248 100644 --- a/.github/workflows/build-alpine-linux.yml +++ b/.github/workflows/build-alpine-linux.yml @@ -59,7 +59,7 @@ on: jobs: build-linux: name: build - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 container: image: alpine:3.20 diff --git a/.github/workflows/build-cross-compile.yml b/.github/workflows/build-cross-compile.yml index b3c63f488a0..e70937f57b6 100644 --- a/.github/workflows/build-cross-compile.yml +++ b/.github/workflows/build-cross-compile.yml @@ -48,7 +48,7 @@ on: jobs: build-cross-compile: name: build - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 strategy: fail-fast: false diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml index f398625cb2c..0680dea6bbe 100644 --- a/.github/workflows/build-linux.yml +++ b/.github/workflows/build-linux.yml @@ -75,7 +75,7 @@ on: jobs: build-linux: name: build - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 strategy: fail-fast: false @@ -115,9 +115,21 @@ jobs: if [[ '${{ inputs.apt-architecture }}' != '' ]]; then sudo dpkg --add-architecture ${{ inputs.apt-architecture }} fi - sudo apt-get update - sudo apt-get install --only-upgrade apt - sudo apt-get install gcc-${{ inputs.gcc-major-version }}${{ inputs.gcc-package-suffix }} g++-${{ inputs.gcc-major-version }}${{ inputs.gcc-package-suffix }} libxrandr-dev${{ steps.arch.outputs.suffix }} libxtst-dev${{ steps.arch.outputs.suffix }} libcups2-dev${{ steps.arch.outputs.suffix }} libasound2-dev${{ steps.arch.outputs.suffix }} ${{ inputs.apt-extra-packages }} + sudo apt update + sudo apt install --only-upgrade apt + sudo apt install \ + gcc-${{ inputs.gcc-major-version }}${{ inputs.gcc-package-suffix }} \ + g++-${{ inputs.gcc-major-version }}${{ inputs.gcc-package-suffix }} \ + libasound2-dev${{ steps.arch.outputs.suffix }} \ + libcups2-dev${{ steps.arch.outputs.suffix }} \ + libfontconfig1-dev${{ steps.arch.outputs.suffix }} \ + libx11-dev${{ steps.arch.outputs.suffix }} \ + libxext-dev${{ steps.arch.outputs.suffix }} \ + libxrandr-dev${{ steps.arch.outputs.suffix }} \ + libxrender-dev${{ steps.arch.outputs.suffix }} \ + libxt-dev${{ steps.arch.outputs.suffix }} \ + libxtst-dev${{ steps.arch.outputs.suffix }} \ + ${{ inputs.apt-extra-packages }} sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-${{ inputs.gcc-major-version }} 100 --slave /usr/bin/g++ g++ /usr/bin/g++-${{ inputs.gcc-major-version }} - name: 'Configure' diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 4d1e8a8be3d..09e6ed65a47 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -57,7 +57,7 @@ jobs: prepare: name: 'Prepare the run' - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 env: # List of platforms to exclude by default EXCLUDED_PLATFORMS: 'alpine-linux-x64' @@ -405,7 +405,7 @@ jobs: with: platform: linux-x64 bootjdk-platform: linux-x64 - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 dry-run: ${{ needs.prepare.outputs.dry-run == 'true' }} debug-suffix: -debug @@ -419,7 +419,7 @@ jobs: with: platform: linux-x64 bootjdk-platform: linux-x64 - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 dry-run: ${{ needs.prepare.outputs.dry-run == 'true' }} static-suffix: "-static" From 3e04e11482605e7734ef75bc477fe31107988f42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20=C3=96sterlund?= Date: Wed, 3 Dec 2025 09:28:30 +0000 Subject: [PATCH 121/706] 8372738: ZGC: C2 allocation reloc promotion deopt race Reviewed-by: aboldtch, stefank --- src/hotspot/share/gc/z/zBarrierSet.cpp | 7 ++-- src/hotspot/share/gc/z/zGeneration.cpp | 3 +- src/hotspot/share/gc/z/zPage.cpp | 11 ++++- src/hotspot/share/gc/z/zPage.hpp | 4 ++ src/hotspot/share/gc/z/zRelocate.cpp | 39 +++++++++++------- src/hotspot/share/gc/z/zRelocate.hpp | 3 +- src/hotspot/share/gc/z/zRelocationSet.cpp | 49 +++++++++++++++++------ src/hotspot/share/gc/z/zRelocationSet.hpp | 4 ++ 8 files changed, 85 insertions(+), 35 deletions(-) diff --git a/src/hotspot/share/gc/z/zBarrierSet.cpp b/src/hotspot/share/gc/z/zBarrierSet.cpp index 643eba1947e..15b694b2ecc 100644 --- a/src/hotspot/share/gc/z/zBarrierSet.cpp +++ b/src/hotspot/share/gc/z/zBarrierSet.cpp @@ -217,11 +217,10 @@ static void deoptimize_allocation(JavaThread* thread) { void ZBarrierSet::on_slowpath_allocation_exit(JavaThread* thread, oop new_obj) { const ZPage* const page = ZHeap::heap()->page(to_zaddress(new_obj)); - const ZPageAge age = page->age(); - if (age == ZPageAge::old) { + if (!page->allows_raw_null()) { // We promised C2 that its allocations would end up in young gen. This object - // breaks that promise. Take a few steps in the interpreter instead, which has - // no such assumptions about where an object resides. + // is too old to guarantee that. Take a few steps in the interpreter instead, + // which does not elide barriers based on the age of an object. deoptimize_allocation(thread); } } diff --git a/src/hotspot/share/gc/z/zGeneration.cpp b/src/hotspot/share/gc/z/zGeneration.cpp index 2b632ef29a9..a8c646bf895 100644 --- a/src/hotspot/share/gc/z/zGeneration.cpp +++ b/src/hotspot/share/gc/z/zGeneration.cpp @@ -190,7 +190,8 @@ void ZGeneration::flip_age_pages(const ZRelocationSetSelector* selector) { ZRendezvousHandshakeClosure cl; Handshake::execute(&cl); - _relocate.barrier_flip_promoted_pages(_relocation_set.flip_promoted_pages()); + _relocate.barrier_promoted_pages(_relocation_set.flip_promoted_pages(), + _relocation_set.relocate_promoted_pages()); } static double fragmentation_limit(ZGenerationId generation) { diff --git a/src/hotspot/share/gc/z/zPage.cpp b/src/hotspot/share/gc/z/zPage.cpp index 9f4654a655f..b6e0d162ef0 100644 --- a/src/hotspot/share/gc/z/zPage.cpp +++ b/src/hotspot/share/gc/z/zPage.cpp @@ -41,7 +41,8 @@ ZPage::ZPage(ZPageType type, ZPageAge age, const ZVirtualMemory& vmem, ZMultiPar _top(to_zoffset_end(start())), _livemap(object_max_count()), _remembered_set(), - _multi_partition_tracker(multi_partition_tracker) { + _multi_partition_tracker(multi_partition_tracker), + _relocate_promoted(false) { assert(!_virtual.is_null(), "Should not be null"); assert((_type == ZPageType::small && size() == ZPageSizeSmall) || (_type == ZPageType::medium && ZPageSizeMediumMin <= size() && size() <= ZPageSizeMediumMax) || @@ -70,6 +71,14 @@ ZPage* ZPage::clone_for_promotion() const { return page; } +bool ZPage::allows_raw_null() const { + return is_young() && !AtomicAccess::load(&_relocate_promoted); +} + +void ZPage::set_is_relocate_promoted() { + AtomicAccess::store(&_relocate_promoted, true); +} + ZGeneration* ZPage::generation() { return ZGeneration::generation(_generation_id); } diff --git a/src/hotspot/share/gc/z/zPage.hpp b/src/hotspot/share/gc/z/zPage.hpp index 96900a37680..0fc134e170a 100644 --- a/src/hotspot/share/gc/z/zPage.hpp +++ b/src/hotspot/share/gc/z/zPage.hpp @@ -52,6 +52,7 @@ private: ZLiveMap _livemap; ZRememberedSet _remembered_set; ZMultiPartitionTracker* const _multi_partition_tracker; + volatile bool _relocate_promoted; const char* type_to_string() const; @@ -103,6 +104,9 @@ public: ZPageAge age() const; + bool allows_raw_null() const; + void set_is_relocate_promoted(); + uint32_t seqnum() const; bool is_allocating() const; bool is_relocatable() const; diff --git a/src/hotspot/share/gc/z/zRelocate.cpp b/src/hotspot/share/gc/z/zRelocate.cpp index 24c4bdeac16..da07f67d859 100644 --- a/src/hotspot/share/gc/z/zRelocate.cpp +++ b/src/hotspot/share/gc/z/zRelocate.cpp @@ -1366,27 +1366,35 @@ public: class ZPromoteBarrierTask : public ZTask { private: - ZArrayParallelIterator _iter; + ZArrayParallelIterator _flip_promoted_iter; + ZArrayParallelIterator _relocate_promoted_iter; public: - ZPromoteBarrierTask(const ZArray* pages) + ZPromoteBarrierTask(const ZArray* flip_promoted_pages, + const ZArray* relocate_promoted_pages) : ZTask("ZPromoteBarrierTask"), - _iter(pages) {} + _flip_promoted_iter(flip_promoted_pages), + _relocate_promoted_iter(relocate_promoted_pages) {} virtual void work() { SuspendibleThreadSetJoiner sts_joiner; - for (ZPage* page; _iter.next(&page);) { - // When promoting an object (and before relocate start), we must ensure that all - // contained zpointers are store good. The marking code ensures that for non-null - // pointers, but null pointers are ignored. This code ensures that even null pointers - // are made store good, for the promoted objects. - page->object_iterate([&](oop obj) { - ZIterator::basic_oop_iterate_safe(obj, ZBarrier::promote_barrier_on_young_oop_field); - }); + auto promote_barriers = [&](ZArrayParallelIterator* iter) { + for (ZPage* page; iter->next(&page);) { + // When promoting an object (and before relocate start), we must ensure that all + // contained zpointers are store good. The marking code ensures that for non-null + // pointers, but null pointers are ignored. This code ensures that even null pointers + // are made store good, for the promoted objects. + page->object_iterate([&](oop obj) { + ZIterator::basic_oop_iterate_safe(obj, ZBarrier::promote_barrier_on_young_oop_field); + }); - SuspendibleThreadSet::yield(); - } + SuspendibleThreadSet::yield(); + } + }; + + promote_barriers(&_flip_promoted_iter); + promote_barriers(&_relocate_promoted_iter); } }; @@ -1395,8 +1403,9 @@ void ZRelocate::flip_age_pages(const ZArray* pages) { workers()->run(&flip_age_task); } -void ZRelocate::barrier_flip_promoted_pages(const ZArray* pages) { - ZPromoteBarrierTask promote_barrier_task(pages); +void ZRelocate::barrier_promoted_pages(const ZArray* flip_promoted_pages, + const ZArray* relocate_promoted_pages) { + ZPromoteBarrierTask promote_barrier_task(flip_promoted_pages, relocate_promoted_pages); workers()->run(&promote_barrier_task); } diff --git a/src/hotspot/share/gc/z/zRelocate.hpp b/src/hotspot/share/gc/z/zRelocate.hpp index 50111f24ee5..038efba83eb 100644 --- a/src/hotspot/share/gc/z/zRelocate.hpp +++ b/src/hotspot/share/gc/z/zRelocate.hpp @@ -119,7 +119,8 @@ public: void relocate(ZRelocationSet* relocation_set); void flip_age_pages(const ZArray* pages); - void barrier_flip_promoted_pages(const ZArray* pages); + void barrier_promoted_pages(const ZArray* flip_promoted_pages, + const ZArray* relocate_promoted_pages); void synchronize(); void desynchronize(); diff --git a/src/hotspot/share/gc/z/zRelocationSet.cpp b/src/hotspot/share/gc/z/zRelocationSet.cpp index fb865934690..95ca6e56c45 100644 --- a/src/hotspot/share/gc/z/zRelocationSet.cpp +++ b/src/hotspot/share/gc/z/zRelocationSet.cpp @@ -38,6 +38,7 @@ class ZRelocationSetInstallTask : public ZTask { private: + ZRelocationSet* _relocation_set; ZForwardingAllocator* const _allocator; ZForwarding** _forwardings; const size_t _nforwardings; @@ -54,16 +55,6 @@ private: page->log_msg(" (relocation selected)"); _forwardings[index] = forwarding; - - if (forwarding->is_promotion()) { - // Before promoting an object (and before relocate start), we must ensure that all - // contained zpointers are store good. The marking code ensures that for non-null - // pointers, but null pointers are ignored. This code ensures that even null pointers - // are made store good, for the promoted objects. - page->object_iterate([&](oop obj) { - ZIterator::basic_oop_iterate_safe(obj, ZBarrier::promote_barrier_on_young_oop_field); - }); - } } void install_small(ZForwarding* forwarding, size_t index) { @@ -78,10 +69,18 @@ private: return ZRelocate::compute_to_age(page->age()); } + void track_if_promoted(ZPage* page, ZForwarding* forwarding, ZArray& relocate_promoted) { + if (forwarding->is_promotion()) { + page->set_is_relocate_promoted(); + relocate_promoted.append(page); + } + } + public: - ZRelocationSetInstallTask(ZForwardingAllocator* allocator, const ZRelocationSetSelector* selector) + ZRelocationSetInstallTask(ZRelocationSet* relocation_set, const ZRelocationSetSelector* selector) : ZTask("ZRelocationSetInstallTask"), - _allocator(allocator), + _relocation_set(relocation_set), + _allocator(&relocation_set->_allocator), _forwardings(nullptr), _nforwardings((size_t)selector->selected_small()->length() + (size_t)selector->selected_medium()->length()), _small(selector->selected_small()), @@ -108,11 +107,14 @@ public: // Join the STS to block out VMThreads while running promote_barrier_on_young_oop_field SuspendibleThreadSetJoiner sts_joiner; + ZArray relocate_promoted; + // Allocate and install forwardings for small pages for (size_t page_index; _small_iter.next_index(&page_index);) { ZPage* page = _small->at(int(page_index)); ZForwarding* const forwarding = ZForwarding::alloc(_allocator, page, to_age(page)); install_small(forwarding, (size_t)_medium->length() + page_index); + track_if_promoted(page, forwarding, relocate_promoted); SuspendibleThreadSet::yield(); } @@ -122,9 +124,12 @@ public: ZPage* page = _medium->at(int(page_index)); ZForwarding* const forwarding = ZForwarding::alloc(_allocator, page, to_age(page)); install_medium(forwarding, page_index); + track_if_promoted(page, forwarding, relocate_promoted); SuspendibleThreadSet::yield(); } + + _relocation_set->register_relocate_promoted(relocate_promoted); } ZForwarding** forwardings() const { @@ -143,6 +148,7 @@ ZRelocationSet::ZRelocationSet(ZGeneration* generation) _nforwardings(0), _promotion_lock(), _flip_promoted_pages(), + _relocate_promoted_pages(), _in_place_relocate_promoted_pages() {} ZWorkers* ZRelocationSet::workers() const { @@ -157,9 +163,13 @@ ZArray* ZRelocationSet::flip_promoted_pages() { return &_flip_promoted_pages; } +ZArray* ZRelocationSet::relocate_promoted_pages() { + return &_relocate_promoted_pages; +} + void ZRelocationSet::install(const ZRelocationSetSelector* selector) { // Install relocation set - ZRelocationSetInstallTask task(&_allocator, selector); + ZRelocationSetInstallTask task(this, selector); workers()->run(&task); _forwardings = task.forwardings(); @@ -189,6 +199,7 @@ void ZRelocationSet::reset(ZPageAllocator* page_allocator) { destroy_and_clear(page_allocator, &_in_place_relocate_promoted_pages); destroy_and_clear(page_allocator, &_flip_promoted_pages); + _relocate_promoted_pages.clear(); } void ZRelocationSet::register_flip_promoted(const ZArray& pages) { @@ -199,6 +210,18 @@ void ZRelocationSet::register_flip_promoted(const ZArray& pages) { } } +void ZRelocationSet::register_relocate_promoted(const ZArray& pages) { + if (pages.is_empty()) { + return; + } + + ZLocker locker(&_promotion_lock); + for (ZPage* const page : pages) { + assert(!_relocate_promoted_pages.contains(page), "no duplicates allowed"); + _relocate_promoted_pages.append(page); + } +} + void ZRelocationSet::register_in_place_relocate_promoted(ZPage* page) { ZLocker locker(&_promotion_lock); assert(!_in_place_relocate_promoted_pages.contains(page), "no duplicates allowed"); diff --git a/src/hotspot/share/gc/z/zRelocationSet.hpp b/src/hotspot/share/gc/z/zRelocationSet.hpp index ee1a9447617..5f54df79805 100644 --- a/src/hotspot/share/gc/z/zRelocationSet.hpp +++ b/src/hotspot/share/gc/z/zRelocationSet.hpp @@ -37,6 +37,7 @@ class ZWorkers; class ZRelocationSet { template friend class ZRelocationSetIteratorImpl; + friend class ZRelocationSetInstallTask; private: ZGeneration* _generation; @@ -45,6 +46,7 @@ private: size_t _nforwardings; ZLock _promotion_lock; ZArray _flip_promoted_pages; + ZArray _relocate_promoted_pages; ZArray _in_place_relocate_promoted_pages; ZWorkers* workers() const; @@ -58,8 +60,10 @@ public: void reset(ZPageAllocator* page_allocator); ZGeneration* generation() const; ZArray* flip_promoted_pages(); + ZArray* relocate_promoted_pages(); void register_flip_promoted(const ZArray& pages); + void register_relocate_promoted(const ZArray& pages); void register_in_place_relocate_promoted(ZPage* page); }; From 858d2e434dd4eb8aa94784bb1cd115554eec5dff Mon Sep 17 00:00:00 2001 From: Jonas Norlinder Date: Wed, 3 Dec 2025 09:35:59 +0000 Subject: [PATCH 122/706] 8372584: [Linux]: Replace reading proc to get thread user CPU time with clock_gettime Reviewed-by: dholmes, kevinw, redestad --- src/hotspot/os/linux/os_linux.cpp | 91 ++++++++----------- src/hotspot/os/linux/os_linux.hpp | 2 +- .../bench/vm/runtime/ThreadMXBeanBench.java | 55 +++++++++++ 3 files changed, 95 insertions(+), 53 deletions(-) create mode 100644 test/micro/org/openjdk/bench/vm/runtime/ThreadMXBeanBench.java diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index cf64c22ddff..880dbeccf7d 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -4305,7 +4305,7 @@ OSReturn os::get_native_priority(const Thread* const thread, // For reference, please, see IEEE Std 1003.1-2004: // http://www.unix.org/single_unix_specification -jlong os::Linux::total_thread_cpu_time(clockid_t clockid) { +jlong os::Linux::thread_cpu_time(clockid_t clockid) { struct timespec tp; int status = clock_gettime(clockid, &tp); assert(status == 0, "clock_gettime error: %s", os::strerror(errno)); @@ -4960,20 +4960,42 @@ int os::open(const char *path, int oflag, int mode) { return fd; } +// Since kernel v2.6.12 the Linux ABI has had support for encoding the clock +// types in the last three bits. Bit 2 indicates whether a cpu clock refers to a +// thread or a process. Bits 1 and 0 give the type: PROF=0, VIRT=1, SCHED=2, or +// FD=3. The clock CPUCLOCK_VIRT (0b001) reports the thread's consumed user +// time. POSIX compliant implementations of pthread_getcpuclockid return the +// clock CPUCLOCK_SCHED (0b010) which reports the thread's consumed system+user +// time (as mandated by the POSIX standard POSIX.1-2024/IEEE Std 1003.1-2024 +// §3.90). +static bool get_thread_clockid(Thread* thread, clockid_t* clockid, bool total) { + constexpr clockid_t CLOCK_TYPE_MASK = 3; + constexpr clockid_t CPUCLOCK_VIRT = 1; + + int rc = pthread_getcpuclockid(thread->osthread()->pthread_id(), clockid); + if (rc != 0) { + // It's possible to encounter a terminated native thread that failed + // to detach itself from the VM - which should result in ESRCH. + assert_status(rc == ESRCH, rc, "pthread_getcpuclockid failed"); + return false; + } + + if (!total) { + clockid_t clockid_tmp = *clockid; + clockid_tmp = (clockid_tmp & ~CLOCK_TYPE_MASK) | CPUCLOCK_VIRT; + *clockid = clockid_tmp; + } + + return true; +} + static jlong user_thread_cpu_time(Thread *thread); static jlong total_thread_cpu_time(Thread *thread) { - clockid_t clockid; - int rc = pthread_getcpuclockid(thread->osthread()->pthread_id(), - &clockid); - if (rc == 0) { - return os::Linux::total_thread_cpu_time(clockid); - } else { - // It's possible to encounter a terminated native thread that failed - // to detach itself from the VM - which should result in ESRCH. - assert_status(rc == ESRCH, rc, "pthread_getcpuclockid failed"); - return -1; - } + clockid_t clockid; + bool success = get_thread_clockid(thread, &clockid, true); + + return success ? os::Linux::thread_cpu_time(clockid) : -1; } // current_thread_cpu_time(bool) and thread_cpu_time(Thread*, bool) @@ -4984,7 +5006,7 @@ static jlong total_thread_cpu_time(Thread *thread) { // the fast estimate available on the platform. jlong os::current_thread_cpu_time() { - return os::Linux::total_thread_cpu_time(CLOCK_THREAD_CPUTIME_ID); + return os::Linux::thread_cpu_time(CLOCK_THREAD_CPUTIME_ID); } jlong os::thread_cpu_time(Thread* thread) { @@ -4993,7 +5015,7 @@ jlong os::thread_cpu_time(Thread* thread) { jlong os::current_thread_cpu_time(bool user_sys_cpu_time) { if (user_sys_cpu_time) { - return os::Linux::total_thread_cpu_time(CLOCK_THREAD_CPUTIME_ID); + return os::Linux::thread_cpu_time(CLOCK_THREAD_CPUTIME_ID); } else { return user_thread_cpu_time(Thread::current()); } @@ -5007,46 +5029,11 @@ jlong os::thread_cpu_time(Thread *thread, bool user_sys_cpu_time) { } } -// -1 on error. static jlong user_thread_cpu_time(Thread *thread) { - pid_t tid = thread->osthread()->thread_id(); - char *s; - char stat[2048]; - size_t statlen; - char proc_name[64]; - int count; - long sys_time, user_time; - char cdummy; - int idummy; - long ldummy; - FILE *fp; + clockid_t clockid; + bool success = get_thread_clockid(thread, &clockid, false); - os::snprintf_checked(proc_name, 64, "/proc/self/task/%d/stat", tid); - fp = os::fopen(proc_name, "r"); - if (fp == nullptr) return -1; - statlen = fread(stat, 1, 2047, fp); - stat[statlen] = '\0'; - fclose(fp); - - // Skip pid and the command string. Note that we could be dealing with - // weird command names, e.g. user could decide to rename java launcher - // to "java 1.4.2 :)", then the stat file would look like - // 1234 (java 1.4.2 :)) R ... ... - // We don't really need to know the command string, just find the last - // occurrence of ")" and then start parsing from there. See bug 4726580. - s = strrchr(stat, ')'); - if (s == nullptr) return -1; - - // Skip blank chars - do { s++; } while (s && isspace((unsigned char) *s)); - - count = sscanf(s,"%c %d %d %d %d %d %lu %lu %lu %lu %lu %lu %lu", - &cdummy, &idummy, &idummy, &idummy, &idummy, &idummy, - &ldummy, &ldummy, &ldummy, &ldummy, &ldummy, - &user_time, &sys_time); - if (count != 13) return -1; - - return (jlong)user_time * (1000000000 / os::Posix::clock_tics_per_second()); + return success ? os::Linux::thread_cpu_time(clockid) : -1; } void os::current_thread_cpu_time_info(jvmtiTimerInfo *info_ptr) { diff --git a/src/hotspot/os/linux/os_linux.hpp b/src/hotspot/os/linux/os_linux.hpp index dd07cb600b9..43f70b4af56 100644 --- a/src/hotspot/os/linux/os_linux.hpp +++ b/src/hotspot/os/linux/os_linux.hpp @@ -142,7 +142,7 @@ class os::Linux { static bool manually_expand_stack(JavaThread * t, address addr); static void expand_stack_to(address bottom); - static jlong total_thread_cpu_time(clockid_t clockid); + static jlong thread_cpu_time(clockid_t clockid); static jlong sendfile(int out_fd, int in_fd, jlong* offset, jlong count); diff --git a/test/micro/org/openjdk/bench/vm/runtime/ThreadMXBeanBench.java b/test/micro/org/openjdk/bench/vm/runtime/ThreadMXBeanBench.java new file mode 100644 index 00000000000..f041eb89f5a --- /dev/null +++ b/test/micro/org/openjdk/bench/vm/runtime/ThreadMXBeanBench.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2025, 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.vm.runtime; + +import java.lang.management.ManagementFactory; +import java.lang.management.ThreadMXBean; +import java.util.concurrent.TimeUnit; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Threads; +import org.openjdk.jmh.annotations.Warmup; + +@State(Scope.Benchmark) +@Warmup(iterations = 2, time = 5) +@Measurement(iterations = 5, time = 5) +@BenchmarkMode(Mode.SampleTime) +@OutputTimeUnit(TimeUnit.MILLISECONDS) +@Threads(1) +@Fork(value = 10) +public class ThreadMXBeanBench { + static final ThreadMXBean mxThreadBean = ManagementFactory.getThreadMXBean(); + static long user; // To avoid dead-code elimination + + @Benchmark + public void getCurrentThreadUserTime() throws Throwable { + user = mxThreadBean.getCurrentThreadUserTime(); + } +} From 94977063baafc2e293193d284db408a069f12aca Mon Sep 17 00:00:00 2001 From: Casper Norrbin Date: Wed, 3 Dec 2025 10:03:50 +0000 Subject: [PATCH 123/706] 8358706: Integer overflow with -XX:MinOopMapAllocation=-1 Reviewed-by: phubner, coleenp --- src/hotspot/share/runtime/globals.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp index d002edd48cd..68b5d8254fd 100644 --- a/src/hotspot/share/runtime/globals.hpp +++ b/src/hotspot/share/runtime/globals.hpp @@ -1671,8 +1671,9 @@ const int ObjectAlignmentInBytes = 8; "putback") \ \ /* new oopmap storage allocation */ \ - develop(intx, MinOopMapAllocation, 8, \ + develop(int, MinOopMapAllocation, 8, \ "Minimum number of OopMap entries in an OopMapSet") \ + range(0, max_jint) \ \ /* recompilation */ \ product_pd(intx, CompileThreshold, \ From f1a4d1bfde652cf758117b93bbd02ae8248e805e Mon Sep 17 00:00:00 2001 From: Casper Norrbin Date: Wed, 3 Dec 2025 10:06:01 +0000 Subject: [PATCH 124/706] 8372615: Many container tests fail when running rootless on cgroup v1 Reviewed-by: sgehwolf, dholmes --- .../containers/docker/DockerBasicTest.java | 8 +++--- .../jtreg/containers/docker/ShareTmpDir.java | 8 +++--- .../containers/docker/TestCPUAwareness.java | 7 +++--- .../jtreg/containers/docker/TestCPUSets.java | 10 +++----- .../containers/docker/TestContainerInfo.java | 8 +++--- .../containers/docker/TestJFREvents.java | 5 ++-- .../docker/TestJFRNetworkEvents.java | 8 +++--- .../containers/docker/TestJFRWithJMX.java | 7 +++--- .../jtreg/containers/docker/TestJcmd.java | 3 ++- .../docker/TestJcmdWithSideCar.java | 8 +++--- .../containers/docker/TestLimitsUpdating.java | 9 +++---- .../docker/TestMemoryAwareness.java | 5 +--- .../docker/TestMemoryInvisibleParent.java | 5 +--- .../docker/TestMemoryWithCgroupV1.java | 7 +++--- .../docker/TestMemoryWithSubgroups.java | 5 +--- .../jtreg/containers/docker/TestMisc.java | 16 +++--------- .../jtreg/containers/docker/TestPids.java | 7 +++--- .../platform/docker/TestDockerBasic.java | 9 +++---- .../platform/docker/TestDockerCpuMetrics.java | 7 +++--- .../docker/TestDockerMemoryMetrics.java | 5 ++-- .../TestDockerMemoryMetricsSubgroup.java | 5 +--- .../docker/TestGetFreeSwapSpaceSize.java | 8 +++--- .../platform/docker/TestLimitsUpdating.java | 6 ++--- .../platform/docker/TestPidsLimit.java | 7 +++--- .../platform/docker/TestSystemMetrics.java | 5 +--- .../docker/TestUseContainerSupport.java | 5 +--- .../containers/docker/DockerTestUtils.java | 25 +++++++++++++------ 27 files changed, 83 insertions(+), 125 deletions(-) diff --git a/test/hotspot/jtreg/containers/docker/DockerBasicTest.java b/test/hotspot/jtreg/containers/docker/DockerBasicTest.java index 8e2c0b6a85a..e564cae9d8e 100644 --- a/test/hotspot/jtreg/containers/docker/DockerBasicTest.java +++ b/test/hotspot/jtreg/containers/docker/DockerBasicTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, 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 @@ * @requires !vm.asan * @library /test/lib * @modules java.base/jdk.internal.misc + * java.base/jdk.internal.platform * java.management * jdk.jartool/sun.tools.jar * @build HelloDocker @@ -45,10 +46,7 @@ public class DockerBasicTest { private static final String imageNameAndTag = Common.imageName("basic"); public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - return; - } - + DockerTestUtils.checkCanTestDocker(); DockerTestUtils.buildJdkContainerImage(imageNameAndTag); try { diff --git a/test/hotspot/jtreg/containers/docker/ShareTmpDir.java b/test/hotspot/jtreg/containers/docker/ShareTmpDir.java index 9a4748563bd..a84cdacefa1 100644 --- a/test/hotspot/jtreg/containers/docker/ShareTmpDir.java +++ b/test/hotspot/jtreg/containers/docker/ShareTmpDir.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, 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 @@ * @requires container.support * @requires !vm.asan * @library /test/lib + * @modules java.base/jdk.internal.platform * @build WaitForFlagFile * @run driver ShareTmpDir */ @@ -50,10 +51,7 @@ public class ShareTmpDir { private static final String imageName = Common.imageName("sharetmpdir"); public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - return; - } - + DockerTestUtils.checkCanTestDocker(); DockerTestUtils.buildJdkContainerImage(imageName); try { diff --git a/test/hotspot/jtreg/containers/docker/TestCPUAwareness.java b/test/hotspot/jtreg/containers/docker/TestCPUAwareness.java index 99220201f66..26f160ab27d 100644 --- a/test/hotspot/jtreg/containers/docker/TestCPUAwareness.java +++ b/test/hotspot/jtreg/containers/docker/TestCPUAwareness.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, 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,9 +48,8 @@ public class TestCPUAwareness { private static final int availableCPUs = Runtime.getRuntime().availableProcessors(); public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - return; - } + DockerTestUtils.checkCanTestDocker(); + DockerTestUtils.checkCanUseResourceLimits(); System.out.println("Test Environment: detected availableCPUs = " + availableCPUs); DockerTestUtils.buildJdkContainerImage(imageName); diff --git a/test/hotspot/jtreg/containers/docker/TestCPUSets.java b/test/hotspot/jtreg/containers/docker/TestCPUSets.java index 7894172e401..001914a6686 100644 --- a/test/hotspot/jtreg/containers/docker/TestCPUSets.java +++ b/test/hotspot/jtreg/containers/docker/TestCPUSets.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, 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 @@ * @requires (os.arch != "s390x") * @library /test/lib * @modules java.base/jdk.internal.misc + * java.base/jdk.internal.platform * java.management * jdk.jartool/sun.tools.jar * @build AttemptOOM jdk.test.whitebox.WhiteBox PrintContainerInfo @@ -52,11 +53,8 @@ public class TestCPUSets { private static final String imageName = Common.imageName("cpusets"); public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - return; - } - - + DockerTestUtils.checkCanTestDocker(); + DockerTestUtils.checkCanUseResourceLimits(); Common.prepareWhiteBox(); DockerTestUtils.buildJdkContainerImage(imageName); diff --git a/test/hotspot/jtreg/containers/docker/TestContainerInfo.java b/test/hotspot/jtreg/containers/docker/TestContainerInfo.java index b9b6fb65b75..a5579aa9528 100644 --- a/test/hotspot/jtreg/containers/docker/TestContainerInfo.java +++ b/test/hotspot/jtreg/containers/docker/TestContainerInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2024, Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -31,6 +31,7 @@ * @requires !vm.asan * @library /test/lib * @modules java.base/jdk.internal.misc + * java.base/jdk.internal.platform * java.management * jdk.jartool/sun.tools.jar * @build CheckContainerized jdk.test.whitebox.WhiteBox PrintContainerInfo @@ -49,10 +50,7 @@ public class TestContainerInfo { private static final String imageName = Common.imageName("container-info"); public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - return; - } - + DockerTestUtils.checkCanTestDocker(); Common.prepareWhiteBox(); DockerTestUtils.buildJdkContainerImage(imageName); diff --git a/test/hotspot/jtreg/containers/docker/TestJFREvents.java b/test/hotspot/jtreg/containers/docker/TestJFREvents.java index 4c33ecfc79b..d46c422723b 100644 --- a/test/hotspot/jtreg/containers/docker/TestJFREvents.java +++ b/test/hotspot/jtreg/containers/docker/TestJFREvents.java @@ -34,6 +34,7 @@ * @modules java.base/jdk.internal.platform * @library /test/lib * @modules java.base/jdk.internal.misc + * java.base/jdk.internal.platform * java.management * jdk.jartool/sun.tools.jar * @build JfrReporter jdk.test.whitebox.WhiteBox @@ -61,9 +62,7 @@ public class TestJFREvents { public static void main(String[] args) throws Exception { System.out.println("Test Environment: detected availableCPUs = " + availableCPUs); - if (!DockerTestUtils.canTestDocker()) { - return; - } + DockerTestUtils.checkCanTestDocker(); // If cgroups is not configured, report success. Metrics metrics = Metrics.systemMetrics(); diff --git a/test/hotspot/jtreg/containers/docker/TestJFRNetworkEvents.java b/test/hotspot/jtreg/containers/docker/TestJFRNetworkEvents.java index c0dde368d1e..2c7120c577c 100644 --- a/test/hotspot/jtreg/containers/docker/TestJFRNetworkEvents.java +++ b/test/hotspot/jtreg/containers/docker/TestJFRNetworkEvents.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, 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 @@ * @requires !vm.asan * @library /test/lib * @modules java.base/jdk.internal.misc + * java.base/jdk.internal.platform * java.management * jdk.jartool/sun.tools.jar * @build JfrNetwork @@ -48,10 +49,7 @@ public class TestJFRNetworkEvents { public static void main(String[] args) throws Exception { System.out.println("Test Environment: detected availableCPUs = " + availableCPUs); - if (!DockerTestUtils.canTestDocker()) { - return; - } - + DockerTestUtils.checkCanTestDocker(); DockerTestUtils.buildJdkContainerImage(imageName); try { diff --git a/test/hotspot/jtreg/containers/docker/TestJFRWithJMX.java b/test/hotspot/jtreg/containers/docker/TestJFRWithJMX.java index efe1fa4ffbc..7c26af9b27a 100644 --- a/test/hotspot/jtreg/containers/docker/TestJFRWithJMX.java +++ b/test/hotspot/jtreg/containers/docker/TestJFRWithJMX.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, 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 @@ * @requires !vm.asan * @library /test/lib * @modules java.base/jdk.internal.misc + * java.base/jdk.internal.platform * java.management * jdk.jartool/sun.tools.jar * @build EventProducer @@ -73,9 +74,7 @@ public class TestJFRWithJMX { static final AtomicReference ipAddr = new AtomicReference(); public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - throw new SkippedException("Docker is not supported on this host"); - } + DockerTestUtils.checkCanTestDocker(); if (DockerTestUtils.isPodman() & !Platform.isRoot()) { throw new SkippedException("test cannot be run under rootless podman configuration"); diff --git a/test/hotspot/jtreg/containers/docker/TestJcmd.java b/test/hotspot/jtreg/containers/docker/TestJcmd.java index 8c210544bb6..3cfe2945e92 100644 --- a/test/hotspot/jtreg/containers/docker/TestJcmd.java +++ b/test/hotspot/jtreg/containers/docker/TestJcmd.java @@ -29,6 +29,7 @@ * @requires container.support * @requires vm.flagless * @modules java.base/jdk.internal.misc + * java.base/jdk.internal.platform * java.management * jdk.jartool/sun.tools.jar * @library /test/lib @@ -62,7 +63,7 @@ public class TestJcmd { public static void main(String[] args) throws Exception { - DockerTestUtils.canTestDocker(); + DockerTestUtils.checkCanTestDocker(); // podman versions below 3.3.1 hava a bug where cross-container testing with correct // permissions fails. See JDK-8273216 diff --git a/test/hotspot/jtreg/containers/docker/TestJcmdWithSideCar.java b/test/hotspot/jtreg/containers/docker/TestJcmdWithSideCar.java index 91a07012f00..28a7a20553f 100644 --- a/test/hotspot/jtreg/containers/docker/TestJcmdWithSideCar.java +++ b/test/hotspot/jtreg/containers/docker/TestJcmdWithSideCar.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, 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,6 +33,7 @@ * @requires vm.flagless * @requires !vm.asan * @modules java.base/jdk.internal.misc + * java.base/jdk.internal.platform * java.management * jdk.jartool/sun.tools.jar * @library /test/lib @@ -95,10 +96,7 @@ public class TestJcmdWithSideCar { private static final String NET_BIND_SERVICE = "--cap-add=NET_BIND_SERVICE"; public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - return; - } - + DockerTestUtils.checkCanTestDocker(); DockerTestUtils.buildJdkContainerImage(IMAGE_NAME); try { diff --git a/test/hotspot/jtreg/containers/docker/TestLimitsUpdating.java b/test/hotspot/jtreg/containers/docker/TestLimitsUpdating.java index 7b05669085c..df8ba5b6161 100644 --- a/test/hotspot/jtreg/containers/docker/TestLimitsUpdating.java +++ b/test/hotspot/jtreg/containers/docker/TestLimitsUpdating.java @@ -1,6 +1,6 @@ /* * Copyright (c) 2023, Red Hat, Inc. - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -32,6 +32,7 @@ * @requires container.support * @requires !vm.asan * @library /test/lib + * @modules java.base/jdk.internal.platform * @build jdk.test.whitebox.WhiteBox LimitUpdateChecker * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar whitebox.jar jdk.test.whitebox.WhiteBox * @run driver TestLimitsUpdating @@ -54,10 +55,8 @@ public class TestLimitsUpdating { private static final String imageName = Common.imageName("limitsUpdating"); public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - return; - } - + DockerTestUtils.checkCanTestDocker(); + DockerTestUtils.checkCanUseResourceLimits(); Common.prepareWhiteBox(); DockerTestUtils.buildJdkContainerImage(imageName); diff --git a/test/hotspot/jtreg/containers/docker/TestMemoryAwareness.java b/test/hotspot/jtreg/containers/docker/TestMemoryAwareness.java index 10db6487fa2..4cf895156fe 100644 --- a/test/hotspot/jtreg/containers/docker/TestMemoryAwareness.java +++ b/test/hotspot/jtreg/containers/docker/TestMemoryAwareness.java @@ -59,10 +59,7 @@ public class TestMemoryAwareness { } public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - return; - } - + DockerTestUtils.checkCanTestDocker(); Common.prepareWhiteBox(); DockerTestUtils.buildJdkContainerImage(imageName); diff --git a/test/hotspot/jtreg/containers/docker/TestMemoryInvisibleParent.java b/test/hotspot/jtreg/containers/docker/TestMemoryInvisibleParent.java index 68331f26766..4854f663101 100644 --- a/test/hotspot/jtreg/containers/docker/TestMemoryInvisibleParent.java +++ b/test/hotspot/jtreg/containers/docker/TestMemoryInvisibleParent.java @@ -55,10 +55,7 @@ public class TestMemoryInvisibleParent { System.out.println("Cgroup not configured."); return; } - if (!DockerTestUtils.canTestDocker()) { - System.out.println("Unable to run docker tests."); - return; - } + DockerTestUtils.checkCanTestDocker(); ContainerRuntimeVersionTestUtils.checkContainerVersionSupported(); diff --git a/test/hotspot/jtreg/containers/docker/TestMemoryWithCgroupV1.java b/test/hotspot/jtreg/containers/docker/TestMemoryWithCgroupV1.java index 3340f9de03c..1edc98035e4 100644 --- a/test/hotspot/jtreg/containers/docker/TestMemoryWithCgroupV1.java +++ b/test/hotspot/jtreg/containers/docker/TestMemoryWithCgroupV1.java @@ -1,5 +1,6 @@ /* * Copyright (C) 2022, Tencent. All rights reserved. + * Copyright (c) 2025, 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 @@ -51,10 +52,8 @@ public class TestMemoryWithCgroupV1 { return; } if ("cgroupv1".equals(metrics.getProvider())) { - if (!DockerTestUtils.canTestDocker()) { - return; - } - + DockerTestUtils.checkCanTestDocker(); + DockerTestUtils.checkCanUseResourceLimits(); Common.prepareWhiteBox(); DockerTestUtils.buildJdkContainerImage(imageName); diff --git a/test/hotspot/jtreg/containers/docker/TestMemoryWithSubgroups.java b/test/hotspot/jtreg/containers/docker/TestMemoryWithSubgroups.java index 3b901765ee9..35b7bf993f7 100644 --- a/test/hotspot/jtreg/containers/docker/TestMemoryWithSubgroups.java +++ b/test/hotspot/jtreg/containers/docker/TestMemoryWithSubgroups.java @@ -52,10 +52,7 @@ public class TestMemoryWithSubgroups { System.out.println("Cgroup not configured."); return; } - if (!DockerTestUtils.canTestDocker()) { - System.out.println("Unable to run docker tests."); - return; - } + DockerTestUtils.checkCanTestDocker(); ContainerRuntimeVersionTestUtils.checkContainerVersionSupported(); diff --git a/test/hotspot/jtreg/containers/docker/TestMisc.java b/test/hotspot/jtreg/containers/docker/TestMisc.java index 400119dac9d..fca3cef5513 100644 --- a/test/hotspot/jtreg/containers/docker/TestMisc.java +++ b/test/hotspot/jtreg/containers/docker/TestMisc.java @@ -46,14 +46,10 @@ import jtreg.SkippedException; public class TestMisc { - private static final Metrics metrics = Metrics.systemMetrics(); private static final String imageName = Common.imageName("misc"); public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - return; - } - + DockerTestUtils.checkCanTestDocker(); Common.prepareWhiteBox(); DockerTestUtils.buildJdkContainerImage(imageName); @@ -102,14 +98,8 @@ public class TestMisc { // Test the mapping function on cgroups v2. Should also pass on cgroups v1 as it's // a direct mapping there. private static void testPrintContainerInfoCPUShares() throws Exception { - // Test won't work on cgv1 rootless podman since resource limits don't - // work there. - if ("cgroupv1".equals(metrics.getProvider()) && - DockerTestUtils.isPodman() && - DockerTestUtils.isRootless()) { - throw new SkippedException("Resource limits required for testPrintContainerInfoCPUShares(). " + - "This is cgv1 with podman in rootless mode. Test skipped."); - } + // Test won't work on cgv1 rootless since resource limits don't work there. + DockerTestUtils.checkCanUseResourceLimits(); // Anything less than 1024 should return the back-mapped cpu-shares value without // rounding to next multiple of 1024 (on cg v2). Only ensure that we get // 'cpu_shares: ' over 'cpu_shares: no shares'. diff --git a/test/hotspot/jtreg/containers/docker/TestPids.java b/test/hotspot/jtreg/containers/docker/TestPids.java index 7d5f1b0cdf9..0e39268184e 100644 --- a/test/hotspot/jtreg/containers/docker/TestPids.java +++ b/test/hotspot/jtreg/containers/docker/TestPids.java @@ -31,6 +31,7 @@ * @requires !vm.asan * @library /test/lib * @modules java.base/jdk.internal.misc + * java.base/jdk.internal.platform * java.management * @build jdk.test.whitebox.WhiteBox PrintContainerInfo * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar whitebox.jar jdk.test.whitebox.WhiteBox @@ -54,10 +55,8 @@ public class TestPids { static final String warning_kernel_no_pids_support = "WARNING: Your kernel does not support pids limit capabilities"; public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - return; - } - + DockerTestUtils.checkCanTestDocker(); + DockerTestUtils.checkCanUseResourceLimits(); Common.prepareWhiteBox(); DockerTestUtils.buildJdkContainerImage(imageName); diff --git a/test/jdk/jdk/internal/platform/docker/TestDockerBasic.java b/test/jdk/jdk/internal/platform/docker/TestDockerBasic.java index 9a531d692ed..bfc628a25fc 100644 --- a/test/jdk/jdk/internal/platform/docker/TestDockerBasic.java +++ b/test/jdk/jdk/internal/platform/docker/TestDockerBasic.java @@ -1,6 +1,6 @@ /* * Copyright (c) 2022, Red Hat, Inc. - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, 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 @@ * @requires container.support * @requires !vm.asan * @library /test/lib + * @modules java.base/jdk.internal.platform * @run main/timeout=360 TestDockerBasic */ @@ -42,10 +43,8 @@ public class TestDockerBasic { private static final String imageName = Common.imageName("javaDockerBasic"); public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - return; - } - + DockerTestUtils.checkCanTestDocker(); + DockerTestUtils.checkCanUseResourceLimits(); DockerTestUtils.buildJdkContainerImage(imageName); try { diff --git a/test/jdk/jdk/internal/platform/docker/TestDockerCpuMetrics.java b/test/jdk/jdk/internal/platform/docker/TestDockerCpuMetrics.java index ff039913b8f..042996a353b 100644 --- a/test/jdk/jdk/internal/platform/docker/TestDockerCpuMetrics.java +++ b/test/jdk/jdk/internal/platform/docker/TestDockerCpuMetrics.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, 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 @@ -46,9 +46,8 @@ public class TestDockerCpuMetrics { private static final String imageName = Common.imageName("metrics-cpu"); public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - return; - } + DockerTestUtils.checkCanTestDocker(); + DockerTestUtils.checkCanUseResourceLimits(); // These tests create a docker image and run this image with // varying docker cpu options. The arguments passed to the docker diff --git a/test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetrics.java b/test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetrics.java index 2afb5ed93b1..818c2c04a1d 100644 --- a/test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetrics.java +++ b/test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetrics.java @@ -45,9 +45,8 @@ public class TestDockerMemoryMetrics { private static final String imageName = Common.imageName("metrics-memory"); public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - return; - } + DockerTestUtils.checkCanTestDocker(); + DockerTestUtils.checkCanUseResourceLimits(); // These tests create a docker image and run this image with // varying docker memory options. The arguments passed to the docker diff --git a/test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetricsSubgroup.java b/test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetricsSubgroup.java index f9dd405891c..7d5dbca6f7c 100644 --- a/test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetricsSubgroup.java +++ b/test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetricsSubgroup.java @@ -58,10 +58,7 @@ public class TestDockerMemoryMetricsSubgroup { System.out.println("Cgroup not configured."); return; } - if (!DockerTestUtils.canTestDocker()) { - System.out.println("Unable to run docker tests."); - return; - } + DockerTestUtils.checkCanTestDocker(); ContainerRuntimeVersionTestUtils.checkContainerVersionSupported(); diff --git a/test/jdk/jdk/internal/platform/docker/TestGetFreeSwapSpaceSize.java b/test/jdk/jdk/internal/platform/docker/TestGetFreeSwapSpaceSize.java index dc70fe32b16..1e5160330de 100644 --- a/test/jdk/jdk/internal/platform/docker/TestGetFreeSwapSpaceSize.java +++ b/test/jdk/jdk/internal/platform/docker/TestGetFreeSwapSpaceSize.java @@ -29,9 +29,11 @@ * @requires container.support * @requires !vm.asan * @library /test/lib + * @modules java.base/jdk.internal.platform * @build GetFreeSwapSpaceSize * @run driver/timeout=480 TestGetFreeSwapSpaceSize */ + import jdk.test.lib.containers.docker.Common; import jdk.test.lib.containers.docker.DockerRunOptions; import jdk.test.lib.containers.docker.DockerTestUtils; @@ -41,10 +43,8 @@ public class TestGetFreeSwapSpaceSize { private static final String imageName = Common.imageName("osbeanSwapSpace"); public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - return; - } - + DockerTestUtils.checkCanTestDocker(); + DockerTestUtils.checkCanUseResourceLimits(); DockerTestUtils.buildJdkContainerImage(imageName); try { diff --git a/test/jdk/jdk/internal/platform/docker/TestLimitsUpdating.java b/test/jdk/jdk/internal/platform/docker/TestLimitsUpdating.java index e4decb7f903..a3df580fed1 100644 --- a/test/jdk/jdk/internal/platform/docker/TestLimitsUpdating.java +++ b/test/jdk/jdk/internal/platform/docker/TestLimitsUpdating.java @@ -55,10 +55,8 @@ public class TestLimitsUpdating { private static final String imageName = Common.imageName("limitsUpdatingJDK"); public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - return; - } - + DockerTestUtils.checkCanTestDocker(); + DockerTestUtils.checkCanUseResourceLimits(); DockerTestUtils.buildJdkContainerImage(imageName); try { diff --git a/test/jdk/jdk/internal/platform/docker/TestPidsLimit.java b/test/jdk/jdk/internal/platform/docker/TestPidsLimit.java index 033562b3951..87ecae7ee62 100644 --- a/test/jdk/jdk/internal/platform/docker/TestPidsLimit.java +++ b/test/jdk/jdk/internal/platform/docker/TestPidsLimit.java @@ -30,6 +30,7 @@ * @requires container.support * @requires !vm.asan * @library /test/lib + * @modules java.base/jdk.internal.platform * @build TestPidsLimit * @run driver/timeout=480 TestPidsLimit */ @@ -49,10 +50,8 @@ public class TestPidsLimit { private static final int UNLIMITED_PIDS_DOCKER = -1; public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - return; - } - + DockerTestUtils.checkCanTestDocker(); + DockerTestUtils.checkCanUseResourceLimits(); DockerTestUtils.buildJdkContainerImage(imageName); try { diff --git a/test/jdk/jdk/internal/platform/docker/TestSystemMetrics.java b/test/jdk/jdk/internal/platform/docker/TestSystemMetrics.java index 49ec5663478..e6e78bd5cd8 100644 --- a/test/jdk/jdk/internal/platform/docker/TestSystemMetrics.java +++ b/test/jdk/jdk/internal/platform/docker/TestSystemMetrics.java @@ -42,10 +42,7 @@ public class TestSystemMetrics { private static final String imageName = Common.imageName("metrics"); public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - return; - } - + DockerTestUtils.checkCanTestDocker(); DockerTestUtils.buildJdkContainerImage(imageName); try { diff --git a/test/jdk/jdk/internal/platform/docker/TestUseContainerSupport.java b/test/jdk/jdk/internal/platform/docker/TestUseContainerSupport.java index d8d300401a0..e77783f395b 100644 --- a/test/jdk/jdk/internal/platform/docker/TestUseContainerSupport.java +++ b/test/jdk/jdk/internal/platform/docker/TestUseContainerSupport.java @@ -42,10 +42,7 @@ public class TestUseContainerSupport { private static final String imageName = Common.imageName("useContainerSupport"); public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - return; - } - + DockerTestUtils.checkCanTestDocker(); DockerTestUtils.buildJdkContainerImage(imageName); try { diff --git a/test/lib/jdk/test/lib/containers/docker/DockerTestUtils.java b/test/lib/jdk/test/lib/containers/docker/DockerTestUtils.java index 422671d65b7..ec3e6d773b1 100644 --- a/test/lib/jdk/test/lib/containers/docker/DockerTestUtils.java +++ b/test/lib/jdk/test/lib/containers/docker/DockerTestUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, 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 java.util.ArrayList; import java.util.Collections; import java.util.EnumSet; import java.util.List; +import jdk.internal.platform.Metrics; import jdk.test.lib.Container; import jdk.test.lib.Utils; import jdk.test.lib.process.OutputAnalyzer; @@ -47,6 +48,7 @@ import jtreg.SkippedException; public class DockerTestUtils { private static boolean isDockerEngineAvailable = false; private static boolean wasDockerEngineChecked = false; + private static final Metrics metrics = Metrics.systemMetrics(); // Specifies how many lines to copy from child STDOUT to main test output. // Having too many lines in the main test output will result @@ -93,16 +95,12 @@ public class DockerTestUtils { } /** - * Convenience method, will check if docker engine is available and usable; - * will print the appropriate message when not available. + * Checks if the docker engine is available and usable, throws an exception if not. * - * @return true if docker engine is available * @throws Exception */ - public static boolean canTestDocker() throws Exception { - if (isDockerEngineAvailable()) { - return true; - } else { + public static void checkCanTestDocker() throws Exception { + if (!isDockerEngineAvailable()) { throw new SkippedException("Docker engine is not available on this system"); } } @@ -133,6 +131,17 @@ public class DockerTestUtils { return execute(Container.ENGINE_COMMAND, "info", "-f", format).getStdout(); } + /** + * Checks if the engine can use resource limits, throws an exception if not. + * + * @throws Exception + */ + public static void checkCanUseResourceLimits() throws Exception { + if (isRootless() && "cgroupv1".equals(metrics.getProvider())) { + throw new SkippedException("Resource limits are not available on this system"); + } + } + /** * Determine if the engine is running in root-less mode. * From 804ce0a2394cb3f837441976e5ef6eb4b9cab257 Mon Sep 17 00:00:00 2001 From: Richard Reingruber Date: Wed, 3 Dec 2025 10:29:09 +0000 Subject: [PATCH 125/706] 8370473: C2: Better Aligment of Vector Spill Slots Reviewed-by: goetz, mdoerr --- src/hotspot/cpu/aarch64/aarch64.ad | 3 + src/hotspot/cpu/ppc/ppc.ad | 70 ++++++----- src/hotspot/share/opto/chaitin.hpp | 2 +- src/hotspot/share/opto/matcher.cpp | 13 +-- src/hotspot/share/opto/regmask.hpp | 16 +-- .../compiler/lib/ir_framework/IRNode.java | 6 + .../vectorapi/TestVectorSpilling.java | 110 ++++++++++++++++++ 7 files changed, 174 insertions(+), 46 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/vectorapi/TestVectorSpilling.java diff --git a/src/hotspot/cpu/aarch64/aarch64.ad b/src/hotspot/cpu/aarch64/aarch64.ad index 9c76ed24788..b9252cc56ff 100644 --- a/src/hotspot/cpu/aarch64/aarch64.ad +++ b/src/hotspot/cpu/aarch64/aarch64.ad @@ -2003,6 +2003,9 @@ uint MachSpillCopyNode::implementation(C2_MacroAssembler *masm, PhaseRegAlloc *r if (bottom_type()->isa_vect() && !bottom_type()->isa_vectmask()) { uint ireg = ideal_reg(); + DEBUG_ONLY(int algm = MIN2(RegMask::num_registers(ireg), (int)Matcher::stack_alignment_in_slots()) * VMRegImpl::stack_slot_size); + assert((src_lo_rc != rc_stack) || is_aligned(src_offset, algm), "unaligned vector spill sp offset %d (src)", src_offset); + assert((dst_lo_rc != rc_stack) || is_aligned(dst_offset, algm), "unaligned vector spill sp offset %d (dst)", dst_offset); if (ireg == Op_VecA && masm) { int sve_vector_reg_size_in_bytes = Matcher::scalable_vector_reg_size(T_BYTE); if (src_lo_rc == rc_stack && dst_lo_rc == rc_stack) { diff --git a/src/hotspot/cpu/ppc/ppc.ad b/src/hotspot/cpu/ppc/ppc.ad index 87fcf112756..aa00609094e 100644 --- a/src/hotspot/cpu/ppc/ppc.ad +++ b/src/hotspot/cpu/ppc/ppc.ad @@ -1795,10 +1795,13 @@ uint MachSpillCopyNode::implementation(C2_MacroAssembler *masm, PhaseRegAlloc *r return size; // Self copy, no move. if (bottom_type()->isa_vect() != nullptr && ideal_reg() == Op_VecX) { + int src_offset = ra_->reg2offset(src_lo); + int dst_offset = ra_->reg2offset(dst_lo); + DEBUG_ONLY(int algm = MIN2(RegMask::num_registers(ideal_reg()), (int)Matcher::stack_alignment_in_slots()) * VMRegImpl::stack_slot_size); + assert((src_lo_rc != rc_stack) || is_aligned(src_offset, algm), "unaligned vector spill sp offset %d (src)", src_offset); + assert((dst_lo_rc != rc_stack) || is_aligned(dst_offset, algm), "unaligned vector spill sp offset %d (dst)", dst_offset); // Memory->Memory Spill. if (src_lo_rc == rc_stack && dst_lo_rc == rc_stack) { - int src_offset = ra_->reg2offset(src_lo); - int dst_offset = ra_->reg2offset(dst_lo); if (masm) { __ ld(R0, src_offset, R1_SP); __ std(R0, dst_offset, R1_SP); @@ -1806,26 +1809,20 @@ uint MachSpillCopyNode::implementation(C2_MacroAssembler *masm, PhaseRegAlloc *r __ std(R0, dst_offset+8, R1_SP); } size += 16; +#ifndef PRODUCT + if (st != nullptr) { + st->print("%-7s [R1_SP + #%d] -> [R1_SP + #%d] \t// vector spill copy", "SPILL", src_offset, dst_offset); + } +#endif // !PRODUCT } // VectorRegister->Memory Spill. else if (src_lo_rc == rc_vec && dst_lo_rc == rc_stack) { VectorSRegister Rsrc = as_VectorRegister(Matcher::_regEncode[src_lo]).to_vsr(); - int dst_offset = ra_->reg2offset(dst_lo); if (PowerArchitecturePPC64 >= 9) { - if (is_aligned(dst_offset, 16)) { - if (masm) { - __ stxv(Rsrc, dst_offset, R1_SP); // matches storeV16_Power9 - } - size += 4; - } else { - // Other alignment can be used by Vector API (VectorPayload in rearrangeOp, - // observed with VectorRearrangeTest.java on Power9). - if (masm) { - __ addi(R0, R1_SP, dst_offset); - __ stxvx(Rsrc, R0); // matches storeV16_Power9 (regarding element ordering) - } - size += 8; + if (masm) { + __ stxv(Rsrc, dst_offset, R1_SP); // matches storeV16_Power9 } + size += 4; } else { if (masm) { __ addi(R0, R1_SP, dst_offset); @@ -1833,24 +1830,25 @@ uint MachSpillCopyNode::implementation(C2_MacroAssembler *masm, PhaseRegAlloc *r } size += 8; } +#ifndef PRODUCT + if (st != nullptr) { + if (PowerArchitecturePPC64 >= 9) { + st->print("%-7s %s, [R1_SP + #%d] \t// vector spill copy", "STXV", Matcher::regName[src_lo], dst_offset); + } else { + st->print("%-7s R0, R1_SP, %d \t// vector spill copy\n\t" + "%-7s %s, [R0] \t// vector spill copy", "ADDI", dst_offset, "STXVD2X", Matcher::regName[src_lo]); + } + } +#endif // !PRODUCT } // Memory->VectorRegister Spill. else if (src_lo_rc == rc_stack && dst_lo_rc == rc_vec) { VectorSRegister Rdst = as_VectorRegister(Matcher::_regEncode[dst_lo]).to_vsr(); - int src_offset = ra_->reg2offset(src_lo); if (PowerArchitecturePPC64 >= 9) { - if (is_aligned(src_offset, 16)) { - if (masm) { - __ lxv(Rdst, src_offset, R1_SP); - } - size += 4; - } else { - if (masm) { - __ addi(R0, R1_SP, src_offset); - __ lxvx(Rdst, R0); - } - size += 8; + if (masm) { + __ lxv(Rdst, src_offset, R1_SP); } + size += 4; } else { if (masm) { __ addi(R0, R1_SP, src_offset); @@ -1858,6 +1856,16 @@ uint MachSpillCopyNode::implementation(C2_MacroAssembler *masm, PhaseRegAlloc *r } size += 8; } +#ifndef PRODUCT + if (st != nullptr) { + if (PowerArchitecturePPC64 >= 9) { + st->print("%-7s %s, [R1_SP + #%d] \t// vector spill copy", "LXV", Matcher::regName[dst_lo], src_offset); + } else { + st->print("%-7s R0, R1_SP, %d \t// vector spill copy\n\t" + "%-7s %s, [R0] \t// vector spill copy", "ADDI", src_offset, "LXVD2X", Matcher::regName[dst_lo]); + } + } +#endif // !PRODUCT } // VectorRegister->VectorRegister. else if (src_lo_rc == rc_vec && dst_lo_rc == rc_vec) { @@ -1867,6 +1875,12 @@ uint MachSpillCopyNode::implementation(C2_MacroAssembler *masm, PhaseRegAlloc *r __ xxlor(Rdst, Rsrc, Rsrc); } size += 4; +#ifndef PRODUCT + if (st != nullptr) { + st->print("%-7s %s, %s, %s\t// vector spill copy", + "XXLOR", Matcher::regName[dst_lo], Matcher::regName[src_lo], Matcher::regName[src_lo]); + } +#endif // !PRODUCT } else { ShouldNotReachHere(); // No VR spill. diff --git a/src/hotspot/share/opto/chaitin.hpp b/src/hotspot/share/opto/chaitin.hpp index ac072e94e2b..2d4f7eeb3f2 100644 --- a/src/hotspot/share/opto/chaitin.hpp +++ b/src/hotspot/share/opto/chaitin.hpp @@ -144,7 +144,7 @@ public: private: // Number of registers this live range uses when it colors - uint16_t _num_regs; // 2 for Longs and Doubles, 1 for all else + uint16_t _num_regs; // byte size of the value divided by slot size which is 4 // except _num_regs is kill count for fat_proj // For scalable register, num_regs may not be the actual physical register size. diff --git a/src/hotspot/share/opto/matcher.cpp b/src/hotspot/share/opto/matcher.cpp index 159e13d8d23..69098befa38 100644 --- a/src/hotspot/share/opto/matcher.cpp +++ b/src/hotspot/share/opto/matcher.cpp @@ -285,13 +285,12 @@ void Matcher::match( ) { _parm_regs[i].set_pair(reg2, reg1); } - // Finally, make sure the incoming arguments take up an even number of - // words, in case the arguments or locals need to contain doubleword stack - // slots. The rest of the system assumes that stack slot pairs (in - // particular, in the spill area) which look aligned will in fact be - // aligned relative to the stack pointer in the target machine. Double - // stack slots will always be allocated aligned. - _new_SP = OptoReg::Name(align_up(_in_arg_limit, (int)RegMask::SlotsPerLong)); + // Allocated register sets are aligned to their size. Offsets to the stack + // pointer have to be aligned to the size of the access. For this _new_SP is + // aligned to the size of the largest register set with the stack alignment as + // limit and a minimum of SlotsPerLong (2). + int vector_aligment = MIN2(C->max_vector_size(), stack_alignment_in_bytes()) / VMRegImpl::stack_slot_size; + _new_SP = OptoReg::Name(align_up(_in_arg_limit, MAX2((int)RegMask::SlotsPerLong, vector_aligment))); // Compute highest outgoing stack argument as // _new_SP + out_preserve_stack_slots + max(outgoing argument size). diff --git a/src/hotspot/share/opto/regmask.hpp b/src/hotspot/share/opto/regmask.hpp index 453fbb45d33..421031fdf61 100644 --- a/src/hotspot/share/opto/regmask.hpp +++ b/src/hotspot/share/opto/regmask.hpp @@ -354,16 +354,12 @@ public: } // SlotsPerLong is 2, since slots are 32 bits and longs are 64 bits. - // Also, consider the maximum alignment size for a normally allocated - // value. Since we allocate register pairs but not register quads (at - // present), this alignment is SlotsPerLong (== 2). A normally - // aligned allocated register is either a single register, or a pair - // of adjacent registers, the lower-numbered being even. - // See also is_aligned_Pairs() below, and the padding added before - // Matcher::_new_SP to keep allocated pairs aligned properly. - // If we ever go to quad-word allocations, SlotsPerQuad will become - // the controlling alignment constraint. Note that this alignment - // requirement is internal to the allocator, and independent of any + // We allocate single registers for 32 bit values and register pairs for 64 + // bit values. The number of registers allocated for vectors match their size. E.g. for 128 bit + // vectors (VecX) we allocate a set of 4 registers. Allocated sets are adjacent and aligned. + // See RegMask::find_first_set(), is_aligned_pairs(), is_aligned_sets(), and the padding added before + // Matcher::_new_SP to keep allocated pairs and sets aligned properly. + // Note that this alignment requirement is internal to the allocator, and independent of any // particular platform. enum { SlotsPerLong = 2, SlotsPerVecA = 4, diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java index 787dedba9c6..85595b9b632 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java @@ -1257,6 +1257,12 @@ public class IRNode { machOnly(MEM_TO_REG_SPILL_COPY, "MemToRegSpillCopy"); } + public static final String MEM_TO_REG_SPILL_COPY_TYPE = COMPOSITE_PREFIX + "MEM_TO_REG_SPILL_COPY_TYPE" + POSTFIX; + static { + String regex = START + "MemToRegSpillCopy" + MID + IS_REPLACED + ".*" + END; + machOnly(MEM_TO_REG_SPILL_COPY_TYPE, regex); + } + public static final String MIN = PREFIX + "MIN" + POSTFIX; static { beforeMatchingNameRegex(MIN, "Min(I|L)"); diff --git a/test/hotspot/jtreg/compiler/vectorapi/TestVectorSpilling.java b/test/hotspot/jtreg/compiler/vectorapi/TestVectorSpilling.java new file mode 100644 index 00000000000..9d9a85e174c --- /dev/null +++ b/test/hotspot/jtreg/compiler/vectorapi/TestVectorSpilling.java @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2025 SAP SE. 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 compiler.vectorapi; + +import compiler.lib.ir_framework.*; + +import jdk.incubator.vector.IntVector; +import jdk.incubator.vector.VectorSpecies; + +import jdk.test.lib.Asserts; + +/** + * @test + * @bug 8370473 + * @library /test/lib / + * @summary Test alignment of vector spill slots. It should match the vector size. + * @modules jdk.incubator.vector + * @requires vm.opt.final.MaxVectorSize == null | vm.opt.final.MaxVectorSize >= 16 + * + * @run driver compiler.vectorapi.TestVectorSpilling + */ + +public class TestVectorSpilling { + + private static final VectorSpecies I_SPECIES = IntVector.SPECIES_128; + private static int LENGTH = 1024; + + private static int[] ia1; + private static int[] ia2; + private static int[] ir ; + + public static void main(String[] args) { + TestFramework.runWithFlags("--add-modules=jdk.incubator.vector"); + } + + static class LData { + // Rading from a volatile field prevents cse optimization + static volatile long vF = 1042; + + long l1, l2, l3, l4, l5, l6, l7, l8; + public LData() { + l1 = vF; l2 = vF; l3 = vF; l4 = vF; l5 = vF; l6 = vF; l7 = vF; l8 = vF; + } + public long sum() { + return l1 + l2 + l3 + l4 + l5 + l6 + l7 + l8; + } + } + + + @Run(test = "test16ByteSpilling") + static void test16ByteSpilling_runner() { + test16ByteSpilling(1, 2, 3, 4, 5, 6, 7, 8, 9); + } + + @Test + @IR(counts = {IRNode.MEM_TO_REG_SPILL_COPY_TYPE, "vectorx", "> 0"}, + phase = {CompilePhase.FINAL_CODE}, + applyIfCPUFeature= {"rvv", "false"}) + static long test16ByteSpilling(long l1, long l2, long l3, long l4, long l5, long l6, long l7, long l8, + long l9 /* odd stack arg */) { + // To be scalar replaced and spilled to stack + LData d1 = new LData(); + LData d2 = new LData(); + LData d3 = new LData(); + + for (int i = 0; i < LENGTH; i += I_SPECIES.length()) { + IntVector a1v = IntVector.fromArray(I_SPECIES, ia1, i); + IntVector a2v = IntVector.fromArray(I_SPECIES, ia2, i); + int scalar = spillPoint(); + a1v.add(a2v) + .add(scalar).intoArray(ir, i); + } + + return l1 + l2 + l3 + l4 + l5 + l6 + l7 + l8 + l9 + d1.sum() + d2.sum() + d3.sum(); + } + + @DontInline + static int spillPoint() { + return 42; + } + + static { + ia1 = new int[LENGTH]; + ia2 = new int[LENGTH]; + ir = new int[LENGTH]; + } + +} From 170ebdc5b7b5e54cc7bec60944898d35a24d760b Mon Sep 17 00:00:00 2001 From: Igor Rudenko Date: Wed, 3 Dec 2025 10:37:55 +0000 Subject: [PATCH 126/706] 8346657: Improve out of bounds exception messages for MemorySegments Reviewed-by: jvernee, liach, mcimadamore --- .../foreign/AbstractMemorySegmentImpl.java | 58 ++++++++++++------- .../foreign/SegmentBulkOperations.java | 2 +- .../jdk/internal/foreign/StringSupport.java | 6 +- test/jdk/java/foreign/TestSegments.java | 26 +++++++-- 4 files changed, 63 insertions(+), 29 deletions(-) diff --git a/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java b/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java index d7636032c28..a0c8a0a5a4f 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java +++ b/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java @@ -33,6 +33,7 @@ import jdk.internal.reflect.CallerSensitive; import jdk.internal.reflect.Reflection; import jdk.internal.util.ArraysSupport; import jdk.internal.util.Preconditions; +import jdk.internal.vm.annotation.DontInline; import jdk.internal.vm.annotation.ForceInline; import sun.nio.ch.DirectBuffer; @@ -68,7 +69,7 @@ import java.util.stream.StreamSupport; * {@link MappedMemorySegmentImpl}. */ public abstract sealed class AbstractMemorySegmentImpl - implements MemorySegment, SegmentAllocator, BiFunction, RuntimeException> + implements MemorySegment, SegmentAllocator permits HeapMemorySegmentImpl, NativeMemorySegmentImpl { static final JavaNioAccess NIO_ACCESS = SharedSecrets.getJavaNioAccess(); @@ -100,19 +101,19 @@ public abstract sealed class AbstractMemorySegmentImpl @Override public AbstractMemorySegmentImpl asSlice(long offset, long newSize) { - checkBounds(offset, newSize); + checkSliceBounds(offset, newSize); return asSliceNoCheck(offset, newSize); } @Override public AbstractMemorySegmentImpl asSlice(long offset) { - checkBounds(offset, 0); + checkSliceBounds(offset, 0); return asSliceNoCheck(offset, length - offset); } @Override public MemorySegment asSlice(long offset, long newSize, long byteAlignment) { - checkBounds(offset, newSize); + checkSliceBounds(offset, newSize); Utils.checkAlign(byteAlignment); if (!isAlignedForElement(offset, byteAlignment)) { @@ -354,7 +355,7 @@ public abstract sealed class AbstractMemorySegmentImpl @ForceInline public void checkAccess(long offset, long length, boolean readOnly) { checkReadOnly(readOnly); - checkBounds(offset, length); + checkAccessBounds(offset, length); } @ForceInline @@ -398,20 +399,40 @@ public abstract sealed class AbstractMemorySegmentImpl } @ForceInline - void checkBounds(long offset, long length) { - if (length > 0) { - Preconditions.checkIndex(offset, this.length - length + 1, this); - } else if (length < 0 || offset < 0 || - offset > this.length - length) { - throw outOfBoundException(offset, length); + void checkSliceBounds(long offset, long length) { + try { + checkBounds(offset, length); + } catch (IndexOutOfBoundsException e) { + throwOutOfBounds(offset, length, /* isSlice = */ true); } } - @Override - public RuntimeException apply(String s, List numbers) { - long offset = numbers.get(0).longValue(); - long length = byteSize() - numbers.get(1).longValue() + 1; - return outOfBoundException(offset, length); + @ForceInline + void checkAccessBounds(long offset, long length) { + try { + checkBounds(offset, length); + } catch (IndexOutOfBoundsException e) { + throwOutOfBounds(offset, length, /* isSlice = */ false); + } + } + + @ForceInline + private void checkBounds(long offset, long length) { + if (length > 0) { + Preconditions.checkIndex(offset, this.length - length + 1, null); + } else if (length < 0 || offset < 0 || + offset > this.length - length) { + throw new IndexOutOfBoundsException(); + } + } + + @DontInline + private void throwOutOfBounds(long offset, long length, boolean isSlice) { + String action = isSlice ? "get slice" : "access an element"; + String msg = String.format("Out of bound access on segment %s; attempting to %s of length %d at offset %d " + + "which is outside the valid range 0 <= offset+length < byteSize (=%d)", + this, action, length, offset, this.length); + throw new IndexOutOfBoundsException(msg); } @Override @@ -429,11 +450,6 @@ public abstract sealed class AbstractMemorySegmentImpl return scope; } - private IndexOutOfBoundsException outOfBoundException(long offset, long length) { - return new IndexOutOfBoundsException(String.format("Out of bound access on segment %s; new offset = %d; new length = %d", - this, offset, length)); - } - static class SegmentSplitter implements Spliterator { AbstractMemorySegmentImpl segment; long elemCount; diff --git a/src/java.base/share/classes/jdk/internal/foreign/SegmentBulkOperations.java b/src/java.base/share/classes/jdk/internal/foreign/SegmentBulkOperations.java index 5af4bc37692..ab6b78b73ee 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/SegmentBulkOperations.java +++ b/src/java.base/share/classes/jdk/internal/foreign/SegmentBulkOperations.java @@ -194,7 +194,7 @@ public final class SegmentBulkOperations { @ForceInline public static int contentHash(AbstractMemorySegmentImpl segment, long fromOffset, long toOffset) { final long length = toOffset - fromOffset; - segment.checkBounds(fromOffset, length); + segment.checkSliceBounds(fromOffset, length); if (length == 0) { // The state has to be checked explicitly for zero-length segments segment.scope.checkValidState(); diff --git a/src/java.base/share/classes/jdk/internal/foreign/StringSupport.java b/src/java.base/share/classes/jdk/internal/foreign/StringSupport.java index bb6cb2d3915..208c6d54aab 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/StringSupport.java +++ b/src/java.base/share/classes/jdk/internal/foreign/StringSupport.java @@ -145,7 +145,7 @@ public final class StringSupport { final long fromOffset, final long toOffset) { final long length = toOffset - fromOffset; - segment.checkBounds(fromOffset, length); + segment.checkSliceBounds(fromOffset, length); if (length < Byte.BYTES) { // There can be no null terminator present segment.scope.checkValidState(); @@ -179,7 +179,7 @@ public final class StringSupport { final long fromOffset, final long toOffset) { final long length = toOffset - fromOffset; - segment.checkBounds(fromOffset, length); + segment.checkSliceBounds(fromOffset, length); if (length < Short.BYTES) { // There can be no null terminator present segment.scope.checkValidState(); @@ -215,7 +215,7 @@ public final class StringSupport { final long fromOffset, final long toOffset) { final long length = toOffset - fromOffset; - segment.checkBounds(fromOffset, length); + segment.checkSliceBounds(fromOffset, length); if (length < Integer.BYTES) { // There can be no null terminator present segment.scope.checkValidState(); diff --git a/test/jdk/java/foreign/TestSegments.java b/test/jdk/java/foreign/TestSegments.java index 2942b388d50..e9f3e8a87cc 100644 --- a/test/jdk/java/foreign/TestSegments.java +++ b/test/jdk/java/foreign/TestSegments.java @@ -212,14 +212,32 @@ public class TestSegments { } @Test - public void testSegmentOOBMessage() { + public void testSegmentAccessOOBMessage() { try { var segment = Arena.global().allocate(10, 1); segment.getAtIndex(ValueLayout.JAVA_INT, 2); + fail("Expected IndexOutOfBoundsException was not thrown"); } catch (IndexOutOfBoundsException ex) { - assertTrue(ex.getMessage().contains("Out of bound access")); - assertTrue(ex.getMessage().contains("offset = 8")); - assertTrue(ex.getMessage().contains("length = 4")); + assertTrue(ex.getMessage().startsWith("Out of bound access")); + assertTrue(ex.getMessage().endsWith("attempting to access an element of length 4 at offset 8 " + + "which is outside the valid range 0 <= offset+length < byteSize (=10)")); + } catch (Exception ex) { + fail("Unexpected exception type thrown: " + ex); + } + } + + @Test + public void testSegmentSliceOOBMessage() { + try { + var segment = Arena.global().allocate(10, 1); + var slice = segment.asSlice(8, 4); + fail("Expected IndexOutOfBoundsException was not thrown"); + } catch (IndexOutOfBoundsException ex) { + assertTrue(ex.getMessage().startsWith("Out of bound access")); + assertTrue(ex.getMessage().endsWith("attempting to get slice of length 4 at offset 8 " + + "which is outside the valid range 0 <= offset+length < byteSize (=10)")); + } catch (Exception ex) { + fail("Unexpected exception type thrown: " + ex); } } From 3f447edf0e22431628ebb74212f760209ea29d37 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Wed, 3 Dec 2025 10:55:12 +0000 Subject: [PATCH 127/706] 8372862: AArch64: Fix GetAndSet-acquire costs after JDK-8372188 Reviewed-by: dlong, mhaessig --- src/hotspot/cpu/aarch64/aarch64_atomic.ad | 8 ++++---- src/hotspot/cpu/aarch64/aarch64_atomic_ad.m4 | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/hotspot/cpu/aarch64/aarch64_atomic.ad b/src/hotspot/cpu/aarch64/aarch64_atomic.ad index faac2a43110..3b05a637215 100644 --- a/src/hotspot/cpu/aarch64/aarch64_atomic.ad +++ b/src/hotspot/cpu/aarch64/aarch64_atomic.ad @@ -695,7 +695,7 @@ instruct getAndSetP(indirect mem, iRegP newval, iRegPNoSp oldval) %{ instruct getAndSetIAcq(indirect mem, iRegI newval, iRegINoSp oldval) %{ predicate(needs_acquiring_load_exclusive(n)); match(Set oldval (GetAndSetI mem newval)); - ins_cost(2*VOLATILE_REF_COST); + ins_cost(VOLATILE_REF_COST); format %{ "atomic_xchgw_acq $oldval, $newval, [$mem]" %} ins_encode %{ __ atomic_xchgalw($oldval$$Register, $newval$$Register, as_Register($mem$$base)); @@ -706,7 +706,7 @@ instruct getAndSetIAcq(indirect mem, iRegI newval, iRegINoSp oldval) %{ instruct getAndSetLAcq(indirect mem, iRegL newval, iRegLNoSp oldval) %{ predicate(needs_acquiring_load_exclusive(n)); match(Set oldval (GetAndSetL mem newval)); - ins_cost(2*VOLATILE_REF_COST); + ins_cost(VOLATILE_REF_COST); format %{ "atomic_xchg_acq $oldval, $newval, [$mem]" %} ins_encode %{ __ atomic_xchgal($oldval$$Register, $newval$$Register, as_Register($mem$$base)); @@ -717,7 +717,7 @@ instruct getAndSetLAcq(indirect mem, iRegL newval, iRegLNoSp oldval) %{ instruct getAndSetNAcq(indirect mem, iRegN newval, iRegNNoSp oldval) %{ predicate(needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() == 0); match(Set oldval (GetAndSetN mem newval)); - ins_cost(2*VOLATILE_REF_COST); + ins_cost(VOLATILE_REF_COST); format %{ "atomic_xchgw_acq $oldval, $newval, [$mem]" %} ins_encode %{ __ atomic_xchgalw($oldval$$Register, $newval$$Register, as_Register($mem$$base)); @@ -728,7 +728,7 @@ instruct getAndSetNAcq(indirect mem, iRegN newval, iRegNNoSp oldval) %{ instruct getAndSetPAcq(indirect mem, iRegP newval, iRegPNoSp oldval) %{ predicate(needs_acquiring_load_exclusive(n) && (n->as_LoadStore()->barrier_data() == 0)); match(Set oldval (GetAndSetP mem newval)); - ins_cost(2*VOLATILE_REF_COST); + ins_cost(VOLATILE_REF_COST); format %{ "atomic_xchg_acq $oldval, $newval, [$mem]" %} ins_encode %{ __ atomic_xchgal($oldval$$Register, $newval$$Register, as_Register($mem$$base)); diff --git a/src/hotspot/cpu/aarch64/aarch64_atomic_ad.m4 b/src/hotspot/cpu/aarch64/aarch64_atomic_ad.m4 index 721b720873a..dc51754e7f9 100644 --- a/src/hotspot/cpu/aarch64/aarch64_atomic_ad.m4 +++ b/src/hotspot/cpu/aarch64/aarch64_atomic_ad.m4 @@ -187,7 +187,7 @@ ifelse($1$3,PAcq,INDENT(predicate(needs_acquiring_load_exclusive(n) && (n->as_Lo $3,Acq,INDENT(predicate(needs_acquiring_load_exclusive(n));), `dnl') match(Set oldval (GetAndSet$1 mem newval)); - ins_cost(`'ifelse($4,Acq,,2*)VOLATILE_REF_COST); + ins_cost(`'ifelse($3,Acq,,2*)VOLATILE_REF_COST); format %{ "atomic_xchg$2`'ifelse($3,Acq,_acq) $oldval, $newval, [$mem]" %} ins_encode %{ __ atomic_xchg`'ifelse($3,Acq,al)$2($oldval$$Register, $newval$$Register, as_Register($mem$$base)); From 125d1820f1f64e465a6b83360c48715a79e3d165 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Galder=20Zamarre=C3=B1o?= Date: Wed, 3 Dec 2025 11:12:00 +0000 Subject: [PATCH 128/706] 8372393: Document requirement for separate metallib installation with Xcode 26.1.1 Reviewed-by: erikj --- doc/building.html | 5 +++++ doc/building.md | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/doc/building.html b/doc/building.html index 19313ebf43a..8e5a7625371 100644 --- a/doc/building.html +++ b/doc/building.html @@ -541,6 +541,11 @@ href="#apple-xcode">Apple Xcode on some strategies to deal with this.

    It is recommended that you use at least macOS 14 and Xcode 15.4, but earlier versions may also work.

    +

    Starting with Xcode 26, introduced in macOS 26, the Metal toolchain +no longer comes bundled with Xcode, so it needs to be installed +separately. This can either be done via the Xcode's Settings/Components +UI, or in the command line calling +xcodebuild -downloadComponent metalToolchain.

    The standard macOS environment contains the basic tooling needed to build, but for external libraries a package manager is recommended. The JDK uses homebrew in the examples, but diff --git a/doc/building.md b/doc/building.md index 1fbd395a9d1..b626027f101 100644 --- a/doc/building.md +++ b/doc/building.md @@ -352,6 +352,11 @@ on some strategies to deal with this. It is recommended that you use at least macOS 14 and Xcode 15.4, but earlier versions may also work. +Starting with Xcode 26, introduced in macOS 26, the Metal toolchain no longer +comes bundled with Xcode, so it needs to be installed separately. This can +either be done via the Xcode's Settings/Components UI, or in the command line +calling `xcodebuild -downloadComponent metalToolchain`. + The standard macOS environment contains the basic tooling needed to build, but for external libraries a package manager is recommended. The JDK uses [homebrew](https://brew.sh/) in the examples, but feel free to use whatever From a655ea48453a321fb7cadc6ffb6111276497a929 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Galder=20Zamarre=C3=B1o?= Date: Wed, 3 Dec 2025 12:31:26 +0000 Subject: [PATCH 129/706] 8371792: Refactor barrier loop tests out of TestIfMinMax Reviewed-by: chagedorn, epeter, bmaillard --- .../compiler/c2/irTests/TestIfMinMax.java | 38 +------- .../gcbarriers/TestMinMaxLongLoopBarrier.java | 86 +++++++++++++++++++ 2 files changed, 87 insertions(+), 37 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/gcbarriers/TestMinMaxLongLoopBarrier.java diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestIfMinMax.java b/test/hotspot/jtreg/compiler/c2/irTests/TestIfMinMax.java index fdc0a83fb8b..bfcc775efeb 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/TestIfMinMax.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestIfMinMax.java @@ -30,7 +30,7 @@ import jdk.test.lib.Utils; /* * @test - * @bug 8324655 8329797 8331090 + * @bug 8324655 8331090 * @key randomness * @summary Test that if expressions are properly folded into min/max nodes * @library /test/lib / @@ -139,42 +139,6 @@ public class TestIfMinMax { return a <= b ? b : a; } - public class Dummy { - long l; - public Dummy(long l) { this.l = l; } - } - - @Setup - Object[] setupDummyArray() { - Dummy[] arr = new Dummy[512]; - for (int i = 0; i < 512; i++) { - arr[i] = new Dummy(RANDOM.nextLong()); - } - return new Object[] { arr }; - } - - @Test - @Arguments(setup = "setupDummyArray") - @IR(failOn = { IRNode.MAX_L }) - public long testMaxLAndBarrierInLoop(Dummy[] arr) { - long result = 0; - for (int i = 0; i < arr.length; ++i) { - result += Math.max(arr[i].l, 1); - } - return result; - } - - @Test - @Arguments(setup = "setupDummyArray") - @IR(failOn = { IRNode.MIN_L }) - public long testMinLAndBarrierInLoop(Dummy[] arr) { - long result = 0; - for (int i = 0; i < arr.length; ++i) { - result += Math.min(arr[i].l, 1); - } - return result; - } - @Setup static Object[] setupIntArrays() { int[] a = new int[512]; diff --git a/test/hotspot/jtreg/compiler/gcbarriers/TestMinMaxLongLoopBarrier.java b/test/hotspot/jtreg/compiler/gcbarriers/TestMinMaxLongLoopBarrier.java new file mode 100644 index 00000000000..9f2ddc0d20e --- /dev/null +++ b/test/hotspot/jtreg/compiler/gcbarriers/TestMinMaxLongLoopBarrier.java @@ -0,0 +1,86 @@ +/* + * Copyright Amazon.com Inc. 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 compiler.gcbarriers; + +import compiler.lib.ir_framework.Arguments; +import compiler.lib.ir_framework.IR; +import compiler.lib.ir_framework.IRNode; +import compiler.lib.ir_framework.Setup; +import compiler.lib.ir_framework.Test; +import compiler.lib.ir_framework.TestFramework; +import jdk.test.lib.Utils; + +import java.util.Random; + +/* + * @test + * @bug 8329797 + * @key randomness + * @summary Test that MinL/MaxL nodes are removed when GC barriers in loop + * @library /test/lib / + * @run driver ${test.main.class} + */ +public class TestMinMaxLongLoopBarrier { + private static final Random RANDOM = Utils.getRandomInstance(); + + public static void main(String[] args) { + TestFramework.run(); + } + + public class Dummy { + long l; + public Dummy(long l) { this.l = l; } + } + + @Setup + Object[] setupDummyArray() { + Dummy[] arr = new Dummy[512]; + for (int i = 0; i < 512; i++) { + arr[i] = new Dummy(RANDOM.nextLong()); + } + return new Object[] { arr }; + } + + @Test + @Arguments(setup = "setupDummyArray") + @IR(failOn = { IRNode.MAX_L }) + public long testMaxLAndBarrierInLoop(Dummy[] arr) { + long result = 0; + for (int i = 0; i < arr.length; ++i) { + result += Math.max(arr[i].l, 1); + } + return result; + } + + @Test + @Arguments(setup = "setupDummyArray") + @IR(failOn = { IRNode.MIN_L }) + public long testMinLAndBarrierInLoop(Dummy[] arr) { + long result = 0; + for (int i = 0; i < arr.length; ++i) { + result += Math.min(arr[i].l, 1); + } + return result; + } +} From abb75ba656ebe14e9e8e1d4a1765d64dfce9e661 Mon Sep 17 00:00:00 2001 From: Kerem Kat Date: Wed, 3 Dec 2025 13:01:32 +0000 Subject: [PATCH 130/706] 8372587: Put jdk/jfr/jvm/TestWaste.java into the ProblemList Reviewed-by: dholmes --- test/jdk/ProblemList.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 9904bd88626..1d547faf662 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -750,6 +750,7 @@ jdk/jfr/event/compiler/TestCodeSweeper.java 8338127 generic- jdk/jfr/event/oldobject/TestEmergencyDumpAtOOM.java 8371014 aix-ppc64,linux-ppc64le jdk/jfr/event/oldobject/TestShenandoah.java 8342951 generic-all jdk/jfr/event/runtime/TestResidentSetSizeEvent.java 8309846 aix-ppc64 +jdk/jfr/jvm/TestWaste.java 8371630 generic-all ############################################################################ From afb6a0c2fecdb2114715290d5d463c9dccf93c28 Mon Sep 17 00:00:00 2001 From: Alan Bateman Date: Wed, 3 Dec 2025 13:03:51 +0000 Subject: [PATCH 131/706] 8372958: SocketInputStream.read throws SocketException instead of returning -1 when input shutdown Reviewed-by: djelinski, michaelm --- .../classes/sun/nio/ch/NioSocketImpl.java | 23 +- test/jdk/java/net/Socket/AsyncShutdown.java | 50 ++-- .../java/net/vthread/BlockingSocketOps.java | 242 ++++++++---------- .../channels/vthread/BlockingChannelOps.java | 89 ++----- 4 files changed, 171 insertions(+), 233 deletions(-) diff --git a/src/java.base/share/classes/sun/nio/ch/NioSocketImpl.java b/src/java.base/share/classes/sun/nio/ch/NioSocketImpl.java index 5832e7f529a..57935ff5b00 100644 --- a/src/java.base/share/classes/sun/nio/ch/NioSocketImpl.java +++ b/src/java.base/share/classes/sun/nio/ch/NioSocketImpl.java @@ -289,6 +289,7 @@ public final class NioSocketImpl extends SocketImpl implements PlatformSocketImp */ private int implRead(byte[] b, int off, int len, long remainingNanos) throws IOException { int n = 0; + SocketException ex = null; FileDescriptor fd = beginRead(); try { if (connectionReset) @@ -307,18 +308,24 @@ public final class NioSocketImpl extends SocketImpl implements PlatformSocketImp n = tryRead(fd, b, off, len); } } - return n; } catch (InterruptedIOException e) { throw e; } catch (ConnectionResetException e) { connectionReset = true; throw new SocketException("Connection reset"); } catch (IOException ioe) { - // throw SocketException to maintain compatibility - throw asSocketException(ioe); + // translate to SocketException to maintain compatibility + ex = asSocketException(ioe); } finally { endRead(n > 0); } + if (n <= 0 && isInputClosed) { + return -1; + } + if (ex != null) { + throw ex; + } + return n; } /** @@ -411,6 +418,7 @@ public final class NioSocketImpl extends SocketImpl implements PlatformSocketImp */ private int implWrite(byte[] b, int off, int len) throws IOException { int n = 0; + SocketException ex = null; FileDescriptor fd = beginWrite(); try { configureNonBlockingIfNeeded(fd, false); @@ -419,15 +427,18 @@ public final class NioSocketImpl extends SocketImpl implements PlatformSocketImp park(fd, Net.POLLOUT); n = tryWrite(fd, b, off, len); } - return n; } catch (InterruptedIOException e) { throw e; } catch (IOException ioe) { - // throw SocketException to maintain compatibility - throw asSocketException(ioe); + // translate to SocketException to maintain compatibility + ex = asSocketException(ioe); } finally { endWrite(n > 0); } + if (ex != null) { + throw ex; + } + return n; } /** diff --git a/test/jdk/java/net/Socket/AsyncShutdown.java b/test/jdk/java/net/Socket/AsyncShutdown.java index cdc930b360c..159c08075ad 100644 --- a/test/jdk/java/net/Socket/AsyncShutdown.java +++ b/test/jdk/java/net/Socket/AsyncShutdown.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, 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,11 +24,13 @@ /* * @test * @requires (os.family == "linux" | os.family == "mac") - * @run testng AsyncShutdown * @summary Test shutdownInput/shutdownOutput with threads blocked in read/write + * @run junit AsyncShutdown */ import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.ServerSocket; @@ -38,54 +40,56 @@ import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; -import org.testng.annotations.Test; -import static org.testng.Assert.*; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import static org.junit.jupiter.api.Assertions.*; -@Test -public class AsyncShutdown { +class AsyncShutdown { - public void testShutdownInput1() throws IOException { + @ParameterizedTest + @ValueSource(booleans = { false, true }) + void testShutdownInput(boolean timed) throws IOException { withConnection((s1, s2) -> { + InputStream in = s1.getInputStream(); scheduleShutdownInput(s1, 2000); - int n = s1.getInputStream().read(); - assertTrue(n == -1); + if (timed) { + s1.setSoTimeout(30*1000); + } + assertEquals(-1, in.read()); + assertEquals(0, in.available()); }); } - public void testShutdownInput2() throws IOException { - withConnection((s1, s2) -> { - scheduleShutdownInput(s1, 2000); - s1.setSoTimeout(30*1000); - int n = s1.getInputStream().read(); - assertTrue(n == -1); - }); - } - - public void testShutdownOutput1() throws IOException { + @Test + void testShutdownOutput1() throws IOException { withConnection((s1, s2) -> { + OutputStream out = s1.getOutputStream(); scheduleShutdownOutput(s1, 2000); byte[] data = new byte[128*1024]; try { while (true) { - s1.getOutputStream().write(data); + out.write(data); } } catch (IOException expected) { } }); } - public void testShutdownOutput2() throws IOException { + @Test + void testShutdownOutput2() throws IOException { withConnection((s1, s2) -> { s1.setSoTimeout(100); try { s1.getInputStream().read(); - assertTrue(false); + fail(); } catch (SocketTimeoutException e) { } + OutputStream out = s1.getOutputStream(); scheduleShutdownOutput(s1, 2000); byte[] data = new byte[128*1024]; try { while (true) { - s1.getOutputStream().write(data); + out.write(data); } } catch (IOException expected) { } }); diff --git a/test/jdk/java/net/vthread/BlockingSocketOps.java b/test/jdk/java/net/vthread/BlockingSocketOps.java index 3c6b9cd5276..ef58e06b915 100644 --- a/test/jdk/java/net/vthread/BlockingSocketOps.java +++ b/test/jdk/java/net/vthread/BlockingSocketOps.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, 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 @@ -21,15 +21,15 @@ * questions. */ -/** +/* * @test id=default - * @bug 8284161 + * @bug 8284161 8372958 * @summary Test virtual threads doing blocking I/O on java.net Sockets * @library /test/lib * @run junit BlockingSocketOps */ -/** +/* * @test id=poller-modes * @requires (os.family == "linux") | (os.family == "mac") * @library /test/lib @@ -37,7 +37,7 @@ * @run junit/othervm -Djdk.pollerMode=2 BlockingSocketOps */ -/** +/* * @test id=no-vmcontinuations * @requires vm.continuations * @library /test/lib @@ -60,6 +60,8 @@ import java.net.SocketTimeoutException; import jdk.test.lib.thread.VThreadRunner; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; import static org.junit.jupiter.api.Assertions.*; class BlockingSocketOps { @@ -90,19 +92,8 @@ class BlockingSocketOps { /** * Virtual thread blocks in read. */ - @Test - void testSocketRead1() throws Exception { - testSocketRead(0); - } - - /** - * Virtual thread blocks in timed read. - */ - @Test - void testSocketRead2() throws Exception { - testSocketRead(60_000); - } - + @ParameterizedTest + @ValueSource(ints = { 0, 60_000 }) void testSocketRead(int timeout) throws Exception { VThreadRunner.run(() -> { try (var connection = new Connection()) { @@ -202,19 +193,8 @@ class BlockingSocketOps { /** * Socket close while virtual thread blocked in read. */ - @Test - void testSocketReadAsyncClose1() throws Exception { - testSocketReadAsyncClose(0); - } - - /** - * Socket close while virtual thread blocked in timed read. - */ - @Test - void testSocketReadAsyncClose2() throws Exception { - testSocketReadAsyncClose(0); - } - + @ParameterizedTest + @ValueSource(ints = { 0, 60_000 }) void testSocketReadAsyncClose(int timeout) throws Exception { VThreadRunner.run(() -> { try (var connection = new Connection()) { @@ -230,7 +210,34 @@ class BlockingSocketOps { try { int n = s.getInputStream().read(); fail("read " + n); - } catch (SocketException expected) { } + } catch (SocketException expected) { + log(expected); + } + } + }); + } + + /** + * Socket shutdownInput while virtual thread blocked in read. + */ + @ParameterizedTest + @ValueSource(ints = { 0, 60_000 }) + void testSocketReadAsyncShutdownInput(int timeout) throws Exception { + VThreadRunner.run(() -> { + try (var connection = new Connection()) { + Socket s = connection.socket1(); + + // delayed shutdown of input stream + InputStream in = s.getInputStream(); + runAfterParkedAsync(s::shutdownInput); + + // read should return -1 + if (timeout > 0) { + s.setSoTimeout(timeout); + } + assertEquals(-1, in.read()); + assertEquals(0, in.available()); + assertFalse(s.isClosed()); } }); } @@ -238,19 +245,8 @@ class BlockingSocketOps { /** * Virtual thread interrupted while blocked in Socket read. */ - @Test - void testSocketReadInterrupt1() throws Exception { - testSocketReadInterrupt(0); - } - - /** - * Virtual thread interrupted while blocked in Socket read with timeout - */ - @Test - void testSocketReadInterrupt2() throws Exception { - testSocketReadInterrupt(60_000); - } - + @ParameterizedTest + @ValueSource(ints = { 0, 60_000 }) void testSocketReadInterrupt(int timeout) throws Exception { VThreadRunner.run(() -> { try (var connection = new Connection()) { @@ -269,6 +265,7 @@ class BlockingSocketOps { int n = s.getInputStream().read(); fail("read " + n); } catch (SocketException expected) { + log(expected); assertTrue(Thread.interrupted()); assertTrue(s.isClosed()); } @@ -285,7 +282,7 @@ class BlockingSocketOps { try (var connection = new Connection()) { Socket s = connection.socket1(); - // delayedclose of s + // delayed close of s runAfterParkedAsync(s::close); // write to s should block, then throw @@ -295,7 +292,36 @@ class BlockingSocketOps { for (;;) { out.write(ba); } - } catch (SocketException expected) { } + } catch (SocketException expected) { + log(expected); + } + } + }); + } + + /** + * Socket shutdownOutput while virtual thread blocked in write. + */ + @Test + void testSocketWriteAsyncShutdownOutput() throws Exception { + VThreadRunner.run(() -> { + try (var connection = new Connection()) { + Socket s = connection.socket1(); + + // delayed shutdown of output stream + OutputStream out = s.getOutputStream(); + runAfterParkedAsync(s::shutdownOutput); + + // write to s should block, then throw + try { + byte[] ba = new byte[100*1024]; + for (;;) { + out.write(ba); + } + } catch (SocketException expected) { + log(expected); + } + assertFalse(s.isClosed()); } }); } @@ -321,6 +347,7 @@ class BlockingSocketOps { out.write(ba); } } catch (SocketException expected) { + log(expected); assertTrue(Thread.interrupted()); assertTrue(s.isClosed()); } @@ -355,7 +382,9 @@ class BlockingSocketOps { try { s1.getInputStream().read(ba); fail(); - } catch (SocketTimeoutException expected) { } + } catch (SocketTimeoutException expected) { + log(expected); + } } }); } @@ -384,19 +413,8 @@ class BlockingSocketOps { /** * Virtual thread blocks in accept. */ - @Test - void testServerSocketAccept2() throws Exception { - testServerSocketAccept(0); - } - - /** - * Virtual thread blocks in timed accept. - */ - @Test - void testServerSocketAccept3() throws Exception { - testServerSocketAccept(60_000); - } - + @ParameterizedTest + @ValueSource(ints = { 0, 60_000 }) void testServerSocketAccept(int timeout) throws Exception { VThreadRunner.run(() -> { try (var listener = new ServerSocket()) { @@ -422,19 +440,8 @@ class BlockingSocketOps { /** * ServerSocket close while virtual thread blocked in accept. */ - @Test - void testServerSocketAcceptAsyncClose1() throws Exception { - testServerSocketAcceptAsyncClose(0); - } - - /** - * ServerSocket close while virtual thread blocked in timed accept. - */ - @Test - void testServerSocketAcceptAsyncClose2() throws Exception { - testServerSocketAcceptAsyncClose(60_000); - } - + @ParameterizedTest + @ValueSource(ints = { 0, 60_000 }) void testServerSocketAcceptAsyncClose(int timeout) throws Exception { VThreadRunner.run(() -> { try (var listener = new ServerSocket()) { @@ -451,7 +458,9 @@ class BlockingSocketOps { try { listener.accept().close(); fail("connection accepted???"); - } catch (SocketException expected) { } + } catch (SocketException expected) { + log(expected); + } } }); } @@ -459,19 +468,8 @@ class BlockingSocketOps { /** * Virtual thread interrupted while blocked in ServerSocket accept. */ - @Test - void testServerSocketAcceptInterrupt1() throws Exception { - testServerSocketAcceptInterrupt(0); - } - - /** - * Virtual thread interrupted while blocked in ServerSocket accept with timeout. - */ - @Test - void testServerSocketAcceptInterrupt2() throws Exception { - testServerSocketAcceptInterrupt(60_000); - } - + @ParameterizedTest + @ValueSource(ints = { 0, 60_000 }) void testServerSocketAcceptInterrupt(int timeout) throws Exception { VThreadRunner.run(() -> { try (var listener = new ServerSocket()) { @@ -490,6 +488,7 @@ class BlockingSocketOps { listener.accept().close(); fail("connection accepted???"); } catch (SocketException expected) { + log(expected); assertTrue(Thread.interrupted()); assertTrue(listener.isClosed()); } @@ -529,20 +528,9 @@ class BlockingSocketOps { /** * Virtual thread blocks in DatagramSocket receive. */ - @Test - void testDatagramSocketSendReceive2() throws Exception { - testDatagramSocketSendReceive(0); - } - - /** - * Virtual thread blocks in DatagramSocket receive with timeout. - */ - @Test - void testDatagramSocketSendReceive3() throws Exception { - testDatagramSocketSendReceive(60_000); - } - - private void testDatagramSocketSendReceive(int timeout) throws Exception { + @ParameterizedTest + @ValueSource(ints = { 0, 60_000 }) + void testDatagramSocketSendReceive(int timeout) throws Exception { VThreadRunner.run(() -> { try (DatagramSocket s1 = new DatagramSocket(null); DatagramSocket s2 = new DatagramSocket(null)) { @@ -585,7 +573,9 @@ class BlockingSocketOps { try { s.receive(p); fail(); - } catch (SocketTimeoutException expected) { } + } catch (SocketTimeoutException expected) { + log(expected); + } } }); } @@ -593,20 +583,9 @@ class BlockingSocketOps { /** * DatagramSocket close while virtual thread blocked in receive. */ - @Test - void testDatagramSocketReceiveAsyncClose1() throws Exception { - testDatagramSocketReceiveAsyncClose(0); - } - - /** - * DatagramSocket close while virtual thread blocked with timeout. - */ - @Test - void testDatagramSocketReceiveAsyncClose2() throws Exception { - testDatagramSocketReceiveAsyncClose(60_000); - } - - private void testDatagramSocketReceiveAsyncClose(int timeout) throws Exception { + @ParameterizedTest + @ValueSource(ints = { 0, 60_000 }) + void testDatagramSocketReceiveAsyncClose(int timeout) throws Exception { VThreadRunner.run(() -> { try (DatagramSocket s = new DatagramSocket(null)) { InetAddress lh = InetAddress.getLoopbackAddress(); @@ -624,7 +603,9 @@ class BlockingSocketOps { DatagramPacket p = new DatagramPacket(ba, ba.length); s.receive(p); fail(); - } catch (SocketException expected) { } + } catch (SocketException expected) { + log(expected); + } } }); } @@ -632,20 +613,9 @@ class BlockingSocketOps { /** * Virtual thread interrupted while blocked in DatagramSocket receive. */ - @Test - void testDatagramSocketReceiveInterrupt1() throws Exception { - testDatagramSocketReceiveInterrupt(0); - } - - /** - * Virtual thread interrupted while blocked in DatagramSocket receive with timeout. - */ - @Test - void testDatagramSocketReceiveInterrupt2() throws Exception { - testDatagramSocketReceiveInterrupt(60_000); - } - - private void testDatagramSocketReceiveInterrupt(int timeout) throws Exception { + @ParameterizedTest + @ValueSource(ints = { 0, 60_000 }) + void testDatagramSocketReceiveInterrupt(int timeout) throws Exception { VThreadRunner.run(() -> { try (DatagramSocket s = new DatagramSocket(null)) { InetAddress lh = InetAddress.getLoopbackAddress(); @@ -665,6 +635,7 @@ class BlockingSocketOps { s.receive(p); fail(); } catch (SocketException expected) { + log(expected); assertTrue(Thread.interrupted()); assertTrue(s.isClosed()); } @@ -737,4 +708,11 @@ class BlockingSocketOps { } }); } + + /** + * Log to System.err to inline with the JUnit messages. + */ + static void log(Throwable e) { + System.err.println(e); + } } diff --git a/test/jdk/java/nio/channels/vthread/BlockingChannelOps.java b/test/jdk/java/nio/channels/vthread/BlockingChannelOps.java index f04bece07b6..eb2229d927a 100644 --- a/test/jdk/java/nio/channels/vthread/BlockingChannelOps.java +++ b/test/jdk/java/nio/channels/vthread/BlockingChannelOps.java @@ -66,6 +66,8 @@ import java.util.concurrent.locks.LockSupport; import jdk.test.lib.thread.VThreadRunner; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; import static org.junit.jupiter.api.Assertions.*; class BlockingChannelOps { @@ -301,20 +303,9 @@ class BlockingChannelOps { /** * Virtual thread blocks in SocketChannel adaptor read. */ - @Test - void testSocketAdaptorRead1() throws Exception { - testSocketAdaptorRead(0); - } - - /** - * Virtual thread blocks in SocketChannel adaptor read with timeout. - */ - @Test - void testSocketAdaptorRead2() throws Exception { - testSocketAdaptorRead(60_000); - } - - private void testSocketAdaptorRead(int timeout) throws Exception { + @ParameterizedTest + @ValueSource(ints = { 0, 60_000 }) + void testSocketAdaptorRead(int timeout) throws Exception { VThreadRunner.run(() -> { try (var connection = new Connection()) { SocketChannel sc1 = connection.channel1(); @@ -420,20 +411,9 @@ class BlockingChannelOps { /** * Virtual thread blocks in ServerSocketChannel adaptor accept. */ - @Test - void testSocketChannelAdaptorAccept1() throws Exception { - testSocketChannelAdaptorAccept(0); - } - - /** - * Virtual thread blocks in ServerSocketChannel adaptor accept with timeout. - */ - @Test - void testSocketChannelAdaptorAccept2() throws Exception { - testSocketChannelAdaptorAccept(60_000); - } - - private void testSocketChannelAdaptorAccept(int timeout) throws Exception { + @ParameterizedTest + @ValueSource(ints = { 0, 60_000 }) + void testSocketChannelAdaptorAccept(int timeout) throws Exception { VThreadRunner.run(() -> { try (var ssc = ServerSocketChannel.open()) { ssc.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0)); @@ -546,20 +526,9 @@ class BlockingChannelOps { /** * Virtual thread blocks in DatagramSocket adaptor receive. */ - @Test - void testDatagramSocketAdaptorReceive1() throws Exception { - testDatagramSocketAdaptorReceive(0); - } - - /** - * Virtual thread blocks in DatagramSocket adaptor receive with timeout. - */ - @Test - void testDatagramSocketAdaptorReceive2() throws Exception { - testDatagramSocketAdaptorReceive(60_000); - } - - private void testDatagramSocketAdaptorReceive(int timeout) throws Exception { + @ParameterizedTest + @ValueSource(ints = { 0, 60_000 }) + void testDatagramSocketAdaptorReceive(int timeout) throws Exception { VThreadRunner.run(() -> { try (DatagramChannel dc1 = DatagramChannel.open(); DatagramChannel dc2 = DatagramChannel.open()) { @@ -585,21 +554,9 @@ class BlockingChannelOps { /** * DatagramChannel close while virtual thread blocked in adaptor receive. */ - @Test - void testDatagramSocketAdaptorReceiveAsyncClose1() throws Exception { - testDatagramSocketAdaptorReceiveAsyncClose(0); - } - - /** - * DatagramChannel close while virtual thread blocked in adaptor receive - * with timeout. - */ - @Test - void testDatagramSocketAdaptorReceiveAsyncClose2() throws Exception { - testDatagramSocketAdaptorReceiveAsyncClose(60_1000); - } - - private void testDatagramSocketAdaptorReceiveAsyncClose(int timeout) throws Exception { + @ParameterizedTest + @ValueSource(ints = { 0, 60_000 }) + void testDatagramSocketAdaptorReceiveAsyncClose(int timeout) throws Exception { VThreadRunner.run(() -> { try (DatagramChannel dc = DatagramChannel.open()) { InetAddress lh = InetAddress.getLoopbackAddress(); @@ -621,21 +578,9 @@ class BlockingChannelOps { /** * Virtual thread interrupted while blocked in DatagramSocket adaptor receive. */ - @Test - void testDatagramSocketAdaptorReceiveInterrupt1() throws Exception { - testDatagramSocketAdaptorReceiveInterrupt(0); - } - - /** - * Virtual thread interrupted while blocked in DatagramSocket adaptor receive - * with timeout. - */ - @Test - void testDatagramSocketAdaptorReceiveInterrupt2() throws Exception { - testDatagramSocketAdaptorReceiveInterrupt(60_1000); - } - - private void testDatagramSocketAdaptorReceiveInterrupt(int timeout) throws Exception { + @ParameterizedTest + @ValueSource(ints = { 0, 60_000 }) + void testDatagramSocketAdaptorReceiveInterrupt(int timeout) throws Exception { VThreadRunner.run(() -> { try (DatagramChannel dc = DatagramChannel.open()) { InetAddress lh = InetAddress.getLoopbackAddress(); From 135661b4389663b8c2e348d9e61e72cc628636bb Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Wed, 3 Dec 2025 13:36:55 +0000 Subject: [PATCH 132/706] 8372179: Remove Unused ConcurrentHashTable::MultiGetHandle Reviewed-by: dholmes, iwalulya --- .../share/utilities/concurrentHashTable.hpp | 15 +-------------- .../utilities/concurrentHashTable.inline.hpp | 8 -------- .../utilities/test_concurrentHashtable.cpp | 17 ++--------------- 3 files changed, 3 insertions(+), 37 deletions(-) diff --git a/src/hotspot/share/utilities/concurrentHashTable.hpp b/src/hotspot/share/utilities/concurrentHashTable.hpp index 48166b22126..a837a56a19a 100644 --- a/src/hotspot/share/utilities/concurrentHashTable.hpp +++ b/src/hotspot/share/utilities/concurrentHashTable.hpp @@ -451,8 +451,7 @@ class ConcurrentHashTable : public CHeapObj { // All callbacks for get are under critical sections. Other callbacks may be // under critical section or may have locked parts of table. Calling any - // methods on the table during a callback is not supported.Only MultiGetHandle - // supports multiple gets. + // methods on the table during a callback is not supported. // Get methods return true on found item with LOOKUP_FUNC and FOUND_FUNC is // called. @@ -538,18 +537,6 @@ class ConcurrentHashTable : public CHeapObj { // Must be done at a safepoint. void rehash_nodes_to(Thread* thread, ConcurrentHashTable* to_cht); - // Scoped multi getter. - class MultiGetHandle : private ScopedCS { - public: - MultiGetHandle(Thread* thread, ConcurrentHashTable* cht) - : ScopedCS(thread, cht) {} - // In the MultiGetHandle scope you can lookup items matching LOOKUP_FUNC. - // The VALUEs are safe as long as you never save the VALUEs outside the - // scope, e.g. after ~MultiGetHandle(). - template - VALUE* get(LOOKUP_FUNC& lookup_f, bool* grow_hint = nullptr); - }; - private: class BucketsOperation; diff --git a/src/hotspot/share/utilities/concurrentHashTable.inline.hpp b/src/hotspot/share/utilities/concurrentHashTable.inline.hpp index 908405d3617..eeaff0167b2 100644 --- a/src/hotspot/share/utilities/concurrentHashTable.inline.hpp +++ b/src/hotspot/share/utilities/concurrentHashTable.inline.hpp @@ -233,14 +233,6 @@ inline ConcurrentHashTable:: GlobalCounter::critical_section_end(_thread, _cs_context); } -template -template -inline typename CONFIG::Value* ConcurrentHashTable:: - MultiGetHandle::get(LOOKUP_FUNC& lookup_f, bool* grow_hint) -{ - return ScopedCS::_cht->internal_get(ScopedCS::_thread, lookup_f, grow_hint); -} - // HaveDeletables template template diff --git a/test/hotspot/gtest/utilities/test_concurrentHashtable.cpp b/test/hotspot/gtest/utilities/test_concurrentHashtable.cpp index 927b5ff3d42..775f0e17409 100644 --- a/test/hotspot/gtest/utilities/test_concurrentHashtable.cpp +++ b/test/hotspot/gtest/utilities/test_concurrentHashtable.cpp @@ -97,7 +97,6 @@ struct Config : public AllStatic { }; typedef ConcurrentHashTable SimpleTestTable; -typedef ConcurrentHashTable::MultiGetHandle SimpleTestGetHandle; typedef ConcurrentHashTable CustomTestTable; struct SimpleTestLookup { @@ -345,10 +344,6 @@ static void cht_scope(Thread* thr) { SimpleTestLookup stl(val); SimpleTestTable* cht = new SimpleTestTable(); EXPECT_TRUE(cht->insert(thr, stl, val)) << "Insert unique value failed."; - { - SimpleTestGetHandle get_handle(thr, cht); - EXPECT_EQ(*get_handle.get(stl), val) << "Getting a pre-existing value failed."; - } // We do remove here to make sure the value-handle 'unlocked' the table when leaving the scope. EXPECT_TRUE(cht->remove(thr, stl)) << "Removing a pre-existing value failed."; EXPECT_FALSE(cht_get_copy(cht, thr, stl) == val) << "Got a removed value."; @@ -556,7 +551,6 @@ public: }; typedef ConcurrentHashTable TestTable; -typedef ConcurrentHashTable::MultiGetHandle TestGetHandle; struct TestLookup { uintptr_t _val; @@ -788,15 +782,8 @@ public: bool test_loop() { for (uintptr_t v = 0x1; v < 0xFFF; v++ ) { uintptr_t tv; - if (v & 0x1) { - TestLookup tl(v); - tv = cht_get_copy(_cht, this, tl); - } else { - TestLookup tl(v); - TestGetHandle value_handle(this, _cht); - uintptr_t* tmp = value_handle.get(tl); - tv = tmp != nullptr ? *tmp : 0; - } + TestLookup tl(v); + tv = cht_get_copy(_cht, this, tl); EXPECT_TRUE(tv == 0 || tv == v) << "Got unknown value."; } return true; From c0636734bdf19de6ba41c127aef1f090010c6d90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20Sikstr=C3=B6m?= Date: Wed, 3 Dec 2025 14:34:05 +0000 Subject: [PATCH 133/706] 8372993: Serial: max_eden_size is too small after JDK-8368740 Reviewed-by: ayang, aboldtch, stefank --- src/hotspot/share/gc/serial/defNewGeneration.cpp | 5 ++++- .../jtreg/gc/arguments/TestNewSizeFlags.java | 14 ++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/gc/serial/defNewGeneration.cpp b/src/hotspot/share/gc/serial/defNewGeneration.cpp index 0b2ba44c780..9ccc7b95529 100644 --- a/src/hotspot/share/gc/serial/defNewGeneration.cpp +++ b/src/hotspot/share/gc/serial/defNewGeneration.cpp @@ -236,7 +236,10 @@ DefNewGeneration::DefNewGeneration(ReservedSpace rs, // These values are exported as performance counters. uintx size = _virtual_space.reserved_size(); _max_survivor_size = compute_survivor_size(size, SpaceAlignment); - _max_eden_size = size - (2*_max_survivor_size); + + // Eden might grow to be almost as large as the entire young generation. + // We approximate this as the entire virtual space. + _max_eden_size = size; // allocate the performance counters diff --git a/test/hotspot/jtreg/gc/arguments/TestNewSizeFlags.java b/test/hotspot/jtreg/gc/arguments/TestNewSizeFlags.java index 2f454940863..f65f211b812 100644 --- a/test/hotspot/jtreg/gc/arguments/TestNewSizeFlags.java +++ b/test/hotspot/jtreg/gc/arguments/TestNewSizeFlags.java @@ -286,6 +286,20 @@ public class TestNewSizeFlags { if (YOUNG_GC_TYPE == GCTypes.YoungGCType.G1) { return new MemoryUsage(edenUsageInit + survivorUsageInit, 0, edenUsageCommited + survivorUsageCommited, Long.MAX_VALUE); + } else if (YOUNG_GC_TYPE == GCTypes.YoungGCType.DefNew) { + // Eden might grow to be almost the entire young generation, + // so it is approximated as the size for the entire young + // generation. + long youngGenUsageMax = edenUsage.getMax(); + + long combinedSurvivorUsageMax = 2 * survivorUsage.getMax(); + if (combinedSurvivorUsageMax > youngGenUsageMax) { + throw new RuntimeException("Unexpectedly large survivorUsage combined maximum value: " + combinedSurvivorUsageMax); + } + + return new MemoryUsage(edenUsageInit + survivorUsageInit * 2, 0, + edenUsageCommited + survivorUsageCommited * 2, + youngGenUsageMax); } else { return new MemoryUsage(edenUsageInit + survivorUsageInit * 2, 0, edenUsageCommited + survivorUsageCommited * 2, From 44e2d499f84458003aa73a149d1ae44735b71d91 Mon Sep 17 00:00:00 2001 From: Erik Joelsson Date: Wed, 3 Dec 2025 14:38:32 +0000 Subject: [PATCH 134/706] 8372705: The riscv-64 cross-compilation build is failing in the CI Reviewed-by: dholmes, shade --- make/autoconf/flags-ldflags.m4 | 16 +++++++++------- make/autoconf/toolchain.m4 | 2 +- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/make/autoconf/flags-ldflags.m4 b/make/autoconf/flags-ldflags.m4 index 18ec04d92b7..b0dc565b39f 100644 --- a/make/autoconf/flags-ldflags.m4 +++ b/make/autoconf/flags-ldflags.m4 @@ -34,7 +34,7 @@ AC_DEFUN([FLAGS_SETUP_LDFLAGS], FLAGS_SETUP_LDFLAGS_CPU_DEP([TARGET]) # Setup the build toolchain - FLAGS_SETUP_LDFLAGS_CPU_DEP([BUILD], [OPENJDK_BUILD_]) + FLAGS_SETUP_LDFLAGS_CPU_DEP([BUILD], [OPENJDK_BUILD_], [BUILD_]) AC_SUBST(ADLC_LDFLAGS) ]) @@ -52,11 +52,6 @@ AC_DEFUN([FLAGS_SETUP_LDFLAGS_HELPER], # add --no-as-needed to disable default --as-needed link flag on some GCC toolchains # add --icf=all (Identical Code Folding — merges identical functions) BASIC_LDFLAGS="-Wl,-z,defs -Wl,-z,relro -Wl,-z,now -Wl,--no-as-needed -Wl,--exclude-libs,ALL" - if test "x$LINKER_TYPE" = "xgold"; then - if test x$DEBUG_LEVEL = xrelease; then - BASIC_LDFLAGS="$BASIC_LDFLAGS -Wl,--icf=all" - fi - fi # Linux : remove unused code+data in link step if test "x$ENABLE_LINKTIME_GC" = xtrue; then @@ -169,7 +164,8 @@ AC_DEFUN([FLAGS_SETUP_LDFLAGS_HELPER], ################################################################################ # $1 - Either BUILD or TARGET to pick the correct OS/CPU variables to check # conditionals against. -# $2 - Optional prefix for each variable defined. +# $2 - Optional prefix for each variable defined (OPENJDK_BUILD_ or nothing). +# $3 - Optional prefix for toolchain variables (BUILD_ or nothing). AC_DEFUN([FLAGS_SETUP_LDFLAGS_CPU_DEP], [ # Setup CPU-dependent basic LDFLAGS. These can differ between the target and @@ -203,6 +199,12 @@ AC_DEFUN([FLAGS_SETUP_LDFLAGS_CPU_DEP], fi fi + if test "x${$3LD_TYPE}" = "xgold"; then + if test x$DEBUG_LEVEL = xrelease; then + $1_CPU_LDFLAGS="${$1_CPU_LDFLAGS} -Wl,--icf=all" + fi + fi + # Export variables according to old definitions, prefix with $2 if present. LDFLAGS_JDK_COMMON="$BASIC_LDFLAGS $BASIC_LDFLAGS_JDK_ONLY \ $OS_LDFLAGS $DEBUGLEVEL_LDFLAGS_JDK_ONLY ${$2EXTRA_LDFLAGS}" diff --git a/make/autoconf/toolchain.m4 b/make/autoconf/toolchain.m4 index 15210efe4a7..c882deb10a7 100644 --- a/make/autoconf/toolchain.m4 +++ b/make/autoconf/toolchain.m4 @@ -516,7 +516,7 @@ AC_DEFUN([TOOLCHAIN_EXTRACT_LD_VERSION], if [ [[ "$LINKER_VERSION_STRING" == *gold* ]] ]; then [ LINKER_VERSION_NUMBER=`$ECHO $LINKER_VERSION_STRING | \ $SED -e 's/.* \([0-9][0-9]*\(\.[0-9][0-9]*\)*\).*) .*/\1/'` ] - LINKER_TYPE=gold + $1_TYPE=gold else [ LINKER_VERSION_NUMBER=`$ECHO $LINKER_VERSION_STRING | \ $SED -e 's/.* \([0-9][0-9]*\(\.[0-9][0-9]*\)*\).*/\1/'` ] From 87c4b01ea3d94c25d260f0687addf7ecd154279a Mon Sep 17 00:00:00 2001 From: Erik Joelsson Date: Wed, 3 Dec 2025 14:38:53 +0000 Subject: [PATCH 135/706] 8372943: Restore --with-tools-dir Reviewed-by: mikael, tbell, shade --- make/autoconf/basic.m4 | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/make/autoconf/basic.m4 b/make/autoconf/basic.m4 index 316bfc5037d..bb6908d9194 100644 --- a/make/autoconf/basic.m4 +++ b/make/autoconf/basic.m4 @@ -353,7 +353,12 @@ AC_DEFUN_ONCE([BASIC_SETUP_DEVKIT], [set up toolchain on Mac OS using a path to an Xcode installation])]) UTIL_DEPRECATED_ARG_WITH(sys-root) - UTIL_DEPRECATED_ARG_WITH(tools-dir) + + AC_ARG_WITH([tools-dir], [AS_HELP_STRING([--with-tools-dir], + [Point to a nonstandard Visual Studio installation location on Windows by + specifying any existing directory 2 or 3 levels below the installation + root.])] + ) if test "x$with_xcode_path" != x; then if test "x$OPENJDK_BUILD_OS" = "xmacosx"; then From 829b85813a3810eeecf6ce4b30b5c3d1fc34ad23 Mon Sep 17 00:00:00 2001 From: Volodymyr Paprotski Date: Wed, 3 Dec 2025 14:53:35 +0000 Subject: [PATCH 136/706] 8372703: Test compiler/arguments/TestCodeEntryAlignment.java failed: assert(allocates2(pc)) failed: not in CodeBuffer memory Reviewed-by: mhaessig, dfenacci, thartmann --- src/hotspot/cpu/x86/stubDeclarations_x86.hpp | 2 +- test/hotspot/jtreg/ProblemList.txt | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/hotspot/cpu/x86/stubDeclarations_x86.hpp b/src/hotspot/cpu/x86/stubDeclarations_x86.hpp index 3e0e1d5bf07..971c8fd3c44 100644 --- a/src/hotspot/cpu/x86/stubDeclarations_x86.hpp +++ b/src/hotspot/cpu/x86/stubDeclarations_x86.hpp @@ -73,7 +73,7 @@ do_arch_blob, \ do_arch_entry, \ do_arch_entry_init) \ - do_arch_blob(compiler, 109000 WINDOWS_ONLY(+2000)) \ + do_arch_blob(compiler, 120000 WINDOWS_ONLY(+2000)) \ do_stub(compiler, vector_float_sign_mask) \ do_arch_entry(x86, compiler, vector_float_sign_mask, \ vector_float_sign_mask, vector_float_sign_mask) \ diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index f379f57a8e5..177c14da785 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -78,8 +78,6 @@ compiler/c2/aarch64/TestStaticCallStub.java 8359963 linux-aarch64,macosx-aarch64 serviceability/jvmti/NMethodRelocation/NMethodRelocationTest.java 8369150 generic-all -compiler/arguments/TestCodeEntryAlignment.java 8372703 generic-x64 - ############################################################################# # :hotspot_gc From 1d753f116135cffa3ec9e8b4af3922aa647317dc Mon Sep 17 00:00:00 2001 From: Nizar Benalla Date: Wed, 3 Dec 2025 15:14:57 +0000 Subject: [PATCH 137/706] 8373010: Update starting-next-release.html after JDK-8372940 Reviewed-by: jpai, erikj --- doc/starting-next-release.html | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/starting-next-release.html b/doc/starting-next-release.html index 6cffdf38b0f..bbb48e243ad 100644 --- a/doc/starting-next-release.html +++ b/doc/starting-next-release.html @@ -119,6 +119,9 @@ cover the new source version

  • and test/langtools/tools/javac/preview/classReaderTest/Client.preview.out: update expected messages for preview errors and warnings +
  • test/langtools/tools/javac/versions/Versions.java: add +new source version to the set of valid sources and add new enum constant +for the new class file version.
  • From 3d54a802e38f425c7035c947758c887fec48e43a Mon Sep 17 00:00:00 2001 From: Axel Boldt-Christmas Date: Wed, 3 Dec 2025 15:21:11 +0000 Subject: [PATCH 138/706] 8372995: SerialGC: Allow SerialHeap::allocate_loaded_archive_space expand old_gen Reviewed-by: ayang, jsikstro --- src/hotspot/share/gc/serial/serialHeap.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/gc/serial/serialHeap.cpp b/src/hotspot/share/gc/serial/serialHeap.cpp index faef3b89125..932c06b8109 100644 --- a/src/hotspot/share/gc/serial/serialHeap.cpp +++ b/src/hotspot/share/gc/serial/serialHeap.cpp @@ -147,7 +147,8 @@ GrowableArray SerialHeap::memory_pools() { HeapWord* SerialHeap::allocate_loaded_archive_space(size_t word_size) { MutexLocker ml(Heap_lock); - return old_gen()->allocate(word_size); + HeapWord* const addr = old_gen()->allocate(word_size); + return addr != nullptr ? addr : old_gen()->expand_and_allocate(word_size); } void SerialHeap::complete_loaded_archive_space(MemRegion archive_space) { From 6d5bf9c801bbec3cd3580f889cc92415021f7322 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Wed, 3 Dec 2025 15:30:14 +0000 Subject: [PATCH 139/706] 8372999: Parallel: Old generation min size constraint broken Reviewed-by: stefank, jsikstro --- .../share/gc/parallel/parallelScavengeHeap.cpp | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp index 4d291120e4a..9df3deedf89 100644 --- a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp +++ b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp @@ -891,9 +891,23 @@ void ParallelScavengeHeap::resize_after_young_gc(bool is_survivor_overflowing) { // Consider if should shrink old-gen if (!is_survivor_overflowing) { - // Upper bound for a single step shrink - size_t max_shrink_bytes = SpaceAlignment; + assert(old_gen()->capacity_in_bytes() >= old_gen()->min_gen_size(), "inv"); + + // Old gen min_gen_size constraint. + const size_t max_shrink_bytes_gen_size_constraint = old_gen()->capacity_in_bytes() - old_gen()->min_gen_size(); + + // Per-step delta to avoid too aggressive shrinking. + const size_t max_shrink_bytes_per_step_constraint = SpaceAlignment; + + // Combining the above two constraints. + const size_t max_shrink_bytes = MIN2(max_shrink_bytes_gen_size_constraint, + max_shrink_bytes_per_step_constraint); + size_t shrink_bytes = _size_policy->compute_old_gen_shrink_bytes(old_gen()->free_in_bytes(), max_shrink_bytes); + + assert(old_gen()->capacity_in_bytes() >= shrink_bytes, "inv"); + assert(old_gen()->capacity_in_bytes() - shrink_bytes >= old_gen()->min_gen_size(), "inv"); + if (shrink_bytes != 0) { if (MinHeapFreeRatio != 0) { size_t new_capacity = old_gen()->capacity_in_bytes() - shrink_bytes; From af8977e40661db2edec069d524f7c9352c7de850 Mon Sep 17 00:00:00 2001 From: Daniel Fuchs Date: Wed, 3 Dec 2025 15:32:46 +0000 Subject: [PATCH 140/706] 8372951: The property jdk.httpclient.quic.maxBidiStreams should be renamed to jdk.internal 8365794: StreamLimitTest vs H3StreamLimitReachedTest: consider renaming or merging Reviewed-by: jpai --- .../net/http/quic/QuicConnectionImpl.java | 14 ++++++- .../H3MultipleConnectionsToSameHost.java | 10 ++--- .../http3/H3StreamLimitReachedTest.java | 42 +++++++++++++++++-- .../net/httpclient/http3/StreamLimitTest.java | 5 ++- 4 files changed, 61 insertions(+), 10 deletions(-) diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicConnectionImpl.java b/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicConnectionImpl.java index 240f90852bc..c07df1c6eb2 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicConnectionImpl.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicConnectionImpl.java @@ -174,17 +174,29 @@ public class QuicConnectionImpl extends QuicConnection implements QuicPacketRece public static final int SMALLEST_MAXIMUM_DATAGRAM_SIZE = QuicClient.SMALLEST_MAXIMUM_DATAGRAM_SIZE; + // The default value for the Quic maxInitialTimeout, in seconds. Will be clamped to [1, Integer.MAX_vALUE] public static final int DEFAULT_MAX_INITIAL_TIMEOUT = Math.clamp( Utils.getIntegerProperty("jdk.httpclient.quic.maxInitialTimeout", 30), 1, Integer.MAX_VALUE); + // The default value for the initial_max_data transport parameter that a QuicConnectionImpl + // will send to its peer, if no value is provided by the higher level protocol. public static final long DEFAULT_INITIAL_MAX_DATA = Math.clamp( Utils.getLongProperty("jdk.httpclient.quic.maxInitialData", 15 << 20), 0, 1L << 60); + // The default value for the initial_max_stream_data_bidi_local, initial_max_stream_data_bidi_remote, + // and initial_max_stream_data_uni transport parameters that a QuicConnectionImpl + // will send to its peer, if no value is provided by the higher level protocol. public static final long DEFAULT_INITIAL_STREAM_MAX_DATA = Math.clamp( Utils.getIntegerProperty("jdk.httpclient.quic.maxStreamInitialData", 6 << 20), 0, 1L << 60); + // The default value for the initial_max_streams_bidi transport parameter that a QuicConnectionImpl + // will send to its peer, if no value is provided by the higher level protocol. + // The Http3ClientImpl typically provides a value of 0, so this property has no effect + // on QuicConnectionImpl instances created on behalf of the HTTP/3 client public static final int DEFAULT_MAX_BIDI_STREAMS = - Utils.getIntegerProperty("jdk.httpclient.quic.maxBidiStreams", 100); + Utils.getIntegerProperty("jdk.internal.httpclient.quic.maxBidiStreams", 100); + // The default value for the initial_max_streams_uni transport parameter that a QuicConnectionImpl + // will send to its peer, if no value is provided by the higher level protocol. public static final int DEFAULT_MAX_UNI_STREAMS = Utils.getIntegerProperty("jdk.httpclient.quic.maxUniStreams", 100); public static final boolean USE_DIRECT_BUFFER_POOL = Utils.getBooleanProperty( diff --git a/test/jdk/java/net/httpclient/http3/H3MultipleConnectionsToSameHost.java b/test/jdk/java/net/httpclient/http3/H3MultipleConnectionsToSameHost.java index 862ccf22ddc..2e4047cf5ea 100644 --- a/test/jdk/java/net/httpclient/http3/H3MultipleConnectionsToSameHost.java +++ b/test/jdk/java/net/httpclient/http3/H3MultipleConnectionsToSameHost.java @@ -37,7 +37,7 @@ * -Djdk.internal.httpclient.quic.poller.usePlatformThreads=false * -Djdk.httpclient.quic.maxEndpoints=-1 * -Djdk.httpclient.http3.maxStreamLimitTimeout=0 - * -Djdk.httpclient.quic.maxBidiStreams=2 + * -Djdk.internal.httpclient.quic.maxBidiStreams=2 * -Djdk.httpclient.retryOnStreamlimit=50 * -Djdk.httpclient.HttpClient.log=errors,http3,quic:retransmit * -Dsimpleget.requests=100 @@ -61,7 +61,7 @@ * -XX:+UnlockExperimentalVMOptions -XX:-VMContinuations * -Djdk.httpclient.quic.maxEndpoints=-1 * -Djdk.httpclient.http3.maxStreamLimitTimeout=0 - * -Djdk.httpclient.quic.maxBidiStreams=2 + * -Djdk.internal.httpclient.quic.maxBidiStreams=2 * -Djdk.httpclient.retryOnStreamlimit=50 * -Djdk.httpclient.HttpClient.log=errors,http3,quic:retransmit * -Dsimpleget.requests=100 @@ -85,7 +85,7 @@ * -Djdk.internal.httpclient.quic.useNioSelector=true * -Djdk.httpclient.http3.maxStreamLimitTimeout=0 * -Djdk.httpclient.quic.maxEndpoints=1 - * -Djdk.httpclient.quic.maxBidiStreams=2 + * -Djdk.internal.httpclient.quic.maxBidiStreams=2 * -Djdk.httpclient.retryOnStreamlimit=50 * -Djdk.httpclient.HttpClient.log=errors,http3,quic:hs:retransmit * -Dsimpleget.requests=100 @@ -109,7 +109,7 @@ * -Djdk.httpclient.quic.maxPtoBackoff=9 * -Djdk.httpclient.http3.maxStreamLimitTimeout=0 * -Djdk.httpclient.quic.maxEndpoints=1 - * -Djdk.httpclient.quic.maxBidiStreams=2 + * -Djdk.internal.httpclient.quic.maxBidiStreams=2 * -Djdk.httpclient.retryOnStreamlimit=50 * -Djdk.httpclient.HttpClient.log=errors,http3,quic:hs:retransmit * -Dsimpleget.requests=100 @@ -239,7 +239,7 @@ public class H3MultipleConnectionsToSameHost implements HttpServerAdapters { long done = System.nanoTime(); System.out.println("Initialization and warmup took "+ TimeUnit.NANOSECONDS.toMillis(done-prestart)+" millis"); // Thread.sleep(30000); - int maxBidiStreams = Utils.getIntegerNetProperty("jdk.httpclient.quic.maxBidiStreams", 100); + int maxBidiStreams = Utils.getIntegerNetProperty("jdk.internal.httpclient.quic.maxBidiStreams", 100); long timeout = MAX_STREAM_LIMIT_WAIT_TIMEOUT; Set connections = new ConcurrentSkipListSet<>(); diff --git a/test/jdk/java/net/httpclient/http3/H3StreamLimitReachedTest.java b/test/jdk/java/net/httpclient/http3/H3StreamLimitReachedTest.java index 916a6a5221d..0de80c6d587 100644 --- a/test/jdk/java/net/httpclient/http3/H3StreamLimitReachedTest.java +++ b/test/jdk/java/net/httpclient/http3/H3StreamLimitReachedTest.java @@ -23,6 +23,24 @@ /* * @test id=with-default-wait + * @summary this test verifies that the correct connection is + * used when a request is retried on a new connection + * due to stream limit reached. + * The maxBidiStreams limit is artificially set to 1. + * This configuration uses the default wait for a stream + * to become available before retrying. + * Different configurations are tested if possible, + * with both HTTP/3 only and HTTP/2 HTTP/3 with altsvc. + * In one case the HTTP/3 only server will be listening + * on the same port as the HTTP/2 server, with the + * HTTP/2 server advertising an AltService on a different + * port. In another case the AltService will be on the + * same port as the HTTP/2 server and the HTTP/3 server + * will be on a different port. In all case, the test + * verifies that the right connection is picked up + * for the retry. + * @bug 8372951 + * @comment this test also tests bug 8372951 * @library /test/lib /test/jdk/java/net/httpclient/lib * @build jdk.httpclient.test.lib.http2.Http2TestServer * jdk.test.lib.Asserts @@ -30,12 +48,30 @@ * jdk.test.lib.net.SimpleSSLContext * @run testng/othervm -Djdk.httpclient.HttpClient.log=ssl,requests,responses,errors,http3,quic:control * -Djdk.internal.httpclient.debug=false - * -Djdk.httpclient.quic.maxBidiStreams=1 + * -Djdk.internal.httpclient.quic.maxBidiStreams=1 * H3StreamLimitReachedTest */ /* * @test id=with-no-wait + * @summary this test verifies that the correct connection is + * used when a request is retried on a new connection + * due to stream limit reached. + * The maxBidiStreams limit is artificially set to 1. + * This configuration retries immediately on a new + * connection when no stream is available. + * Different configurations are tested if possible, + * with both HTTP/3 only and HTTP/2 HTTP/3 with altsvc. + * In one case the HTTP/3 only server will be listening + * on the same port as the HTTP/2 server, with the + * HTTP/2 server advertising an AltService on a different + * port. In another case the AltService will be on the + * same port as the HTTP/2 server and the HTTP/3 server + * will be on a different port. In all case, the test + * verifies that the right connection is picked up + * for the retry. + * @bug 8372951 + * @comment this test also tests bug 8372951 * @library /test/lib /test/jdk/java/net/httpclient/lib * @build jdk.httpclient.test.lib.http2.Http2TestServer * jdk.test.lib.Asserts @@ -43,7 +79,7 @@ * jdk.test.lib.net.SimpleSSLContext * @run testng/othervm -Djdk.httpclient.HttpClient.log=ssl,requests,responses,errors,http3,quic:control * -Djdk.internal.httpclient.debug=false - * -Djdk.httpclient.quic.maxBidiStreams=1 + * -Djdk.internal.httpclient.quic.maxBidiStreams=1 * -Djdk.httpclient.http3.maxStreamLimitTimeout=0 * -Djdk.httpclient.retryOnStreamlimit=9 * H3StreamLimitReachedTest @@ -93,7 +129,7 @@ import static org.testng.Assert.assertFalse; public class H3StreamLimitReachedTest implements HttpServerAdapters { - private static final String CLASS_NAME = H3ConnectionPoolTest.class.getSimpleName(); + private static final String CLASS_NAME = H3StreamLimitReachedTest.class.getSimpleName(); static int altsvcPort, https2Port, http3Port; static Http3TestServer http3OnlyServer; diff --git a/test/jdk/java/net/httpclient/http3/StreamLimitTest.java b/test/jdk/java/net/httpclient/http3/StreamLimitTest.java index d8a920c8544..105417950a1 100644 --- a/test/jdk/java/net/httpclient/http3/StreamLimitTest.java +++ b/test/jdk/java/net/httpclient/http3/StreamLimitTest.java @@ -56,7 +56,10 @@ import static java.net.http.HttpOption.H3_DISCOVERY; /* * @test * @summary verifies that when the Quic stream limit is reached - * then HTTP3 requests are retried on newer connection + * then HTTP3 requests are retried on newer connection. + * This test uses an HTTP/3 only test server, which is + * configured to allow the test to control when a new + * MAX_STREAMS frames is sent to the client. * @library /test/lib /test/jdk/java/net/httpclient/lib * @build jdk.test.lib.net.SimpleSSLContext * jdk.httpclient.test.lib.common.HttpServerAdapters From c4321503976840f6630567c4fa430cd1ffca41fb Mon Sep 17 00:00:00 2001 From: Chris Plummer Date: Wed, 3 Dec 2025 16:37:10 +0000 Subject: [PATCH 141/706] 8372809: Test vmTestbase/nsk/jdi/ThreadReference/isSuspended/issuspended001/TestDescription.java failed: JVMTI_ERROR_THREAD_NOT_ALIVE Reviewed-by: amenkov, sspitsyn --- .../share/native/libjdwp/threadControl.c | 24 +++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c b/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c index 491182a583f..39407133889 100644 --- a/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c +++ b/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c @@ -157,11 +157,20 @@ setThreadLocalStorage(jthread thread, ThreadNode *node) error = JVMTI_FUNC_PTR(gdata->jvmti,SetThreadLocalStorage) (gdata->jvmti, thread, (void*)node); - if ( error == JVMTI_ERROR_THREAD_NOT_ALIVE && node == NULL) { - /* Just return. This can happen when clearing the TLS. */ - return; - } else if ( error != JVMTI_ERROR_NONE ) { - /* The jthread object must be valid, so this must be a fatal error */ + if (error == JVMTI_ERROR_THREAD_NOT_ALIVE) { + if (node == NULL) { + // Just return. This can happen when clearing the TLS. + return; + } + if (isVThread(thread)) { + // Just return. This can happen with a vthread that is running and we + // had to create a ThreadNode for it. By the time we get here, it may + // have already terminated. + return; + } + } + if (error != JVMTI_ERROR_NONE) { + // The jthread object must be valid, so this must be a fatal error. EXIT_ERROR(error, "cannot set thread local storage"); } } @@ -251,9 +260,10 @@ findThread(ThreadList *list, jthread thread) * Otherwise the thread should not be on the runningThreads. */ if ( !gdata->jvmtiCallBacksCleared ) { - /* The thread better not be on either list if the TLS lookup failed. */ + // The thread better not be on the runningThreads list if the TLS lookup failed. + // It might be on the runningVThreads list because of how ThreadNodes for vthreads + // can be recreated just before terminating, so we don't check runningVThreads. JDI_ASSERT(!nonTlsSearch(getEnv(), &runningThreads, thread)); - JDI_ASSERT(!nonTlsSearch(getEnv(), &runningVThreads, thread)); } else { /* * Search the runningThreads and runningVThreads lists. The TLS lookup may have From 0bcef61a6de027c1b7e481e2115016ee961707a5 Mon Sep 17 00:00:00 2001 From: Chris Plummer Date: Wed, 3 Dec 2025 17:15:37 +0000 Subject: [PATCH 142/706] 8372957: After JDK-8282441 JDWP might allow some invalid FrameIDs to be used Reviewed-by: amenkov, sspitsyn --- src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c b/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c index 39407133889..734dd5eb7dc 100644 --- a/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c +++ b/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c @@ -70,6 +70,7 @@ typedef struct ThreadNode { unsigned int popFrameEvent : 1; unsigned int popFrameProceed : 1; unsigned int popFrameThread : 1; + unsigned int frameGeneration_accessed:1; /* true if frameGeneration accessed to produce a FrameID */ EventIndex current_ei; /* Used to determine if we are currently handling an event on this thread. */ jobject pendingStop; /* Object we are throwing to stop the thread (ThreadReferenceImpl.stop). */ jint suspendCount; /* Number of outstanding suspends from the debugger. */ @@ -616,6 +617,7 @@ freeUnusedVThreadNode(JNIEnv *env, ThreadNode* node) !node->popFrameEvent && !node->popFrameProceed && !node->popFrameThread && + !node->frameGeneration_accessed && node->pendingStop == NULL) { removeNode(node); @@ -2683,6 +2685,7 @@ threadControl_getFrameGeneration(jthread thread) if (node != NULL) { frameGeneration = node->frameGeneration; + node->frameGeneration_accessed = JNI_TRUE; } } debugMonitorExit(threadLock); From fa6ca0bbd14436cd3778a7a3383183cd73688123 Mon Sep 17 00:00:00 2001 From: Justin Lu Date: Wed, 3 Dec 2025 17:25:05 +0000 Subject: [PATCH 143/706] 8362428: Update IANA Language Subtag Registry to Version 2025-08-25 Reviewed-by: lancea, naoto, iris --- .../data/lsrdata/language-subtag-registry.txt | 61 +++++++++++++++++-- .../Locale/LanguageSubtagRegistryTest.java | 4 +- 2 files changed, 59 insertions(+), 6 deletions(-) diff --git a/src/java.base/share/data/lsrdata/language-subtag-registry.txt b/src/java.base/share/data/lsrdata/language-subtag-registry.txt index 64c40f28162..82618f9b40e 100644 --- a/src/java.base/share/data/lsrdata/language-subtag-registry.txt +++ b/src/java.base/share/data/lsrdata/language-subtag-registry.txt @@ -1,4 +1,4 @@ -File-Date: 2025-05-15 +File-Date: 2025-08-25 %% Type: language Subtag: aa @@ -3102,6 +3102,7 @@ Added: 2009-07-29 Type: language Subtag: asb Description: Assiniboine +Description: Nakoda Assiniboine Added: 2009-07-29 %% Type: language @@ -3269,6 +3270,7 @@ Added: 2009-07-29 Type: language Subtag: atj Description: Atikamekw +Description: Nehirowimowin Added: 2009-07-29 %% Type: language @@ -7981,6 +7983,7 @@ Added: 2009-07-29 Type: language Subtag: clc Description: Chilcotin +Description: Tsilhqot’in Added: 2009-07-29 %% Type: language @@ -8021,6 +8024,7 @@ Added: 2009-07-29 %% Type: language Subtag: clm +Description: Klallam Description: Clallam Added: 2009-07-29 %% @@ -13509,7 +13513,7 @@ Added: 2009-07-29 %% Type: language Subtag: haa -Description: Han +Description: Hän Added: 2009-07-29 %% Type: language @@ -19022,6 +19026,7 @@ Added: 2009-07-29 %% Type: language Subtag: kwk +Description: Kwak'wala Description: Kwakiutl Added: 2009-07-29 %% @@ -22262,7 +22267,7 @@ Added: 2009-07-29 %% Type: language Subtag: mhn -Description: Mócheno +Description: Mòcheno Added: 2009-07-29 %% Type: language @@ -31655,6 +31660,7 @@ Added: 2009-07-29 Type: language Subtag: sec Description: Sechelt +Description: She shashishalhem Added: 2009-07-29 %% Type: language @@ -32003,6 +32009,7 @@ Added: 2009-07-29 Type: language Subtag: shs Description: Shuswap +Description: Secwepemctsín Added: 2009-07-29 %% Type: language @@ -33014,6 +33021,7 @@ Added: 2009-07-29 Type: language Subtag: squ Description: Squamish +Description: Sḵwx̱wú7mesh sníchim Added: 2009-07-29 %% Type: language @@ -34664,6 +34672,8 @@ Added: 2009-07-29 Type: language Subtag: thp Description: Thompson +Description: Nłeʔkepmxcín +Description: Thompson River Salish Added: 2009-07-29 %% Type: language @@ -34684,6 +34694,7 @@ Added: 2009-07-29 Type: language Subtag: tht Description: Tahltan +Description: Tāłtān Added: 2009-07-29 %% Type: language @@ -42419,7 +42430,7 @@ Added: 2009-07-29 %% Type: language Subtag: zmp -Description: Mpuono +Description: Mbuun Added: 2009-07-29 %% Type: language @@ -47639,6 +47650,12 @@ Comments: Denotes conventions established by the Academia Brasileira de Letras in 1943 and generally used in Brazil until 2009 %% Type: variant +Subtag: akhmimic +Description: Akhmimic dialect of Coptic +Added: 2025-07-14 +Prefix: cop +%% +Type: variant Subtag: akuapem Description: Akuapem Twi Added: 2017-06-05 @@ -47814,6 +47831,12 @@ Comments: Black American Sign Language (BASL) or Black Sign Variation (BSV) is a dialect of American Sign Language (ASL) %% Type: variant +Subtag: bohairic +Description: Bohairic dialect of Coptic +Added: 2025-07-14 +Prefix: cop +%% +Type: variant Subtag: bohoric Description: Slovene in Bohorič alphabet Added: 2012-06-27 @@ -47898,6 +47921,12 @@ Comments: Represents the standard written form of Ladin in Fascia which unified the three subvarieties Cazet, Brach and Moenat %% Type: variant +Subtag: fayyumic +Description: Fayyumic dialect of Coptic +Added: 2025-07-14 +Prefix: cop +%% +Type: variant Subtag: fodom Description: Fodom standard of Ladin Added: 2024-03-04 @@ -48167,6 +48196,12 @@ Comments: Russian orthography as established by the 1917/1918 orthographic reforms %% Type: variant +Subtag: lycopol +Description: Lycopolitan alias Subakhmimic dialect of Coptic +Added: 2025-07-14 +Prefix: cop +%% +Type: variant Subtag: mdcegyp Description: Ancient Egyptian hieroglyphs encoded in Manuel de Codage Added: 2025-02-06 @@ -48180,6 +48215,12 @@ Added: 2025-02-06 Prefix: egy %% Type: variant +Subtag: mesokem +Description: Mesokemic alias Oxyrhynchite dialect of Coptic +Added: 2025-07-14 +Prefix: cop +%% +Type: variant Subtag: metelko Description: Slovene in Metelko alphabet Added: 2012-06-27 @@ -48367,6 +48408,12 @@ Prefix: rm Comments: Supraregional Romansh written standard %% Type: variant +Subtag: sahidic +Description: Sahidic dialect of Coptic +Added: 2025-07-14 +Prefix: cop +%% +Type: variant Subtag: saigon Description: The Sài Gòn variant of Vietnamese Added: 2025-03-10 @@ -48555,6 +48602,12 @@ Comments: The subtag represents the old orthography of the Latvian language used during c. 1600s–1920s. %% Type: variant +Subtag: viennese +Description: The Viennese dialect of German +Added: 2025-06-22 +Prefix: de +%% +Type: variant Subtag: vivaraup Description: Vivaro-Alpine Added: 2018-04-22 diff --git a/test/jdk/java/util/Locale/LanguageSubtagRegistryTest.java b/test/jdk/java/util/Locale/LanguageSubtagRegistryTest.java index 12f5a96d3fb..07cc7a412b6 100644 --- a/test/jdk/java/util/Locale/LanguageSubtagRegistryTest.java +++ b/test/jdk/java/util/Locale/LanguageSubtagRegistryTest.java @@ -25,9 +25,9 @@ * @test * @bug 8025703 8040211 8191404 8203872 8222980 8225435 8241082 8242010 8247432 * 8258795 8267038 8287180 8302512 8304761 8306031 8308021 8313702 8318322 - * 8327631 8332424 8334418 8344589 8348328 + * 8327631 8332424 8334418 8344589 8348328 8362428 * @summary Checks the IANA language subtag registry data update - * (LSR Revision: 2025-05-15) with Locale and Locale.LanguageRange + * (LSR Revision: 2025-08-25) with Locale and Locale.LanguageRange * class methods. * @run main LanguageSubtagRegistryTest */ From 8d80778e05aee878f9a3e8beabe6a0cfd0a02c16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20Sikstr=C3=B6m?= Date: Wed, 3 Dec 2025 18:02:06 +0000 Subject: [PATCH 144/706] 8373023: [REDO] Remove the default value of InitialRAMPercentage Reviewed-by: stefank, sjohanss, aboldtch --- src/hotspot/share/gc/shared/gc_globals.hpp | 2 +- src/hotspot/share/runtime/flags/jvmFlag.cpp | 2 +- src/java.base/share/man/java.md | 3 +-- test/hotspot/jtreg/ProblemList.txt | 10 ++++++++++ test/jdk/ProblemList.txt | 1 + 5 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/hotspot/share/gc/shared/gc_globals.hpp b/src/hotspot/share/gc/shared/gc_globals.hpp index e86a8744847..d08e95378f7 100644 --- a/src/hotspot/share/gc/shared/gc_globals.hpp +++ b/src/hotspot/share/gc/shared/gc_globals.hpp @@ -291,7 +291,7 @@ "size on systems with small physical memory size") \ range(0.0, 100.0) \ \ - product(double, InitialRAMPercentage, 0.2, \ + product(double, InitialRAMPercentage, 0.0, \ "Percentage of real memory used for initial heap size") \ range(0.0, 100.0) \ \ diff --git a/src/hotspot/share/runtime/flags/jvmFlag.cpp b/src/hotspot/share/runtime/flags/jvmFlag.cpp index 487528c49bd..51517fa49db 100644 --- a/src/hotspot/share/runtime/flags/jvmFlag.cpp +++ b/src/hotspot/share/runtime/flags/jvmFlag.cpp @@ -162,7 +162,7 @@ void JVMFlag::print_on(outputStream* st, bool withComments, bool printRanges) co // uintx ThresholdTolerance = 10 {product} {default} // size_t TLABSize = 0 {product} {default} // uintx SurvivorRatio = 8 {product} {default} - // double InitialRAMPercentage = 1.562500 {product} {default} + // double InitialRAMPercentage = 0.000000 {product} {default} // ccstr CompileCommandFile = MyFile.cmd {product} {command line} // ccstrlist CompileOnly = Method1 // CompileOnly += Method2 {product} {command line} diff --git a/src/java.base/share/man/java.md b/src/java.base/share/man/java.md index 462baa5a4a0..8517e161e3f 100644 --- a/src/java.base/share/man/java.md +++ b/src/java.base/share/man/java.md @@ -2455,8 +2455,7 @@ Java HotSpot VM. `-XX:InitialRAMPercentage=`*percent* : Sets the initial amount of memory that the JVM will use for the Java heap before applying ergonomics heuristics as a percentage of the maximum amount - determined as described in the `-XX:MaxRAM` option. The default value is - 0.2 percent. + determined as described in the `-XX:MaxRAM` option. The following example shows how to set the percentage of the initial amount of memory used for the Java heap: diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index 177c14da785..6c3d907961d 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -94,6 +94,7 @@ gc/shenandoah/TestEvilSyncBug.java#generational 8345501 generic-all gc/shenandoah/TestRetainObjects.java#no-tlab 8361099 generic-all gc/shenandoah/TestSieveObjects.java#no-tlab 8361099 generic-all gc/shenandoah/TestSieveObjects.java#no-tlab-genshen 8361099 generic-all +gc/cslocker/TestCSLocker.java 8373025 generic-all ############################################################################# @@ -139,6 +140,9 @@ serviceability/sa/ClhsdbPstack.java#core 8318754 macosx-aarch64 serviceability/sa/TestJmapCore.java 8318754 macosx-aarch64 serviceability/sa/TestJmapCoreMetaspace.java 8318754 macosx-aarch64 +serviceability/sa/ClhsdbScanOops.java#parallel 8373022 generic-all +serviceability/sa/ClhsdbScanOops.java#serial 8373022 generic-all + serviceability/sa/ClhsdbThreadContext.java 8356704 windows-x64 serviceability/jvmti/stress/StackTrace/NotSuspended/GetStackTraceNotSuspendedStressTest.java 8315980 linux-all,windows-x64 @@ -183,3 +187,9 @@ vmTestbase/nsk/jdwp/ThreadReference/ForceEarlyReturn/forceEarlyReturn001/forceEa vmTestbase/nsk/monitoring/ThreadMXBean/ThreadInfo/Multi/Multi005/TestDescription.java 8076494 windows-x64 vmTestbase/nsk/monitoring/ThreadMXBean/findMonitorDeadlockedThreads/find006/TestDescription.java 8310144 macosx-aarch64 + +vmTestbase/nsk/monitoring/MemoryPoolMBean/isUsageThresholdExceeded/isexceeded001/TestDescription.java 8373022 generic-all +vmTestbase/nsk/monitoring/MemoryPoolMBean/isUsageThresholdExceeded/isexceeded002/TestDescription.java 8373022 generic-all +vmTestbase/nsk/monitoring/MemoryPoolMBean/isUsageThresholdExceeded/isexceeded003/TestDescription.java 8373022 generic-all +vmTestbase/nsk/monitoring/MemoryPoolMBean/isUsageThresholdExceeded/isexceeded004/TestDescription.java 8373022 generic-all +vmTestbase/nsk/monitoring/MemoryPoolMBean/isUsageThresholdExceeded/isexceeded005/TestDescription.java 8373022 generic-all diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 1d547faf662..72a248408ac 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -715,6 +715,7 @@ javax/swing/plaf/synth/7158712/bug7158712.java 8324782 macosx-all # jdk_jdi com/sun/jdi/InvokeHangTest.java 8218463 linux-all +com/sun/jdi/MethodInvokeWithTraceOnTest.java 8373022 generic-all ############################################################################ From e93b10d08456f720e303771a882e79660911e1eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20Gr=C3=B6nlund?= Date: Wed, 3 Dec 2025 18:12:58 +0000 Subject: [PATCH 145/706] 8365400: Enhance JFR to emit file and module metadata for class loading Reviewed-by: coleenp, egahlin --- .../share/cds/lambdaProxyClassDictionary.cpp | 6 +- .../share/classfile/classFileParser.cpp | 5 - .../share/classfile/classFileParser.hpp | 2 + src/hotspot/share/classfile/klassFactory.cpp | 7 +- .../share/classfile/systemDictionary.cpp | 51 ++- .../share/classfile/systemDictionary.hpp | 6 +- src/hotspot/share/classfile/vmClasses.cpp | 7 + .../jfrEventClassTransformer.cpp | 2 +- src/hotspot/share/jfr/jfr.cpp | 18 +- src/hotspot/share/jfr/jfr.hpp | 2 + src/hotspot/share/jfr/metadata/metadata.xml | 1 + .../recorder/checkpoint/types/jfrTypeSet.cpp | 5 +- .../checkpoint/types/jfrTypeSetUtils.cpp | 49 +-- .../checkpoint/types/jfrTypeSetUtils.hpp | 18 +- .../types/jfrTypeSetUtils.inline.hpp | 42 ++ .../checkpoint/types/traceid/jfrTraceId.cpp | 1 + .../share/jfr/recorder/jfrRecorder.cpp | 9 + .../share/jfr/recorder/jfrRecorder.hpp | 1 + .../recorder/service/jfrRecorderService.cpp | 3 + .../share/jfr/support/jfrClassDefineEvent.cpp | 188 ++++++++ .../share/jfr/support/jfrClassDefineEvent.hpp | 40 ++ .../share/jfr/support/jfrKlassExtension.hpp | 1 - .../share/jfr/support/jfrSymbolTable.cpp | 406 +++++++++++------- .../share/jfr/support/jfrSymbolTable.hpp | 179 ++++---- .../jfr/support/jfrSymbolTable.inline.hpp | 72 ++++ .../share/jfr/support/jfrTraceIdExtension.hpp | 1 - .../jfr/utilities/jfrConcurrentHashtable.hpp | 139 ++++++ .../jfrConcurrentHashtable.inline.hpp | 254 +++++++++++ .../share/jfr/utilities/jfrLinkedList.hpp | 5 +- .../jfr/utilities/jfrLinkedList.inline.hpp | 36 +- src/hotspot/share/oops/klass.cpp | 8 +- .../classes/jdk/jfr/internal/query/view.ini | 9 + .../event/runtime/TestClassDefineEvent.java | 2 + 33 files changed, 1224 insertions(+), 351 deletions(-) create mode 100644 src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.inline.hpp create mode 100644 src/hotspot/share/jfr/support/jfrClassDefineEvent.cpp create mode 100644 src/hotspot/share/jfr/support/jfrClassDefineEvent.hpp create mode 100644 src/hotspot/share/jfr/support/jfrSymbolTable.inline.hpp create mode 100644 src/hotspot/share/jfr/utilities/jfrConcurrentHashtable.hpp create mode 100644 src/hotspot/share/jfr/utilities/jfrConcurrentHashtable.inline.hpp diff --git a/src/hotspot/share/cds/lambdaProxyClassDictionary.cpp b/src/hotspot/share/cds/lambdaProxyClassDictionary.cpp index f6da1a34af3..d091067c116 100644 --- a/src/hotspot/share/cds/lambdaProxyClassDictionary.cpp +++ b/src/hotspot/share/cds/lambdaProxyClassDictionary.cpp @@ -357,7 +357,7 @@ InstanceKlass* LambdaProxyClassDictionary::load_and_init_lambda_proxy_class(Inst InstanceKlass* nest_host = caller_ik->nest_host(THREAD); assert(nest_host == shared_nest_host, "mismatched nest host"); - EventClassLoad class_load_start_event; + EventClassLoad class_load_event; // Add to class hierarchy, and do possible deoptimizations. lambda_ik->add_to_hierarchy(THREAD); @@ -368,8 +368,8 @@ InstanceKlass* LambdaProxyClassDictionary::load_and_init_lambda_proxy_class(Inst if (JvmtiExport::should_post_class_load()) { JvmtiExport::post_class_load(THREAD, lambda_ik); } - if (class_load_start_event.should_commit()) { - SystemDictionary::post_class_load_event(&class_load_start_event, lambda_ik, ClassLoaderData::class_loader_data(class_loader())); + if (class_load_event.should_commit()) { + JFR_ONLY(SystemDictionary::post_class_load_event(&class_load_event, lambda_ik, ClassLoaderData::class_loader_data(class_loader()));) } lambda_ik->initialize(CHECK_NULL); diff --git a/src/hotspot/share/classfile/classFileParser.cpp b/src/hotspot/share/classfile/classFileParser.cpp index 68890775051..312accb1df9 100644 --- a/src/hotspot/share/classfile/classFileParser.cpp +++ b/src/hotspot/share/classfile/classFileParser.cpp @@ -89,9 +89,6 @@ #if INCLUDE_CDS #include "classfile/systemDictionaryShared.hpp" #endif -#if INCLUDE_JFR -#include "jfr/support/jfrTraceIdExtension.hpp" -#endif // We generally try to create the oops directly when parsing, rather than // allocating temporary data structures and copying the bytes twice. A @@ -5272,8 +5269,6 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik, } } - JFR_ONLY(INIT_ID(ik);) - // If we reach here, all is well. // Now remove the InstanceKlass* from the _klass_to_deallocate field // in order for it to not be destroyed in the ClassFileParser destructor. diff --git a/src/hotspot/share/classfile/classFileParser.hpp b/src/hotspot/share/classfile/classFileParser.hpp index 5d4236132f1..48cdacedc1e 100644 --- a/src/hotspot/share/classfile/classFileParser.hpp +++ b/src/hotspot/share/classfile/classFileParser.hpp @@ -500,6 +500,8 @@ class ClassFileParser { InstanceKlass* create_instance_klass(bool cf_changed_in_CFLH, const ClassInstanceInfo& cl_inst_info, TRAPS); + const ClassFileStream& stream() const { return *_stream; } + const ClassFileStream* clone_stream() const; void set_klass_to_deallocate(InstanceKlass* klass); diff --git a/src/hotspot/share/classfile/klassFactory.cpp b/src/hotspot/share/classfile/klassFactory.cpp index 50d327d7e8c..4e599feb3ff 100644 --- a/src/hotspot/share/classfile/klassFactory.cpp +++ b/src/hotspot/share/classfile/klassFactory.cpp @@ -37,7 +37,7 @@ #include "runtime/handles.inline.hpp" #include "utilities/macros.hpp" #if INCLUDE_JFR -#include "jfr/support/jfrKlassExtension.hpp" +#include "jfr/jfr.hpp" #endif @@ -99,6 +99,9 @@ InstanceKlass* KlassFactory::check_shared_class_file_load_hook( new_ik->set_classpath_index(path_index); } + + JFR_ONLY(Jfr::on_klass_creation(new_ik, parser, THREAD);) + return new_ik; } } @@ -213,7 +216,7 @@ InstanceKlass* KlassFactory::create_from_stream(ClassFileStream* stream, result->set_cached_class_file(cached_class_file); } - JFR_ONLY(ON_KLASS_CREATION(result, parser, THREAD);) + JFR_ONLY(Jfr::on_klass_creation(result, parser, THREAD);) #if INCLUDE_CDS if (CDSConfig::is_dumping_archive()) { diff --git a/src/hotspot/share/classfile/systemDictionary.cpp b/src/hotspot/share/classfile/systemDictionary.cpp index a17e7e129ce..ac57293687c 100644 --- a/src/hotspot/share/classfile/systemDictionary.cpp +++ b/src/hotspot/share/classfile/systemDictionary.cpp @@ -560,15 +560,6 @@ static InstanceKlass* handle_parallel_loading(JavaThread* current, return nullptr; } -void SystemDictionary::post_class_load_event(EventClassLoad* event, const InstanceKlass* k, const ClassLoaderData* init_cld) { - assert(event != nullptr, "invariant"); - assert(k != nullptr, "invariant"); - event->set_loadedClass(k); - event->set_definingClassLoader(k->class_loader_data()); - event->set_initiatingClassLoader(init_cld); - event->commit(); -} - // SystemDictionary::resolve_instance_class_or_null is the main function for class name resolution. // After checking if the InstanceKlass already exists, it checks for ClassCircularityError and // whether the thread must wait for loading in parallel. It eventually calls load_instance_class, @@ -582,7 +573,7 @@ InstanceKlass* SystemDictionary::resolve_instance_class_or_null(Symbol* name, assert(name != nullptr && !Signature::is_array(name) && !Signature::has_envelope(name), "invalid class name: %s", name == nullptr ? "nullptr" : name->as_C_string()); - EventClassLoad class_load_start_event; + EventClassLoad class_load_event; HandleMark hm(THREAD); @@ -713,8 +704,8 @@ InstanceKlass* SystemDictionary::resolve_instance_class_or_null(Symbol* name, return nullptr; } - if (class_load_start_event.should_commit()) { - post_class_load_event(&class_load_start_event, loaded_class, loader_data); + if (class_load_event.should_commit()) { + JFR_ONLY(post_class_load_event(&class_load_event, loaded_class, loader_data);) } // Make sure we have the right class in the dictionary @@ -789,7 +780,7 @@ InstanceKlass* SystemDictionary::resolve_hidden_class_from_stream( const ClassLoadInfo& cl_info, TRAPS) { - EventClassLoad class_load_start_event; + EventClassLoad class_load_event; ClassLoaderData* loader_data; // - for hidden classes that are not strong: create a new CLD that has a class holder and @@ -819,15 +810,16 @@ InstanceKlass* SystemDictionary::resolve_hidden_class_from_stream( k->add_to_hierarchy(THREAD); // But, do not add to dictionary. + if (class_load_event.should_commit()) { + JFR_ONLY(post_class_load_event(&class_load_event, k, loader_data);) + } + k->link_class(CHECK_NULL); // notify jvmti if (JvmtiExport::should_post_class_load()) { JvmtiExport::post_class_load(THREAD, k); } - if (class_load_start_event.should_commit()) { - post_class_load_event(&class_load_start_event, k, loader_data); - } return k; } @@ -1154,6 +1146,17 @@ void SystemDictionary::load_shared_class_misc(InstanceKlass* ik, ClassLoaderData } } +#if INCLUDE_JFR +void SystemDictionary::post_class_load_event(EventClassLoad* event, const InstanceKlass* k, const ClassLoaderData* init_cld) { + assert(event != nullptr, "invariant"); + assert(k != nullptr, "invariant"); + event->set_loadedClass(k); + event->set_definingClassLoader(k->class_loader_data()); + event->set_initiatingClassLoader(init_cld); + event->commit(); +} +#endif // INCLUDE_JFR + // This is much more lightweight than SystemDictionary::resolve_or_null // - There's only a single Java thread at this point. No need for placeholder. // - All supertypes of ik have been loaded @@ -1182,6 +1185,8 @@ void SystemDictionary::preload_class(Handle class_loader, InstanceKlass* ik, TRA } #endif + EventClassLoad class_load_event; + ClassLoaderData* loader_data = ClassLoaderData::class_loader_data(class_loader()); oop java_mirror = ik->archived_java_mirror(); precond(java_mirror != nullptr); @@ -1203,6 +1208,10 @@ void SystemDictionary::preload_class(Handle class_loader, InstanceKlass* ik, TRA update_dictionary(THREAD, ik, loader_data); } + if (class_load_event.should_commit()) { + JFR_ONLY(post_class_load_event(&class_load_event, ik, loader_data);) + } + assert(ik->is_loaded(), "Must be in at least loaded state"); } @@ -1380,15 +1389,6 @@ InstanceKlass* SystemDictionary::load_instance_class(Symbol* name, return loaded_class; } -static void post_class_define_event(InstanceKlass* k, const ClassLoaderData* def_cld) { - EventClassDefine event; - if (event.should_commit()) { - event.set_definedClass(k); - event.set_definingClassLoader(def_cld); - event.commit(); - } -} - void SystemDictionary::define_instance_class(InstanceKlass* k, Handle class_loader, TRAPS) { ClassLoaderData* loader_data = k->class_loader_data(); @@ -1440,7 +1440,6 @@ void SystemDictionary::define_instance_class(InstanceKlass* k, Handle class_load if (JvmtiExport::should_post_class_load()) { JvmtiExport::post_class_load(THREAD, k); } - post_class_define_event(k, loader_data); } // Support parallel classloading diff --git a/src/hotspot/share/classfile/systemDictionary.hpp b/src/hotspot/share/classfile/systemDictionary.hpp index 99cb1d0b5d2..99e13fea61e 100644 --- a/src/hotspot/share/classfile/systemDictionary.hpp +++ b/src/hotspot/share/classfile/systemDictionary.hpp @@ -326,11 +326,10 @@ private: static void restore_archived_method_handle_intrinsics_impl(TRAPS) NOT_CDS_RETURN; protected: - // Used by AOTLinkedClassBulkLoader, LambdaProxyClassDictionary, and SystemDictionaryShared + // Used by AOTLinkedClassBulkLoader, LambdaProxyClassDictionary, VMClasses and SystemDictionaryShared static bool add_loader_constraint(Symbol* name, Klass* klass_being_linked, Handle loader1, Handle loader2); - static void post_class_load_event(EventClassLoad* event, const InstanceKlass* k, const ClassLoaderData* init_cld); static InstanceKlass* load_shared_class(InstanceKlass* ik, Handle class_loader, Handle protection_domain, @@ -342,6 +341,9 @@ protected: static InstanceKlass* find_or_define_instance_class(Symbol* class_name, Handle class_loader, InstanceKlass* k, TRAPS); + JFR_ONLY(static void post_class_load_event(EventClassLoad* event, + const InstanceKlass* k, + const ClassLoaderData* init_cld);) public: static bool is_system_class_loader(oop class_loader); diff --git a/src/hotspot/share/classfile/vmClasses.cpp b/src/hotspot/share/classfile/vmClasses.cpp index 0a3d33f4c5b..00d209a05ca 100644 --- a/src/hotspot/share/classfile/vmClasses.cpp +++ b/src/hotspot/share/classfile/vmClasses.cpp @@ -35,6 +35,7 @@ #include "classfile/vmClasses.hpp" #include "classfile/vmSymbols.hpp" #include "gc/shared/collectedHeap.hpp" +#include "jfr/jfrEvents.hpp" #include "memory/metaspaceClosure.hpp" #include "memory/universe.hpp" #include "oops/instanceKlass.hpp" @@ -240,6 +241,8 @@ void vmClasses::resolve_shared_class(InstanceKlass* klass, ClassLoaderData* load return; } + EventClassLoad class_load_event; + // add super and interfaces first InstanceKlass* super = klass->super(); if (super != nullptr && super->class_loader_data() == nullptr) { @@ -261,6 +264,10 @@ void vmClasses::resolve_shared_class(InstanceKlass* klass, ClassLoaderData* load dictionary->add_klass(THREAD, klass->name(), klass); klass->add_to_hierarchy(THREAD); assert(klass->is_loaded(), "Must be in at least loaded state"); + + if (class_load_event.should_commit()) { + JFR_ONLY(SystemDictionary::post_class_load_event(&class_load_event, klass, loader_data);) + } } #endif // INCLUDE_CDS diff --git a/src/hotspot/share/jfr/instrumentation/jfrEventClassTransformer.cpp b/src/hotspot/share/jfr/instrumentation/jfrEventClassTransformer.cpp index d5ef3502fa2..27accac2c00 100644 --- a/src/hotspot/share/jfr/instrumentation/jfrEventClassTransformer.cpp +++ b/src/hotspot/share/jfr/instrumentation/jfrEventClassTransformer.cpp @@ -1427,10 +1427,10 @@ static void transform(InstanceKlass*& ik, ClassFileParser& parser, JavaThread* t } else { JfrClassTransformer::cache_class_file_data(new_ik, stream, thread); } + JfrClassTransformer::copy_traceid(ik, new_ik); if (is_instrumented && JdkJfrEvent::is_subklass(new_ik)) { bless_commit_method(new_ik); } - JfrClassTransformer::copy_traceid(ik, new_ik); JfrClassTransformer::rewrite_klass_pointer(ik, new_ik, parser, thread); } diff --git a/src/hotspot/share/jfr/jfr.cpp b/src/hotspot/share/jfr/jfr.cpp index 7abf5c89945..3a2465e211d 100644 --- a/src/hotspot/share/jfr/jfr.cpp +++ b/src/hotspot/share/jfr/jfr.cpp @@ -22,6 +22,7 @@ * */ +#include "classfile/classFileParser.hpp" #include "jfr/instrumentation/jfrEventClassTransformer.hpp" #include "jfr/jfr.hpp" #include "jfr/jni/jfrJavaSupport.hpp" @@ -31,6 +32,7 @@ #include "jfr/recorder/repository/jfrEmergencyDump.hpp" #include "jfr/recorder/repository/jfrRepository.hpp" #include "jfr/recorder/service/jfrOptionSet.hpp" +#include "jfr/support/jfrClassDefineEvent.hpp" #include "jfr/support/jfrKlassExtension.hpp" #include "jfr/support/jfrResolution.hpp" #include "jfr/support/jfrThreadLocal.hpp" @@ -78,13 +80,15 @@ void Jfr::on_unloading_classes() { } void Jfr::on_klass_creation(InstanceKlass*& ik, ClassFileParser& parser, TRAPS) { + JfrTraceId::assign(ik); if (IS_EVENT_OR_HOST_KLASS(ik)) { JfrEventClassTransformer::on_klass_creation(ik, parser, THREAD); - return; - } - if (JfrMethodTracer::in_use()) { + } else if (JfrMethodTracer::in_use()) { JfrMethodTracer::on_klass_creation(ik, parser, THREAD); } + if (!parser.is_internal()) { + JfrClassDefineEvent::on_creation(ik, parser, THREAD); + } } void Jfr::on_klass_redefinition(const InstanceKlass* ik, const InstanceKlass* scratch_klass) { @@ -168,3 +172,11 @@ bool Jfr::on_flight_recorder_option(const JavaVMOption** option, char* delimiter bool Jfr::on_start_flight_recording_option(const JavaVMOption** option, char* delimiter) { return JfrOptionSet::parse_start_flight_recording_option(option, delimiter); } + +void Jfr::on_restoration(const Klass* k, JavaThread* jt) { + assert(k != nullptr, "invariant"); + JfrTraceId::restore(k); + if (k->is_instance_klass()) { + JfrClassDefineEvent::on_restoration(InstanceKlass::cast(k), jt); + } +} diff --git a/src/hotspot/share/jfr/jfr.hpp b/src/hotspot/share/jfr/jfr.hpp index 2e1fc738a61..7b86e6c917e 100644 --- a/src/hotspot/share/jfr/jfr.hpp +++ b/src/hotspot/share/jfr/jfr.hpp @@ -25,6 +25,7 @@ #ifndef SHARE_JFR_JFR_HPP #define SHARE_JFR_JFR_HPP +#include "jfr/utilities/jfrTypes.hpp" #include "memory/allStatic.hpp" #include "oops/oopsHierarchy.hpp" #include "utilities/exceptions.hpp" @@ -78,6 +79,7 @@ class Jfr : AllStatic { static void initialize_main_thread(JavaThread* jt); static bool has_sample_request(JavaThread* jt); static void check_and_process_sample_request(JavaThread* jt); + static void on_restoration(const Klass* k, JavaThread* jt); }; #endif // SHARE_JFR_JFR_HPP diff --git a/src/hotspot/share/jfr/metadata/metadata.xml b/src/hotspot/share/jfr/metadata/metadata.xml index eaafef37306..18a74454eb6 100644 --- a/src/hotspot/share/jfr/metadata/metadata.xml +++ b/src/hotspot/share/jfr/metadata/metadata.xml @@ -215,6 +215,7 @@ + diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp index 375ab4d04e9..b1c502e17f8 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp @@ -30,11 +30,12 @@ #include "classfile/vmClasses.hpp" #include "jfr/leakprofiler/checkpoint/objectSampleCheckpoint.hpp" #include "jfr/recorder/checkpoint/types/jfrTypeSet.hpp" -#include "jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp" +#include "jfr/recorder/checkpoint/types/jfrTypeSetUtils.inline.hpp" #include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp" #include "jfr/recorder/checkpoint/types/traceid/jfrTraceIdLoadBarrier.inline.hpp" #include "jfr/recorder/jfrRecorder.hpp" #include "jfr/support/jfrKlassUnloading.hpp" +#include "jfr/support/jfrSymbolTable.inline.hpp" #include "jfr/support/methodtracer/jfrInstrumentedClass.hpp" #include "jfr/support/methodtracer/jfrMethodTracer.hpp" #include "jfr/utilities/jfrHashtable.hpp" @@ -1262,7 +1263,7 @@ static size_t teardown() { clear_klasses_and_methods(); clear_method_tracer_klasses(); JfrKlassUnloading::clear(); - _artifacts->increment_checkpoint_id(); + _artifacts->clear(); _initial_type_set = true; } else { _initial_type_set = false; diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.cpp b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.cpp index c60556927ad..765bba69105 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.cpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.cpp @@ -23,18 +23,19 @@ */ #include "jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp" +#include "jfr/support/jfrSymbolTable.inline.hpp" #include "jfr/utilities/jfrPredicate.hpp" #include "jfr/utilities/jfrRelation.hpp" #include "oops/instanceKlass.hpp" #include "oops/oop.inline.hpp" #include "oops/symbol.hpp" -JfrArtifactSet::JfrArtifactSet(bool class_unload, bool previous_epoch) : _symbol_table(nullptr), - _klass_set(nullptr), +JfrArtifactSet::JfrArtifactSet(bool class_unload, bool previous_epoch) : _klass_set(nullptr), _klass_loader_set(nullptr), _klass_loader_leakp_set(nullptr), _total_count(0), - _class_unload(class_unload) { + _class_unload(class_unload), + _previous_epoch(previous_epoch) { initialize(class_unload, previous_epoch); assert(!previous_epoch || _klass_loader_leakp_set != nullptr, "invariant"); assert(_klass_loader_set != nullptr, "invariant"); @@ -47,12 +48,7 @@ static unsigned initial_klass_loader_leakp_set_size = 64; void JfrArtifactSet::initialize(bool class_unload, bool previous_epoch) { _class_unload = class_unload; - if (_symbol_table == nullptr) { - _symbol_table = JfrSymbolTable::create(); - assert(_symbol_table != nullptr, "invariant"); - } - assert(_symbol_table != nullptr, "invariant"); - _symbol_table->set_class_unload(class_unload); + _previous_epoch = previous_epoch; _total_count = 0; // Resource allocations. Keep in this allocation order. if (previous_epoch) { @@ -63,45 +59,33 @@ void JfrArtifactSet::initialize(bool class_unload, bool previous_epoch) { } void JfrArtifactSet::clear() { - if (_symbol_table != nullptr) { - _symbol_table->clear(); - } + assert(_previous_epoch, "invariant"); + JfrSymbolTable::clear_previous_epoch(); + assert(_klass_loader_leakp_set != nullptr, "invariant"); + initial_klass_loader_leakp_set_size = MAX2(initial_klass_loader_leakp_set_size, _klass_loader_leakp_set->table_size()); } JfrArtifactSet::~JfrArtifactSet() { - delete _symbol_table; // _klass_loader_set, _klass_loader_leakp_set and // _klass_list will be cleared by a ResourceMark } traceid JfrArtifactSet::bootstrap_name(bool leakp) { - return _symbol_table->bootstrap_name(leakp); -} - -traceid JfrArtifactSet::mark_hidden_klass_name(const Klass* klass, bool leakp) { - assert(klass->is_instance_klass(), "invariant"); - return _symbol_table->mark_hidden_klass_name((const InstanceKlass*)klass, leakp); -} - -traceid JfrArtifactSet::mark(uintptr_t hash, const Symbol* sym, bool leakp) { - return _symbol_table->mark(hash, sym, leakp); + return JfrSymbolTable::bootstrap_name(leakp); } traceid JfrArtifactSet::mark(const Klass* klass, bool leakp) { - return _symbol_table->mark(klass, leakp); + return JfrSymbolTable::mark(klass, leakp, _class_unload, _previous_epoch); } traceid JfrArtifactSet::mark(const Symbol* symbol, bool leakp) { - return _symbol_table->mark(symbol, leakp); -} - -traceid JfrArtifactSet::mark(uintptr_t hash, const char* const str, bool leakp) { - return _symbol_table->mark(hash, str, leakp); + return JfrSymbolTable::mark(symbol, leakp, _class_unload, _previous_epoch); } bool JfrArtifactSet::has_klass_entries() const { return _klass_set->is_nonempty(); } + static inline bool not_in_set(JfrArtifactSet::JfrKlassSet* set, const Klass* k) { assert(set != nullptr, "invariant"); assert(k != nullptr, "invariant"); @@ -129,10 +113,3 @@ size_t JfrArtifactSet::total_count() const { initial_klass_loader_set_size = MAX2(initial_klass_loader_set_size, _klass_loader_set->table_size()); return _total_count; } - -void JfrArtifactSet::increment_checkpoint_id() { - assert(_symbol_table != nullptr, "invariant"); - _symbol_table->increment_checkpoint_id(); - assert(_klass_loader_leakp_set != nullptr, "invariant"); - initial_klass_loader_leakp_set_size = MAX2(initial_klass_loader_leakp_set_size, _klass_loader_leakp_set->table_size()); -} diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp index 74200aef1f1..cc5ebb2be39 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp @@ -207,12 +207,12 @@ class JfrArtifactSet : public JfrCHeapObj { typedef JfrSet JfrKlassSet; private: - JfrSymbolTable* _symbol_table; JfrKlassSet* _klass_set; JfrKlassSet* _klass_loader_set; JfrKlassSet* _klass_loader_leakp_set; size_t _total_count; bool _class_unload; + bool _previous_epoch; public: JfrArtifactSet(bool class_unload, bool previous_epoch); @@ -222,32 +222,20 @@ class JfrArtifactSet : public JfrCHeapObj { void initialize(bool class_unload, bool previous_epoch); void clear(); - traceid mark(uintptr_t hash, const Symbol* sym, bool leakp); traceid mark(const Klass* klass, bool leakp); traceid mark(const Symbol* symbol, bool leakp); - traceid mark(uintptr_t hash, const char* const str, bool leakp); - traceid mark_hidden_klass_name(const Klass* klass, bool leakp); traceid bootstrap_name(bool leakp); - const JfrSymbolTable::SymbolEntry* map_symbol(const Symbol* symbol) const; - const JfrSymbolTable::SymbolEntry* map_symbol(uintptr_t hash) const; - const JfrSymbolTable::StringEntry* map_string(uintptr_t hash) const; - bool has_klass_entries() const; size_t total_count() const; void register_klass(const Klass* k); bool should_do_cld_klass(const Klass* k, bool leakp); - void increment_checkpoint_id(); template - void iterate_symbols(T& functor) { - _symbol_table->iterate_symbols(functor); - } + void iterate_symbols(T& functor); template - void iterate_strings(T& functor) { - _symbol_table->iterate_strings(functor); - } + void iterate_strings(T& functor); template void tally(Writer& writer) { diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.inline.hpp b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.inline.hpp new file mode 100644 index 00000000000..a1a25c4e907 --- /dev/null +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.inline.hpp @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2025, 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. + * + */ + +#ifndef SHARE_JFR_RECORDER_CHECKPOINT_TYPES_JFRTYPESETUTILS_INLINE_HPP +#define SHARE_JFR_RECORDER_CHECKPOINT_TYPES_JFRTYPESETUTILS_INLINE_HPP + +#include "jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp" + +#include "jfr/support/jfrSymbolTable.inline.hpp" + +template +inline void JfrArtifactSet::iterate_symbols(T& functor) { + JfrSymbolTable::iterate_symbols(functor, _previous_epoch); +} + +template +inline void JfrArtifactSet::iterate_strings(T& functor) { + JfrSymbolTable::iterate_strings(functor, _previous_epoch); +} + +#endif // SHARE_JFR_RECORDER_CHECKPOINT_TYPES_JFRTYPESETUTILS_INLINE_HPP diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceId.cpp b/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceId.cpp index 2fcb1a64baf..405fa25baff 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceId.cpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceId.cpp @@ -109,6 +109,7 @@ static void check_klass(const Klass* klass) { void JfrTraceId::assign(const Klass* klass) { assert(klass != nullptr, "invariant"); + assert(klass->trace_id() == 0, "invariant"); klass->set_trace_id(next_class_id()); check_klass(klass); const Klass* const super = klass->super(); diff --git a/src/hotspot/share/jfr/recorder/jfrRecorder.cpp b/src/hotspot/share/jfr/recorder/jfrRecorder.cpp index f5214ff7942..6a6da0f9b04 100644 --- a/src/hotspot/share/jfr/recorder/jfrRecorder.cpp +++ b/src/hotspot/share/jfr/recorder/jfrRecorder.cpp @@ -43,6 +43,7 @@ #include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp" #include "jfr/recorder/storage/jfrStorage.hpp" #include "jfr/recorder/stringpool/jfrStringPool.hpp" +#include "jfr/support/jfrSymbolTable.hpp" #include "jfr/support/jfrThreadLocal.hpp" #include "jfr/utilities/jfrTime.hpp" #include "jfr/writers/jfrJavaEventWriter.hpp" @@ -315,6 +316,9 @@ bool JfrRecorder::create_components() { if (!create_thread_group_manager()) { return false; } + if (!create_symbol_table()) { + return false; + } return true; } @@ -413,6 +417,10 @@ bool JfrRecorder::create_thread_group_manager() { return JfrThreadGroupManager::create(); } +bool JfrRecorder::create_symbol_table() { + return JfrSymbolTable::create(); +} + void JfrRecorder::destroy_components() { JfrJvmtiAgent::destroy(); if (_post_box != nullptr) { @@ -453,6 +461,7 @@ void JfrRecorder::destroy_components() { } JfrEventThrottler::destroy(); JfrThreadGroupManager::destroy(); + JfrSymbolTable::destroy(); } bool JfrRecorder::create_recorder_thread() { diff --git a/src/hotspot/share/jfr/recorder/jfrRecorder.hpp b/src/hotspot/share/jfr/recorder/jfrRecorder.hpp index 34cc8fda949..8cc4521669d 100644 --- a/src/hotspot/share/jfr/recorder/jfrRecorder.hpp +++ b/src/hotspot/share/jfr/recorder/jfrRecorder.hpp @@ -57,6 +57,7 @@ class JfrRecorder : public JfrCHeapObj { static bool create_thread_sampler(); static bool create_cpu_time_thread_sampling(); static bool create_event_throttler(); + static bool create_symbol_table(); static bool create_components(); static void destroy_components(); static void on_recorder_thread_exit(); diff --git a/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp b/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp index 3f0b132f1a4..08250a1ae59 100644 --- a/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp +++ b/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp @@ -39,6 +39,7 @@ #include "jfr/recorder/storage/jfrStorageControl.hpp" #include "jfr/recorder/stringpool/jfrStringPool.hpp" #include "jfr/support/jfrDeprecationManager.hpp" +#include "jfr/support/jfrSymbolTable.inline.hpp" #include "jfr/utilities/jfrAllocation.hpp" #include "jfr/utilities/jfrThreadIterator.hpp" #include "jfr/utilities/jfrTime.hpp" @@ -450,6 +451,7 @@ void JfrRecorderService::clear() { void JfrRecorderService::pre_safepoint_clear() { _storage.clear(); JfrStackTraceRepository::clear(); + JfrSymbolTable::allocate_next_epoch(); } void JfrRecorderService::invoke_safepoint_clear() { @@ -558,6 +560,7 @@ void JfrRecorderService::pre_safepoint_write() { } write_storage(_storage, _chunkwriter); write_stacktrace(_stack_trace_repository, _chunkwriter, true); + JfrSymbolTable::allocate_next_epoch(); } void JfrRecorderService::invoke_safepoint_write() { diff --git a/src/hotspot/share/jfr/support/jfrClassDefineEvent.cpp b/src/hotspot/share/jfr/support/jfrClassDefineEvent.cpp new file mode 100644 index 00000000000..06f361ced8c --- /dev/null +++ b/src/hotspot/share/jfr/support/jfrClassDefineEvent.cpp @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2025, 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. + * + */ + +#include "cds/aotClassLocation.hpp" +#include "classfile/classFileParser.hpp" +#include "classfile/classFileStream.hpp" +#include "classfile/classLoaderData.inline.hpp" +#include "jfr/instrumentation/jfrClassTransformer.hpp" +#include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp" +#include "jfr/support/jfrClassDefineEvent.hpp" +#include "jfr/support/jfrSymbolTable.hpp" +#include "jfrfiles/jfrEventClasses.hpp" +#include "oops/instanceKlass.hpp" +#include "runtime/javaThread.hpp" + + /* + * Two cases for JDK modules as outlined by JEP 200: The Modular JDK. + * + * The modular structure of the JDK implements the following principles: + * 1. Standard modules, whose specifications are governed by the JCP, have names starting with the string "java.". + * 2. All other modules are merely part of the JDK, and have names starting with the string "jdk.". + * */ +static inline bool is_jdk_module(const char* module_name) { + assert(module_name != nullptr, "invariant"); + return strstr(module_name, "java.") == module_name || strstr(module_name, "jdk.") == module_name; +} + +static inline bool is_unnamed_module(const ModuleEntry* module) { + return module == nullptr || !module->is_named(); +} + +static inline bool is_jdk_module(const ModuleEntry* module, JavaThread* jt) { + assert(jt != nullptr, "invariant"); + if (is_unnamed_module(module)) { + return false; + } + const Symbol* const module_symbol = module->name(); + assert(module_symbol != nullptr, "invariant"); + return is_jdk_module(module_symbol->as_C_string()); +} + +static inline bool is_jdk_module(const InstanceKlass* ik, JavaThread* jt) { + assert(ik != nullptr, "invariant"); + assert(jt != nullptr, "invariant"); + return is_jdk_module(ik->module(), jt); +} + +static traceid module_path(const InstanceKlass* ik, JavaThread* jt) { + assert(ik != nullptr, "invariant"); + const ModuleEntry* const module_entry = ik->module(); + if (is_unnamed_module(module_entry)) { + return 0; + } + const char* const module_name = module_entry->name()->as_C_string(); + assert(module_name != nullptr, "invariant"); + if (is_jdk_module(module_name)) { + const size_t module_name_len = strlen(module_name); + char* const path = NEW_RESOURCE_ARRAY_IN_THREAD(jt, char, module_name_len + 6); // "jrt:/" + jio_snprintf(path, module_name_len + 6, "%s%s", "jrt:/", module_name); + return JfrSymbolTable::add(path); + } + return 0; +} + +static traceid caller_path(const InstanceKlass* ik, JavaThread* jt) { + assert(ik != nullptr, "invariant"); + assert(jt != nullptr, "invariant"); + assert(ik->class_loader_data()->is_the_null_class_loader_data(), "invariant"); + const Klass* const caller = jt->security_get_caller_class(1); + // caller can be null, for example, during a JVMTI VM_Init hook + if (caller != nullptr) { + const char* caller_name = caller->external_name(); + assert(caller_name != nullptr, "invariant"); + const size_t caller_name_len = strlen(caller_name); + char* const path = NEW_RESOURCE_ARRAY_IN_THREAD(jt, char, caller_name_len + 13); // "instance of " + jio_snprintf(path, caller_name_len + 13, "%s%s", "instance of ", caller_name); + return JfrSymbolTable::add(path); + } + return 0; +} + +static traceid class_loader_path(const InstanceKlass* ik, JavaThread* jt) { + assert(ik != nullptr, "invariant"); + assert(jt != nullptr, "invariant"); + assert(!ik->class_loader_data()->is_the_null_class_loader_data(), "invariant"); + oop class_loader = ik->class_loader_data()->class_loader(); + const char* class_loader_name = class_loader->klass()->external_name(); + return class_loader_name != nullptr ? JfrSymbolTable::add(class_loader_name) : 0; +} + +static inline bool is_not_retransforming(const InstanceKlass* ik, JavaThread* jt) { + return JfrClassTransformer::find_existing_klass(ik, jt) == nullptr; +} + +static traceid get_source(const InstanceKlass* ik, JavaThread* jt) { + traceid source_id = 0; + if (is_jdk_module(ik, jt)) { + source_id = module_path(ik, jt); + } else if (ik->class_loader_data()->is_the_null_class_loader_data()) { + source_id = caller_path(ik, jt); + } else { + source_id = class_loader_path(ik, jt); + } + return source_id; +} + +static traceid get_source(const AOTClassLocation* cl, JavaThread* jt) { + assert(cl != nullptr, "invariant"); + assert(!cl->is_modules_image(), "invariant"); + const char* const path = cl->path(); + assert(path != nullptr, "invariant"); + size_t len = strlen(path); + const char* file_type = cl->file_type_string(); + assert(file_type != nullptr, "invariant"); + len += strlen(file_type) + 3; // ":/" + null + char* const url = NEW_RESOURCE_ARRAY_IN_THREAD(jt, char, len); + jio_snprintf(url, len, "%s%s%s", file_type, ":/", path); + return JfrSymbolTable::add(url); +} + +static inline void send_event(const InstanceKlass* ik, traceid source_id) { + EventClassDefine event; + event.set_definedClass(ik); + event.set_definingClassLoader(ik->class_loader_data()); + event.set_source(source_id); + event.commit(); +} + +void JfrClassDefineEvent::on_creation(const InstanceKlass* ik, const ClassFileParser& parser, JavaThread* jt) { + assert(ik != nullptr, "invariant"); + assert(ik->trace_id() != 0, "invariant"); + assert(!parser.is_internal(), "invariant"); + assert(jt != nullptr, "invariant"); + + if (EventClassDefine::is_enabled() && is_not_retransforming(ik, jt)) { + ResourceMark rm(jt); + traceid source_id = 0; + const ClassFileStream& stream = parser.stream(); + if (stream.source() != nullptr) { + if (stream.from_boot_loader_modules_image()) { + assert(is_jdk_module(ik, jt), "invariant"); + source_id = module_path(ik, jt); + } else { + source_id = JfrSymbolTable::add(stream.source()); + } + } else { + source_id = get_source(ik, jt); + } + send_event(ik, source_id); + } +} + +void JfrClassDefineEvent::on_restoration(const InstanceKlass* ik, JavaThread* jt) { + assert(ik != nullptr, "invariant"); + assert(ik->trace_id() != 0, "invariant"); + assert(jt != nullptr, "invariant"); + + if (EventClassDefine::is_enabled()) { + ResourceMark rm(jt); + assert(is_not_retransforming(ik, jt), "invariant"); + const int index = ik->shared_classpath_index(); + assert(index >= 0, "invariant"); + const AOTClassLocation* const cl = AOTClassLocationConfig::runtime()->class_location_at(index); + assert(cl != nullptr, "invariant"); + send_event(ik, cl->is_modules_image() ? module_path(ik, jt) : get_source(cl, jt)); + } +} diff --git a/src/hotspot/share/jfr/support/jfrClassDefineEvent.hpp b/src/hotspot/share/jfr/support/jfrClassDefineEvent.hpp new file mode 100644 index 00000000000..4a0926023ca --- /dev/null +++ b/src/hotspot/share/jfr/support/jfrClassDefineEvent.hpp @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2025, 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. + * + */ + +#ifndef SHARE_JFR_SUPPORT_JFRCLASSDEFINEEVENT_HPP +#define SHARE_JFR_SUPPORT_JFRCLASSDEFINEEVENT_HPP + +#include "memory/allStatic.hpp" + +class ClassFileParser; +class InstanceKlass; +class JavaThread; + +class JfrClassDefineEvent : AllStatic { + public: + static void on_creation(const InstanceKlass* ik, const ClassFileParser& parser, JavaThread* jt); + static void on_restoration(const InstanceKlass* ik, JavaThread* jt); +}; + +#endif // SHARE_JFR_SUPPORT_JFRCLASSDEFINEEVENT_HPP diff --git a/src/hotspot/share/jfr/support/jfrKlassExtension.hpp b/src/hotspot/share/jfr/support/jfrKlassExtension.hpp index dc5f7aa7e90..54f5031dd3b 100644 --- a/src/hotspot/share/jfr/support/jfrKlassExtension.hpp +++ b/src/hotspot/share/jfr/support/jfrKlassExtension.hpp @@ -40,6 +40,5 @@ #define EVENT_STICKY_BIT 8192 #define IS_EVENT_KLASS(ptr) (((ptr)->trace_id() & (JDK_JFR_EVENT_KLASS | JDK_JFR_EVENT_SUBKLASS)) != 0) #define IS_EVENT_OR_HOST_KLASS(ptr) (((ptr)->trace_id() & (JDK_JFR_EVENT_KLASS | JDK_JFR_EVENT_SUBKLASS | EVENT_HOST_KLASS)) != 0) -#define ON_KLASS_CREATION(k, p, t) Jfr::on_klass_creation(k, p, t) #endif // SHARE_JFR_SUPPORT_JFRKLASSEXTENSION_HPP diff --git a/src/hotspot/share/jfr/support/jfrSymbolTable.cpp b/src/hotspot/share/jfr/support/jfrSymbolTable.cpp index 3fc639ffb5c..c791a05f818 100644 --- a/src/hotspot/share/jfr/support/jfrSymbolTable.cpp +++ b/src/hotspot/share/jfr/support/jfrSymbolTable.cpp @@ -24,131 +24,32 @@ #include "classfile/classLoaderData.hpp" #include "classfile/javaClasses.hpp" -#include "jfr/support/jfrSymbolTable.hpp" +#include "jfr/recorder/jfrRecorder.hpp" +#include "jfr/support/jfrSymbolTable.inline.hpp" #include "oops/klass.hpp" #include "oops/symbol.hpp" +#include "runtime/atomicAccess.hpp" #include "runtime/mutexLocker.hpp" -// incremented on each rotation -static u8 checkpoint_id = 1; +JfrSymbolTable::Impl* JfrSymbolTable::_epoch_0 = nullptr; +JfrSymbolTable::Impl* JfrSymbolTable::_epoch_1 = nullptr; +JfrSymbolTable::StringEntry* JfrSymbolTable::_bootstrap = nullptr; -// creates a unique id by combining a checkpoint relative symbol id (2^24) -// with the current checkpoint id (2^40) -#define CREATE_SYMBOL_ID(sym_id) (((u8)((checkpoint_id << 24) | sym_id))) - -static traceid create_symbol_id(traceid artifact_id) { - return artifact_id != 0 ? CREATE_SYMBOL_ID(artifact_id) : 0; -} - -static uintptr_t string_hash(const char* str) { - return java_lang_String::hash_code(reinterpret_cast(str), static_cast(strlen(str))); -} - -static JfrSymbolTable::StringEntry* bootstrap = nullptr; - -static JfrSymbolTable* _instance = nullptr; - -static JfrSymbolTable& instance() { - assert(_instance != nullptr, "invariant"); - return *_instance; -} - -JfrSymbolTable* JfrSymbolTable::create() { - assert(_instance == nullptr, "invariant"); - assert_locked_or_safepoint(ClassLoaderDataGraph_lock); - _instance = new JfrSymbolTable(); - return _instance; -} - -void JfrSymbolTable::destroy() { - assert_locked_or_safepoint(ClassLoaderDataGraph_lock); - if (_instance != nullptr) { - delete _instance; - _instance = nullptr; - } - assert(_instance == nullptr, "invariant"); -} - -JfrSymbolTable::JfrSymbolTable() : - _symbols(new Symbols(this)), - _strings(new Strings(this)), - _symbol_list(nullptr), - _string_list(nullptr), - _symbol_query(nullptr), - _string_query(nullptr), - _id_counter(1), - _class_unload(false) { - assert(_symbols != nullptr, "invariant"); - assert(_strings != nullptr, "invariant"); - bootstrap = new StringEntry(0, (const char*)&BOOTSTRAP_LOADER_NAME); - assert(bootstrap != nullptr, "invariant"); - bootstrap->set_id(create_symbol_id(1)); - _string_list = bootstrap; -} - -JfrSymbolTable::~JfrSymbolTable() { - clear(); - delete _symbols; - delete _strings; - delete bootstrap; -} - -void JfrSymbolTable::clear() { - assert(_symbols != nullptr, "invariant"); - if (_symbols->has_entries()) { - _symbols->clear_entries(); - } - assert(!_symbols->has_entries(), "invariant"); - - assert(_strings != nullptr, "invariant"); - if (_strings->has_entries()) { - _strings->clear_entries(); - } - assert(!_strings->has_entries(), "invariant"); - - _symbol_list = nullptr; - _id_counter = 1; - - _symbol_query = nullptr; - _string_query = nullptr; - - assert(bootstrap != nullptr, "invariant"); - bootstrap->reset(); - _string_list = bootstrap; -} - -void JfrSymbolTable::set_class_unload(bool class_unload) { - _class_unload = class_unload; -} - -void JfrSymbolTable::increment_checkpoint_id() { - assert_lock_strong(ClassLoaderDataGraph_lock); - clear(); - ++checkpoint_id; -} +JfrSymbolCallback::JfrSymbolCallback() : _id_counter(2) {} // 1 is reserved for "bootstrap" entry template -inline void JfrSymbolTable::assign_id(T* entry) { +inline void JfrSymbolCallback::assign_id(const T* entry) { assert(entry != nullptr, "invariant"); assert(entry->id() == 0, "invariant"); - entry->set_id(create_symbol_id(++_id_counter)); + entry->set_id(AtomicAccess::fetch_then_add(&_id_counter, (traceid)1)); } -void JfrSymbolTable::on_link(const SymbolEntry* entry) { +void JfrSymbolCallback::on_link(const JfrSymbolTable::SymbolEntry* entry) { assign_id(entry); const_cast(entry->literal())->increment_refcount(); - entry->set_list_next(_symbol_list); - _symbol_list = entry; } -bool JfrSymbolTable::on_equals(uintptr_t hash, const SymbolEntry* entry) { - assert(entry != nullptr, "invariant"); - assert(entry->hash() == hash, "invariant"); - assert(_symbol_query != nullptr, "invariant"); - return _symbol_query == entry->literal(); -} - -void JfrSymbolTable::on_unlink(const SymbolEntry* entry) { +void JfrSymbolCallback::on_unlink(const JfrSymbolTable::SymbolEntry* entry) { assert(entry != nullptr, "invariant"); const_cast(entry->literal())->decrement_refcount(); } @@ -162,75 +63,241 @@ static const char* resource_to_c_heap_string(const char* resource_str) { return c_string; } -void JfrSymbolTable::on_link(const StringEntry* entry) { +void JfrSymbolCallback::on_link(const JfrSymbolTable::StringEntry* entry) { assign_id(entry); - const_cast(entry)->set_literal(resource_to_c_heap_string(entry->literal())); - entry->set_list_next(_string_list); - _string_list = entry; + const_cast(entry)->set_literal(resource_to_c_heap_string(entry->literal())); } -static bool string_compare(const char* query, const char* candidate) { - assert(query != nullptr, "invariant"); - assert(candidate != nullptr, "invariant"); - const size_t length = strlen(query); - return strncmp(query, candidate, length) == 0; -} - -bool JfrSymbolTable::on_equals(uintptr_t hash, const StringEntry* entry) { +void JfrSymbolCallback::on_unlink(const JfrSymbolTable::StringEntry* entry) { assert(entry != nullptr, "invariant"); - assert(entry->hash() == hash, "invariant"); - assert(_string_query != nullptr, "invariant"); - return string_compare(_string_query, entry->literal()); + JfrCHeapObj::free(const_cast(entry->literal()), strlen(entry->literal()) + 1); } -void JfrSymbolTable::on_unlink(const StringEntry* entry) { - assert(entry != nullptr, "invariant"); - JfrCHeapObj::free(const_cast(entry->literal()), strlen(entry->literal() + 1)); +static JfrSymbolCallback* _callback = nullptr; + +template +JfrSymbolTableEntry::JfrSymbolTableEntry(unsigned hash, const T& data) : + JfrConcurrentHashtableEntry(hash, data), _serialized(false), _unloading(false), _leakp(false) {} + +template +bool JfrSymbolTableEntry::on_equals(const char* str) { + assert(str != nullptr, "invariant"); + return strcmp((const char*)this->literal(), str) == 0; +} + +static const constexpr unsigned max_capacity = 1 << 30; + +static inline unsigned calculate_capacity(unsigned size, unsigned capacity) { + assert(is_power_of_2(capacity), "invariant"); + assert(capacity <= max_capacity, "invariant"); + double load_factor = (double)size / (double)capacity; + if (load_factor < 0.75) { + return capacity; + } + do { + capacity <<= 1; + assert(is_power_of_2(capacity), "invariant"); + guarantee(capacity <= max_capacity, "overflow"); + load_factor = (double)size / (double)capacity; + } while (load_factor >= 0.75); + return capacity; +} + +bool JfrSymbolTable::create() { + assert(_callback == nullptr, "invariant"); + // Allocate callback instance before tables. + _callback = new JfrSymbolCallback(); + if (_callback == nullptr) { + return false; + } + assert(_bootstrap == nullptr, "invariant"); + _bootstrap = new StringEntry(0, (const char*)&BOOTSTRAP_LOADER_NAME); + if (_bootstrap == nullptr) { + return false; + } + _bootstrap->set_id(1); + assert(this_epoch_table() == nullptr, "invariant"); + Impl* table = new JfrSymbolTable::Impl(); + if (table == nullptr) { + return false; + } + set_this_epoch(table); + assert(previous_epoch_table() == nullptr, "invariant"); + return true; +} + +void JfrSymbolTable::destroy() { + if (_callback != nullptr) { + delete _callback; + _callback = nullptr; + } + if (_bootstrap != nullptr) { + delete _bootstrap; + _bootstrap = nullptr; + } + if (_epoch_0 != nullptr) { + delete _epoch_0; + _epoch_0 = nullptr; + } + if (_epoch_1 != nullptr) { + delete _epoch_1; + _epoch_1 = nullptr; + } +} + +void JfrSymbolTable::allocate_next_epoch() { + assert(nullptr == previous_epoch_table(), "invariant"); + const Impl* const current = this_epoch_table(); + assert(current != nullptr, "invariant"); + const unsigned next_symbols_capacity = calculate_capacity(current->symbols_size(), current->symbols_capacity()); + const unsigned next_strings_capacity = calculate_capacity(current->strings_size(), current->strings_capacity()); + assert(_callback != nullptr, "invariant"); + // previous epoch to become the next epoch. + set_previous_epoch(new JfrSymbolTable::Impl(next_symbols_capacity, next_strings_capacity)); + assert(this_epoch_table() != nullptr, "invariant"); + assert(previous_epoch_table() != nullptr, "invariant"); +} + +void JfrSymbolTable::clear_previous_epoch() { + Impl* const table = previous_epoch_table(); + assert(table != nullptr, "invariant"); + set_previous_epoch(nullptr); + delete table; + assert(_bootstrap != nullptr, "invariant"); + _bootstrap->reset(); + assert(!_bootstrap->is_serialized(), "invariant"); +} + +void JfrSymbolTable::set_this_epoch(JfrSymbolTable::Impl* table) { + assert(table != nullptr, "invariant"); + const u1 epoch = JfrTraceIdEpoch::current(); + if (epoch == 0) { + _epoch_0 = table; + } else { + _epoch_1 = table; + } +} + +void JfrSymbolTable::set_previous_epoch(JfrSymbolTable::Impl* table) { + const u1 epoch = JfrTraceIdEpoch::previous(); + if (epoch == 0) { + _epoch_0 = table; + } else { + _epoch_1 = table; + } +} + +inline bool JfrSymbolTable::Impl::has_symbol_entries() const { + return _symbols->is_nonempty(); +} + +inline bool JfrSymbolTable::Impl::has_string_entries() const { + return _strings->is_nonempty(); +} + +inline bool JfrSymbolTable::Impl::has_entries() const { + return has_symbol_entries() || has_string_entries(); +} + +inline unsigned JfrSymbolTable::Impl::symbols_capacity() const { + return _symbols->capacity(); +} + +inline unsigned JfrSymbolTable::Impl::symbols_size() const { + return _symbols->size(); +} + +inline unsigned JfrSymbolTable::Impl::strings_capacity() const { + return _strings->capacity(); +} + +inline unsigned JfrSymbolTable::Impl::strings_size() const { + return _strings->size(); +} + +bool JfrSymbolTable::has_entries(bool previous_epoch /* false */) { + const Impl* table = previous_epoch ? previous_epoch_table() : this_epoch_table(); + assert(table != nullptr, "invariant"); + return table->has_entries(); +} + +bool JfrSymbolTable::has_symbol_entries(bool previous_epoch /* false */) { + const Impl* table = previous_epoch ? previous_epoch_table() : this_epoch_table(); + assert(table != nullptr, "invariant"); + return table->has_symbol_entries(); +} + +bool JfrSymbolTable::has_string_entries(bool previous_epoch /* false */) { + const Impl* table = previous_epoch ? previous_epoch_table() : this_epoch_table(); + assert(table != nullptr, "invariant"); + return table->has_string_entries(); } traceid JfrSymbolTable::bootstrap_name(bool leakp) { - assert(bootstrap != nullptr, "invariant"); + assert(_bootstrap != nullptr, "invariant"); if (leakp) { - bootstrap->set_leakp(); + _bootstrap->set_leakp(); } - return bootstrap->id(); + return _bootstrap->id(); } -traceid JfrSymbolTable::mark(const Symbol* sym, bool leakp /* false */) { +JfrSymbolTable::Impl::Impl(unsigned symbols_capacity /* 0*/, unsigned strings_capacity /* 0 */) : + _symbols(new Symbols(_callback, symbols_capacity)), _strings(new Strings(_callback, strings_capacity)) {} + +JfrSymbolTable::Impl::~Impl() { + delete _symbols; + delete _strings; +} + +traceid JfrSymbolTable::Impl::mark(const Symbol* sym, bool leakp /* false */, bool class_unload /* false */) { assert(sym != nullptr, "invariant"); - return mark(sym->identity_hash(), sym, leakp); + return mark(sym->identity_hash(), sym, leakp, class_unload); } -traceid JfrSymbolTable::mark(uintptr_t hash, const Symbol* sym, bool leakp) { +traceid JfrSymbolTable::Impl::mark(unsigned hash, const Symbol* sym, bool leakp, bool class_unload /* false */) { assert(sym != nullptr, "invariant"); assert(_symbols != nullptr, "invariant"); - _symbol_query = sym; - const SymbolEntry& entry = _symbols->lookup_put(hash, sym); - if (_class_unload) { - entry.set_unloading(); - } + const SymbolEntry* entry = _symbols->lookup_put(hash, sym); + assert(entry != nullptr, "invariant"); if (leakp) { - entry.set_leakp(); + entry->set_leakp(); + } else if (class_unload) { + entry->set_unloading(); } - return entry.id(); + return entry->id(); } -traceid JfrSymbolTable::mark(const char* str, bool leakp /* false*/) { - return mark(string_hash(str), str, leakp); +traceid JfrSymbolTable::mark(const Symbol* sym, bool leakp /* false */, bool class_unload /* false */, bool previous_epoch /* false */) { + Impl* const table = previous_epoch ? previous_epoch_table() : this_epoch_table(); + assert(table != nullptr, "invariant"); + return table->mark(sym->identity_hash(), sym, leakp, class_unload); } -traceid JfrSymbolTable::mark(uintptr_t hash, const char* str, bool leakp) { +static inline unsigned string_hash(const char* str) { + return java_lang_String::hash_code(reinterpret_cast(str), static_cast(strlen(str))); +} + +traceid JfrSymbolTable::Impl::mark(const char* str, bool leakp /* false*/, bool class_unload /* false */) { + return mark(string_hash(str), str, leakp, class_unload); +} + +traceid JfrSymbolTable::Impl::mark(unsigned hash, const char* str, bool leakp, bool class_unload /* false */) { assert(str != nullptr, "invariant"); assert(_strings != nullptr, "invariant"); - _string_query = str; - const StringEntry& entry = _strings->lookup_put(hash, str); - if (_class_unload) { - entry.set_unloading(); - } + const StringEntry* entry = _strings->lookup_put(hash, str); + assert(entry != nullptr, "invariant"); if (leakp) { - entry.set_leakp(); + entry->set_leakp(); + } else if (class_unload) { + entry->set_unloading(); } - return entry.id(); + return entry->id(); +} + +traceid JfrSymbolTable::mark(unsigned hash, const char* str, bool leakp, bool class_unload /* false */, bool previous_epoch /* false */) { + Impl* const table = previous_epoch ? previous_epoch_table() : this_epoch_table(); + assert(table != nullptr, "invariant"); + return table->mark(hash, str, leakp, class_unload); } /* @@ -241,40 +308,47 @@ traceid JfrSymbolTable::mark(uintptr_t hash, const char* str, bool leakp) { * * Caller needs ResourceMark. */ -traceid JfrSymbolTable::mark_hidden_klass_name(const Klass* k, bool leakp) { +inline traceid JfrSymbolTable::Impl::mark_hidden_klass_name(const Klass* k, bool leakp, bool class_unload /* false */) { assert(k != nullptr, "invariant"); assert(k->is_hidden(), "invariant"); - const uintptr_t hash = k->name()->identity_hash(); - return mark(hash, k->external_name(), leakp); + return mark(k->name()->identity_hash(), k->external_name(), leakp, class_unload); } -traceid JfrSymbolTable::mark(const Klass* k, bool leakp) { +traceid JfrSymbolTable::Impl::mark(const Klass* k, bool leakp, bool class_unload /* false */) { assert(k != nullptr, "invariant"); traceid symbol_id = 0; if (k->is_hidden()) { - symbol_id = mark_hidden_klass_name(k, leakp); + symbol_id = mark_hidden_klass_name(k, leakp, class_unload); } else { Symbol* const sym = k->name(); if (sym != nullptr) { - symbol_id = mark(sym, leakp); + symbol_id = mark(sym, leakp, class_unload); } } assert(symbol_id > 0, "a symbol handler must mark the symbol for writing"); return symbol_id; } -template -traceid JfrSymbolTable::add_impl(const T* sym) { - assert(sym != nullptr, "invariant"); - assert(_instance != nullptr, "invariant"); - assert_locked_or_safepoint(ClassLoaderDataGraph_lock); - return instance().mark(sym); +traceid JfrSymbolTable::mark(const Klass* k, bool leakp, bool class_unload /* false */, bool previous_epoch /* false */) { + Impl* const table = previous_epoch ? previous_epoch_table() : this_epoch_table(); + assert(table != nullptr, "invariant"); + return table->mark(k, leakp, class_unload); } -traceid JfrSymbolTable::add(const Symbol* sym) { - return add_impl(sym); +inline traceid JfrSymbolTable::Impl::add(const Symbol* sym) { + assert(sym != nullptr, "invariant"); + return _symbols->lookup_put(sym->identity_hash(), sym)->id(); +} + +traceid JfrSymbolTable::Impl::add(const char* str) { + assert(str != nullptr, "invariant"); + return _strings->lookup_put(string_hash(str), str)->id(); +} + +inline traceid JfrSymbolTable::add(const Symbol* sym) { + return this_epoch_table()->add(sym); } traceid JfrSymbolTable::add(const char* str) { - return add_impl(str); + return this_epoch_table()->add(str); } diff --git a/src/hotspot/share/jfr/support/jfrSymbolTable.hpp b/src/hotspot/share/jfr/support/jfrSymbolTable.hpp index 8cefa287c8a..d2ee6cd4bc1 100644 --- a/src/hotspot/share/jfr/support/jfrSymbolTable.hpp +++ b/src/hotspot/share/jfr/support/jfrSymbolTable.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, 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,32 +25,58 @@ #ifndef SHARE_JFR_SUPPORT_JFRSYMBOLTABLE_HPP #define SHARE_JFR_SUPPORT_JFRSYMBOLTABLE_HPP -#include "jfr/utilities/jfrHashtable.hpp" +#include "jfr/utilities/jfrAllocation.hpp" +#include "jfr/utilities/jfrConcurrentHashtable.hpp" #include "jfr/utilities/jfrTypes.hpp" template -class ListEntry : public JfrHashtableEntry { +class JfrSymbolTableEntry : public JfrConcurrentHashtableEntry { public: - ListEntry(uintptr_t hash, const T& data) : JfrHashtableEntry(hash, data), - _list_next(nullptr), _serialized(false), _unloading(false), _leakp(false) {} - const ListEntry* list_next() const { return _list_next; } - void reset() const { - _list_next = nullptr; _serialized = false; _unloading = false; _leakp = false; - } - void set_list_next(const ListEntry* next) const { _list_next = next; } + JfrSymbolTableEntry(unsigned hash, const T& data); bool is_serialized() const { return _serialized; } void set_serialized() const { _serialized = true; } bool is_unloading() const { return _unloading; } void set_unloading() const { _unloading = true; } bool is_leakp() const { return _leakp; } void set_leakp() const { _leakp = true; } + void reset() const { + _serialized = false; + _unloading = false; + _leakp = false; + } + + bool on_equals(const Symbol* sym) { + assert(sym != nullptr, "invariant"); + return sym == (const Symbol*)this->literal(); + } + + bool on_equals(const char* str); + private: - mutable const ListEntry* _list_next; mutable bool _serialized; mutable bool _unloading; mutable bool _leakp; }; +class JfrSymbolCallback : public JfrCHeapObj { + friend class JfrSymbolTable; + public: + typedef JfrConcurrentHashTableHost Symbols; + typedef JfrConcurrentHashTableHost Strings; + + void on_link(const Symbols::Entry* entry); + void on_unlink(const Symbols::Entry* entry); + void on_link(const Strings::Entry* entry); + void on_unlink(const Strings::Entry* entry); + + private: + traceid _id_counter; + + JfrSymbolCallback(); + template + void assign_id(const T* entry); +}; + /* * This table maps an oop/Symbol* or a char* to the Jfr type 'Symbol'. * @@ -58,88 +84,93 @@ class ListEntry : public JfrHashtableEntry { * which is represented in the binary format as a sequence of checkpoint events. * The returned id can be used as a foreign key, but please note that the id is * epoch-relative, and is therefore only valid in the current epoch / chunk. - * The table is cleared as part of rotation. - * - * Caller must ensure mutual exclusion by means of the ClassLoaderDataGraph_lock or by safepointing. */ -class JfrSymbolTable : public JfrCHeapObj { - template class, typename, size_t> - friend class HashTableHost; - typedef HashTableHost Symbols; - typedef HashTableHost Strings; +class JfrSymbolTable : public AllStatic { friend class JfrArtifactSet; + template class, typename, unsigned> + friend class JfrConcurrentHashTableHost; + friend class JfrRecorder; + friend class JfrRecorderService; + friend class JfrSymbolCallback; + + typedef JfrConcurrentHashTableHost Symbols; + typedef JfrConcurrentHashTableHost Strings; public: - typedef Symbols::HashEntry SymbolEntry; - typedef Strings::HashEntry StringEntry; + typedef Symbols::Entry SymbolEntry; + typedef Strings::Entry StringEntry; static traceid add(const Symbol* sym); static traceid add(const char* str); private: - Symbols* _symbols; - Strings* _strings; - const SymbolEntry* _symbol_list; - const StringEntry* _string_list; - const Symbol* _symbol_query; - const char* _string_query; - traceid _id_counter; - bool _class_unload; + class Impl : public JfrCHeapObj { + friend class JfrSymbolTable; + private: + Symbols* _symbols; + Strings* _strings; - JfrSymbolTable(); - ~JfrSymbolTable(); - static JfrSymbolTable* create(); + Impl(unsigned symbol_capacity = 0, unsigned string_capacity = 0); + ~Impl(); + + void clear(); + + traceid add(const Symbol* sym); + traceid add(const char* str); + + traceid mark(unsigned hash, const Symbol* sym, bool leakp, bool class_unload = false); + traceid mark(const Klass* k, bool leakp, bool class_unload = false); + traceid mark(const Symbol* sym, bool leakp = false, bool class_unload = false); + traceid mark(const char* str, bool leakp = false, bool class_unload = false); + traceid mark(unsigned hash, const char* str, bool leakp, bool class_unload = false); + traceid mark_hidden_klass_name(const Klass* k, bool leakp, bool class_unload = false); + + bool has_entries() const; + bool has_symbol_entries() const; + bool has_string_entries() const; + + unsigned symbols_capacity() const; + unsigned symbols_size() const; + unsigned strings_capacity() const; + unsigned strings_size() const; + + template + void iterate_symbols(Functor& functor); + + template + void iterate_strings(Functor& functor); + }; + + static Impl* _epoch_0; + static Impl* _epoch_1; + static StringEntry* _bootstrap; + + static bool create(); static void destroy(); - void clear(); - void increment_checkpoint_id(); - void set_class_unload(bool class_unload); + static Impl* this_epoch_table(); + static Impl* previous_epoch_table(); + static Impl* epoch_table_selector(u1 epoch); + static void set_this_epoch(Impl* table); + static void set_previous_epoch(Impl* table); - traceid mark(uintptr_t hash, const Symbol* sym, bool leakp); - traceid mark(const Klass* k, bool leakp); - traceid mark(const Symbol* sym, bool leakp = false); - traceid mark(const char* str, bool leakp = false); - traceid mark(uintptr_t hash, const char* str, bool leakp); - traceid mark_hidden_klass_name(const Klass* k, bool leakp); - traceid bootstrap_name(bool leakp); + static void clear_previous_epoch(); + static void allocate_next_epoch(); - bool has_entries() const { return has_symbol_entries() || has_string_entries(); } - bool has_symbol_entries() const { return _symbol_list != nullptr; } - bool has_string_entries() const { return _string_list != nullptr; } + static bool has_entries(bool previous_epoch = false); + static bool has_symbol_entries(bool previous_epoch = false); + static bool has_string_entries(bool previous_epoch = false); - // hashtable(s) callbacks - void on_link(const SymbolEntry* entry); - bool on_equals(uintptr_t hash, const SymbolEntry* entry); - void on_unlink(const SymbolEntry* entry); - void on_link(const StringEntry* entry); - bool on_equals(uintptr_t hash, const StringEntry* entry); - void on_unlink(const StringEntry* entry); - - template - static traceid add_impl(const T* sym); - - template - void assign_id(T* entry); + static traceid mark(const Klass* k, bool leakp, bool class_unload = false, bool previous_epoch = false); + static traceid mark(const Symbol* sym, bool leakp = false, bool class_unload = false, bool previous_epoch = false); + static traceid mark(unsigned hash, const char* str, bool leakp, bool class_unload = false, bool previous_epoch = false); + static traceid bootstrap_name(bool leakp); template - void iterate_symbols(Functor& functor) { - iterate(functor, _symbol_list); - } + static void iterate_symbols(Functor& functor, bool previous_epoch = false); template - void iterate_strings(Functor& functor) { - iterate(functor, _string_list); - } - - template - void iterate(Functor& functor, const T* list) { - const T* symbol = list; - while (symbol != nullptr) { - const T* next = symbol->list_next(); - functor(symbol); - symbol = next; - } - } + static void iterate_strings(Functor& functor, bool previous_epoch = false); }; #endif // SHARE_JFR_SUPPORT_JFRSYMBOLTABLE_HPP diff --git a/src/hotspot/share/jfr/support/jfrSymbolTable.inline.hpp b/src/hotspot/share/jfr/support/jfrSymbolTable.inline.hpp new file mode 100644 index 00000000000..9e7ac8c9d47 --- /dev/null +++ b/src/hotspot/share/jfr/support/jfrSymbolTable.inline.hpp @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2025, 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. + * + */ + +#ifndef SHARE_JFR_SUPPORT_JFRSYMBOLTABLE_INLINE_HPP +#define SHARE_JFR_SUPPORT_JFRSYMBOLTABLE_INLINE_HPP + +#include "jfr/support/jfrSymbolTable.hpp" + +#include "jfr/recorder/checkpoint/types/traceid/jfrTraceIdEpoch.hpp" +#include "jfr/utilities/jfrConcurrentHashtable.inline.hpp" + +inline JfrSymbolTable::Impl* JfrSymbolTable::epoch_table_selector(u1 epoch) { + return epoch == 0 ? _epoch_0 : _epoch_1; +} + +inline JfrSymbolTable::Impl* JfrSymbolTable::this_epoch_table() { + return epoch_table_selector(JfrTraceIdEpoch::current()); +} + +inline JfrSymbolTable::Impl* JfrSymbolTable::previous_epoch_table() { + return epoch_table_selector(JfrTraceIdEpoch::previous()); +} + +template +inline void JfrSymbolTable::Impl::iterate_symbols(Functor& functor) { + _symbols->iterate_entry(functor); +} + +template +inline void JfrSymbolTable::iterate_symbols(Functor& functor, bool previous_epoch /* false */) { + Impl* const table = previous_epoch ? previous_epoch_table() : this_epoch_table(); + assert(table != nullptr, "invariant"); + table->iterate_symbols(functor); +} + +template +inline void JfrSymbolTable::Impl::iterate_strings(Functor& functor) { + _strings->iterate_entry(functor); +} + +template +inline void JfrSymbolTable::iterate_strings(Functor& functor, bool previous_epoch /* false */) { + Impl* const table = previous_epoch ? previous_epoch_table() : this_epoch_table(); + assert(table != nullptr, "invariant"); + if (!functor(_bootstrap)) { + return; + } + table->iterate_strings(functor); +} + +#endif // SHARE_JFR_SUPPORT_JFRSYMBOLTABLE_INLINE_HPP diff --git a/src/hotspot/share/jfr/support/jfrTraceIdExtension.hpp b/src/hotspot/share/jfr/support/jfrTraceIdExtension.hpp index bb0e3e082fe..46b4d973ce4 100644 --- a/src/hotspot/share/jfr/support/jfrTraceIdExtension.hpp +++ b/src/hotspot/share/jfr/support/jfrTraceIdExtension.hpp @@ -42,7 +42,6 @@ #define ASSIGN_PRIMITIVE_CLASS_ID(data) JfrTraceId::assign_primitive_klass_id() #define REMOVE_ID(k) JfrTraceId::remove(k); #define REMOVE_METHOD_ID(method) JfrTraceId::remove(method); -#define RESTORE_ID(k) JfrTraceId::restore(k); static constexpr const uint16_t cleared_epoch_bits = 512 | 256; diff --git a/src/hotspot/share/jfr/utilities/jfrConcurrentHashtable.hpp b/src/hotspot/share/jfr/utilities/jfrConcurrentHashtable.hpp new file mode 100644 index 00000000000..5434023e636 --- /dev/null +++ b/src/hotspot/share/jfr/utilities/jfrConcurrentHashtable.hpp @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2025, 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. + * + */ + +#ifndef SHARE_JFR_UTILITIES_JFRCONCURRENTHASHTABLE_HPP +#define SHARE_JFR_UTILITIES_JFRCONCURRENTHASHTABLE_HPP + +#include "jfr/utilities/jfrLinkedList.hpp" +#include "memory/allocation.hpp" + +template class TableEntry> +class JfrConcurrentAscendingId { +private: + IdType _id; +public: + JfrConcurrentAscendingId() : _id(1) {} + // Callbacks. + void on_link(TableEntry* entry); + bool on_equals(unsigned hash, const TableEntry* entry); +}; + +template +class JfrConcurrentHashtableEntry : public CHeapObj { + template + friend class JfrLinkedList; + private: + typedef JfrConcurrentHashtableEntry Entry; + Entry* _next; + T _literal; // ref to item in table. + mutable IdType _id; + unsigned _hash; + + public: + JfrConcurrentHashtableEntry(unsigned hash, const T& data) : _next(nullptr), _literal(data), _id(0), _hash(hash) {} + unsigned hash() const { return _hash; } + T literal() const { return _literal; } + T* literal_addr() { return &_literal; } + void set_literal(T s) { _literal = s; } + void set_next(Entry* next) { _next = next; } + Entry* next() const { return _next; } + Entry** next_addr() { return &_next; } + IdType id() const { return _id; } + void set_id(IdType id) const { _id = id; } + T& value() const { return *const_cast(this)->literal_addr(); } + const T* value_addr() const { return const_cast(this)->literal_addr(); } +}; + +template class TableEntry> +class JfrConcurrentHashtable : public CHeapObj { + public: + typedef TableEntry Entry; + typedef JfrLinkedList Bucket; + + unsigned capacity() const { return _capacity; } + unsigned size() const; + + protected: + JfrConcurrentHashtable(unsigned size); + ~JfrConcurrentHashtable(); + + unsigned index(unsigned hash) const { + return hash & _mask; + } + + Bucket& bucket(unsigned idx) { return _buckets[idx]; } + Bucket* bucket_addr(unsigned idx) { return &_buckets[idx]; } + Entry* head(unsigned idx) { return bucket(idx).head(); } + + bool try_add(unsigned idx, Entry* entry, Entry* next); + + template + void iterate(Callback& cb); + + template + void iterate(unsigned idx, Callback& cb); + + template + static void iterate(Entry* entry, Callback& cb); + + void unlink_entry(Entry* entry); + + private: + Bucket* _buckets; + unsigned _capacity; + unsigned _mask; + unsigned _size; +}; + +template class TableEntry, + typename Callback = JfrConcurrentAscendingId, unsigned TABLE_CAPACITY = 1024> +class JfrConcurrentHashTableHost : public JfrConcurrentHashtable { + public: + typedef TableEntry Entry; + JfrConcurrentHashTableHost(unsigned initial_capacity = 0); + JfrConcurrentHashTableHost(Callback* cb, unsigned initial_capacity = 0); + ~JfrConcurrentHashTableHost(); + + // lookup entry, will put if not found + Entry* lookup_put(unsigned hash, const T& data); + + // id retrieval + IdType id(unsigned hash, const T& data); + + bool is_empty() const; + bool is_nonempty() const { return !is_empty(); } + + template + void iterate_value(Functor& f); + + template + void iterate_entry(Functor& f); + + private: + Callback* _callback; + + Entry* new_entry(unsigned hash, const T& data); +}; + +#endif // SHARE_JFR_UTILITIES_JFRCONCURRENTHASHTABLE_HPP diff --git a/src/hotspot/share/jfr/utilities/jfrConcurrentHashtable.inline.hpp b/src/hotspot/share/jfr/utilities/jfrConcurrentHashtable.inline.hpp new file mode 100644 index 00000000000..6d6908234a3 --- /dev/null +++ b/src/hotspot/share/jfr/utilities/jfrConcurrentHashtable.inline.hpp @@ -0,0 +1,254 @@ +/* + * Copyright (c) 2025, 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. + * + */ + +#ifndef SHARE_JFR_UTILITIES_JFRCONCURRENTHASHTABLE_INLINE_HPP +#define SHARE_JFR_UTILITIES_JFRCONCURRENTHASHTABLE_INLINE_HPP + +#include "jfr/utilities/jfrConcurrentHashtable.hpp" + +#include "jfr/utilities/jfrLinkedList.inline.hpp" +#include "memory/allocation.inline.hpp" +#include "nmt/memTracker.hpp" +#include "runtime/atomicAccess.hpp" +#include "utilities/debug.hpp" +#include "utilities/macros.hpp" + +template class TableEntry> +inline void JfrConcurrentAscendingId::on_link(TableEntry* entry) { + assert(entry != nullptr, "invariant"); + assert(entry->id() == 0, "invariant"); + entry->set_id(AtomicAccess::fetch_then_add(&_id, static_cast(1))); +} + +template class TableEntry> +inline bool JfrConcurrentAscendingId::on_equals(unsigned hash, const TableEntry* entry) { + assert(entry != nullptr, "invariant"); + assert(entry->hash() == hash, "invariant"); + return true; +} + +template class TableEntry> +inline JfrConcurrentHashtable::JfrConcurrentHashtable(unsigned initial_capacity) : + _buckets(nullptr), _capacity(initial_capacity), _mask(initial_capacity - 1), _size(0) { + assert(initial_capacity >= 2, "invariant"); + assert(is_power_of_2(initial_capacity), "invariant"); + _buckets = NEW_C_HEAP_ARRAY2(Bucket, initial_capacity, mtTracing, CURRENT_PC); + memset((void*)_buckets, 0, initial_capacity * sizeof(Bucket)); +} + +template class TableEntry> +inline JfrConcurrentHashtable::~JfrConcurrentHashtable() { + FREE_C_HEAP_ARRAY(Bucket, _buckets); +} + +template class TableEntry> +inline unsigned JfrConcurrentHashtable::size() const { + return AtomicAccess::load(&_size); +} + +template class TableEntry> +template +inline void JfrConcurrentHashtable::iterate(unsigned idx, Callback& cb) { + assert(idx < _capacity, "invariant"); + bucket(idx).iterate(cb); +} + +template class TableEntry> +template +inline void JfrConcurrentHashtable::iterate(Callback& cb) { + for (unsigned i = 0; i < _capacity; ++i) { + iterate(i, cb); + } +} + +template class TableEntry> +template +inline void JfrConcurrentHashtable::iterate(TableEntry* entry, Callback& cb) { + Bucket::iterate(entry, cb); +} + +template class TableEntry> +inline bool JfrConcurrentHashtable::try_add(unsigned idx, TableEntry* entry, TableEntry* next) { + assert(entry != nullptr, "invariant"); + entry->set_next(next); + const bool added = bucket(idx).try_add(entry, next); + if (added) { + AtomicAccess::inc(&_size); + } + return added; +} + +template class TableEntry> +inline void JfrConcurrentHashtable::unlink_entry(TableEntry* entry) { + AtomicAccess::dec(&_size); +} + +template class TableEntry, typename Callback, unsigned TABLE_CAPACITY> +inline JfrConcurrentHashTableHost::JfrConcurrentHashTableHost(unsigned initial_capacity /* 0 */) : + JfrConcurrentHashtable(initial_capacity == 0 ? TABLE_CAPACITY : initial_capacity), _callback(new Callback()) {} + +template class TableEntry, typename Callback, unsigned TABLE_CAPACITY> +inline JfrConcurrentHashTableHost::JfrConcurrentHashTableHost(Callback* cb, unsigned initial_capacity /* 0 */) : + JfrConcurrentHashtable(initial_capacity == 0 ? TABLE_CAPACITY : initial_capacity), _callback(cb) {} + +template class TableEntry, typename Callback, unsigned TABLE_CAPACITY> +inline bool JfrConcurrentHashTableHost::is_empty() const { + return this->size() == 0; +} + +template class TableEntry, typename Callback, unsigned TABLE_CAPACITY> +inline TableEntry* JfrConcurrentHashTableHost::new_entry(unsigned hash, const T& data) { + Entry* const entry = new Entry(hash, data); + assert(entry != nullptr, "invariant"); + assert(0 == entry->id(), "invariant"); + _callback->on_link(entry); + assert(0 != entry->id(), "invariant"); + return entry; +} + +template +class JfrConcurrentHashtableLookup { + private: + Callback* const _cb; + const T& _data; + Entry* _found; + unsigned _hash; + public: + JfrConcurrentHashtableLookup(unsigned hash, const T& data, Callback* cb) : _cb(cb), _data(data), _found(nullptr), _hash(hash) {} + + bool process(Entry* entry) { + assert(entry != nullptr, "invariant"); + if (entry->hash() == _hash && entry->on_equals(_data)) { + _found = entry; + return false; + } + return true; + } + + bool found() const { return _found != nullptr; } + Entry* result() const { return _found; } +}; + +template class TableEntry, typename Callback, unsigned TABLE_CAPACITY> +inline TableEntry* JfrConcurrentHashTableHost::lookup_put(unsigned hash, const T& data) { + JfrConcurrentHashtableLookup lookup(hash, data, _callback); + const unsigned idx = this->index(hash); + Entry* entry = nullptr; + while (true) { + assert(!lookup.found(), "invariant"); + Entry* next = this->head(idx); + if (next != nullptr) { + JfrConcurrentHashtable::iterate(next, lookup); + if (lookup.found()) { + if (entry != nullptr) { + _callback->on_unlink(entry); + delete entry; + } + entry = lookup.result(); + break; + } + } + if (entry == nullptr) { + entry = new_entry(hash, data); + } + assert(entry != nullptr, "invariant"); + if (this->try_add(idx, entry, next)) { + break; + } + // Concurrent insertion to this bucket. Retry. + } + assert(entry != nullptr, "invariant"); + return entry; +} + +// id retrieval +template class TableEntry, typename Callback, unsigned TABLE_CAPACITY> +inline IdType JfrConcurrentHashTableHost::id(unsigned hash, const T& data) { + assert(data != nullptr, "invariant"); + const Entry* const entry = lookup_put(hash, data); + assert(entry != nullptr, "invariant"); + assert(entry->id() > 0, "invariant"); + return entry->id(); +} + +template +class JfrConcurrentHashtableClear { + private: + Callback* const _cb; + public: + JfrConcurrentHashtableClear(Callback* cb) : _cb(cb) {} + + bool process(const Entry* entry) { + assert(entry != nullptr, "invariant"); + _cb->on_unlink(entry); + delete entry; + return true; + } +}; + +template class TableEntry, typename Callback, unsigned TABLE_CAPACITY> +inline JfrConcurrentHashTableHost::~JfrConcurrentHashTableHost() { + JfrConcurrentHashtableClear cls(_callback); + this->iterate(cls); +} + +template +class JfrConcurrentHashtableValueDelegator { + private: + Functor& _f; + public: + JfrConcurrentHashtableValueDelegator(Functor& f) : _f(f) {} + bool process(const Entry* entry) { + assert(entry != nullptr, "invariant"); + return _f(entry->value()); + } +}; + +template +class JfrConcurrentHashtableEntryDelegator { + private: + Functor& _f; + public: + JfrConcurrentHashtableEntryDelegator(Functor& f) : _f(f) {} + bool process(const Entry* entry) { + assert(entry != nullptr, "invariant"); + return _f(entry); + } +}; + +template class TableEntry, typename Callback, unsigned TABLE_CAPACITY> +template +inline void JfrConcurrentHashTableHost::iterate_value(Functor& f) { + JfrConcurrentHashtableValueDelegator delegator(f); + this->iterate(delegator); +} + +template class TableEntry, typename Callback, unsigned TABLE_CAPACITY> +template +inline void JfrConcurrentHashTableHost::iterate_entry(Functor& f) { + JfrConcurrentHashtableEntryDelegator delegator(f); + this->iterate(delegator); +} + +#endif // SHARE_JFR_UTILITIES_JFRCONCURRENTHASHTABLE_INLINE_HPP diff --git a/src/hotspot/share/jfr/utilities/jfrLinkedList.hpp b/src/hotspot/share/jfr/utilities/jfrLinkedList.hpp index 96e3acc0daa..a0d18bd383c 100644 --- a/src/hotspot/share/jfr/utilities/jfrLinkedList.hpp +++ b/src/hotspot/share/jfr/utilities/jfrLinkedList.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, 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,10 +43,13 @@ class JfrLinkedList : public AllocPolicy { bool is_empty() const; bool is_nonempty() const; void add(NodePtr node); + bool try_add(NodePtr node, NodePtr next); void add_list(NodePtr first); NodePtr remove(); template void iterate(Callback& cb); + template + static void iterate(NodePtr node, Callback& cb); NodePtr head() const; NodePtr excise(NodePtr prev, NodePtr node); bool in_list(const NodeType* node) const; diff --git a/src/hotspot/share/jfr/utilities/jfrLinkedList.inline.hpp b/src/hotspot/share/jfr/utilities/jfrLinkedList.inline.hpp index fed379672dc..f481caa6528 100644 --- a/src/hotspot/share/jfr/utilities/jfrLinkedList.inline.hpp +++ b/src/hotspot/share/jfr/utilities/jfrLinkedList.inline.hpp @@ -30,10 +30,10 @@ #include "runtime/atomicAccess.hpp" template -JfrLinkedList::JfrLinkedList() : _head(nullptr) {} +inline JfrLinkedList::JfrLinkedList() : _head(nullptr) {} template -bool JfrLinkedList::initialize() { +inline bool JfrLinkedList::initialize() { return true; } @@ -62,6 +62,13 @@ inline void JfrLinkedList::add(NodeType* node) { } while (AtomicAccess::cmpxchg(&_head, next, node) != next); } +template +inline bool JfrLinkedList::try_add(NodeType* node, NodeType* next) { + assert(node != nullptr, "invariant"); + assert(node->_next == next, "invariant"); + return head() == next && AtomicAccess::cmpxchg(&_head, next, node) == next; +} + template inline NodeType* JfrLinkedList::remove() { NodePtr node; @@ -76,19 +83,24 @@ inline NodeType* JfrLinkedList::remove() { template template -void JfrLinkedList::iterate(Callback& cb) { - NodePtr current = head(); - while (current != nullptr) { - NodePtr next = (NodePtr)current->_next; - if (!cb.process(current)) { +inline void JfrLinkedList::iterate(Callback& cb) { + JfrLinkedList::iterate(head(), cb); +} + +template +template +inline void JfrLinkedList::iterate(NodeType* node, Callback& cb) { + while (node != nullptr) { + NodePtr next = (NodePtr)node->_next; + if (!cb.process(node)) { return; } - current = next; + node = next; } } template -NodeType* JfrLinkedList::excise(NodeType* prev, NodeType* node) { +inline NodeType* JfrLinkedList::excise(NodeType* prev, NodeType* node) { NodePtr next = (NodePtr)node->_next; if (prev == nullptr) { prev = AtomicAccess::cmpxchg(&_head, node, next); @@ -106,7 +118,7 @@ NodeType* JfrLinkedList::excise(NodeType* prev, NodeType* } template -bool JfrLinkedList::in_list(const NodeType* node) const { +inline bool JfrLinkedList::in_list(const NodeType* node) const { assert(node != nullptr, "invariant"); const NodeType* current = head(); while (current != nullptr) { @@ -119,7 +131,7 @@ bool JfrLinkedList::in_list(const NodeType* node) const { } template -NodeType* JfrLinkedList::cut() { +inline NodeType* JfrLinkedList::cut() { NodePtr node; do { node = head(); @@ -128,7 +140,7 @@ NodeType* JfrLinkedList::cut() { } template -void JfrLinkedList::clear() { +inline void JfrLinkedList::clear() { cut(); } diff --git a/src/hotspot/share/oops/klass.cpp b/src/hotspot/share/oops/klass.cpp index b30ec2f4887..772541cdd10 100644 --- a/src/hotspot/share/oops/klass.cpp +++ b/src/hotspot/share/oops/klass.cpp @@ -57,6 +57,10 @@ #include "utilities/rotate_bits.hpp" #include "utilities/stack.inline.hpp" +#if INCLUDE_JFR +#include "jfr/jfr.hpp" +#endif + void Klass::set_java_mirror(Handle m) { assert(!m.is_null(), "New mirror should never be null."); assert(_java_mirror.is_empty(), "should only be used to initialize mirror"); @@ -862,7 +866,6 @@ void Klass::restore_unshareable_info(ClassLoaderData* loader_data, Handle protec assert(is_klass(), "ensure C++ vtable is restored"); assert(in_aot_cache(), "must be set"); assert(secondary_supers()->length() >= (int)population_count(_secondary_supers_bitmap), "must be"); - JFR_ONLY(RESTORE_ID(this);) if (log_is_enabled(Trace, aot, unshareable)) { ResourceMark rm(THREAD); oop class_loader = loader_data->class_loader(); @@ -876,10 +879,13 @@ void Klass::restore_unshareable_info(ClassLoaderData* loader_data, Handle protec if (class_loader_data() == nullptr) { set_class_loader_data(loader_data); } + // Add to class loader list first before creating the mirror // (same order as class file parsing) loader_data->add_class(this); + JFR_ONLY(Jfr::on_restoration(this, THREAD);) + Handle loader(THREAD, loader_data->class_loader()); ModuleEntry* module_entry = nullptr; Klass* k = this; diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/query/view.ini b/src/jdk.jfr/share/classes/jdk/jfr/internal/query/view.ini index 91decb1aa20..5d72a9f85dc 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/query/view.ini +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/query/view.ini @@ -110,6 +110,15 @@ table = "COLUMN 'Time', 'Requested By', 'Operation', 'Classes' GROUP BY redefinitionId ORDER BY duration DESC" +[jvm.classes-by-source] + label = "Classes by Source" + table = "COLUMN 'Source', 'Count' + FORMAT truncate-beginning, none + SELECT source, COUNT(*) AS C + FROM jdk.ClassDefine + GROUP BY source + ORDER BY C DESC" + [jvm.compiler-configuration] label = "Compiler Configuration" form = "SELECT LAST(threadCount), LAST(dynamicCompilerThreadCount), LAST(tieredCompilation) diff --git a/test/jdk/jdk/jfr/event/runtime/TestClassDefineEvent.java b/test/jdk/jdk/jfr/event/runtime/TestClassDefineEvent.java index b0522741a1e..74fb8e71e87 100644 --- a/test/jdk/jdk/jfr/event/runtime/TestClassDefineEvent.java +++ b/test/jdk/jdk/jfr/event/runtime/TestClassDefineEvent.java @@ -70,6 +70,8 @@ public final class TestClassDefineEvent { "Expected type " + cl.getClass().getName() + ", got type " + definingClassLoaderType.getName()); Asserts.assertEquals(cl.getName(), definingClassLoader.getName(), "Defining Class Loader should have the same name as the original class loader"); + Asserts.assertTrue(event.getString("source").startsWith("file:/"), "Invalid source location"); + Asserts.assertTrue(event.getString("source").endsWith(TEST_CLASS_NAME.substring(TEST_CLASS_NAME.lastIndexOf('.') + 1) + ".class"), "Invalid source location"); foundTestClasses = true; } } From aff25f135af20ec89c7a68f2a0a0ede7eb1491a6 Mon Sep 17 00:00:00 2001 From: Phil Race Date: Wed, 3 Dec 2025 18:20:31 +0000 Subject: [PATCH 146/706] 4690476: NegativeArraySizeException from AffineTransformOp with shear Reviewed-by: psadhukhan, jdv --- .../java/awt/image/AffineTransformOp.java | 82 ++++++++++++++++--- .../AffineTransformOp/AffineTxOpSizeTest.java | 68 +++++++++++++++ 2 files changed, 140 insertions(+), 10 deletions(-) create mode 100644 test/jdk/java/awt/image/AffineTransformOp/AffineTxOpSizeTest.java diff --git a/src/java.desktop/share/classes/java/awt/image/AffineTransformOp.java b/src/java.desktop/share/classes/java/awt/image/AffineTransformOp.java index 4c4179699f0..7a3ee8646a7 100644 --- a/src/java.desktop/share/classes/java/awt/image/AffineTransformOp.java +++ b/src/java.desktop/share/classes/java/awt/image/AffineTransformOp.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, 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 @@ -186,7 +186,13 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp { * {@code getBounds2D(BufferedImage)} * are not necessarily the same as the coordinates of the * {@code BufferedImage} returned by this method. If the - * upper-left corner coordinates of the rectangle are + * application provides a {@code dst} that is always returned. + * If {@code dst} is {@code null} and a destination {code BufferedImage} + * with the transformed dimensions cannot be created, the {@code src} + * dimensions will be substituted. + * + *

    + * If the upper-left corner coordinates of the rectangle are * negative then this part of the rectangle is not drawn. If the * upper-left corner coordinates of the rectangle are positive * then the filtered image is drawn at that position in the @@ -224,7 +230,7 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp { BufferedImage origDst = dst; if (dst == null) { - dst = createCompatibleDestImage(src, null); + dst = createCompatibleDestImageInt(src, null); dstCM = srcCM; origDst = dst; } @@ -272,7 +278,7 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp { } else { needToConvert = true; - dst = createCompatibleDestImage(src, null); + dst = createCompatibleDestImageInt(src, null); } } @@ -320,7 +326,12 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp { * {@code getBounds2D(Raster)} * are not necessarily the same as the coordinates of the * {@code WritableRaster} returned by this method. If the - * upper-left corner coordinates of rectangle are negative then + * application provides a {@code dst} that is always returned. + * If {@code dst} is {@code null} and a destination {code Raster} + * with the transformed dimensions cannot be created, the {@code src} + * dimensions will be substituted. + *

    + * If the upper-left corner coordinates of rectangle are negative then * this part of the rectangle is not drawn. If the coordinates * of the rectangle are positive then the filtered image is drawn at * that position in the destination {@code Raster}. @@ -342,7 +353,7 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp { throw new NullPointerException("src image is null"); } if (dst == null) { - dst = createCompatibleDestRaster(src); + dst = createCompatibleDestRasterInt(src); } if (src == dst) { throw new IllegalArgumentException("src image cannot be the "+ @@ -422,7 +433,7 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp { /** * Creates a zeroed destination image with the correct size and number of * bands. A {@code RasterFormatException} may be thrown if the - * transformed width or height is equal to 0. + * transformed width or height is less than or equal to 0, or too large. *

    * If {@code destCM} is null, * an appropriate {@code ColorModel} is used; this @@ -437,9 +448,36 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp { */ public BufferedImage createCompatibleDestImage (BufferedImage src, ColorModel destCM) { - BufferedImage image; Rectangle r = getBounds2D(src).getBounds(); + try { + return createCompatibleDestImage(src, destCM, r); + } catch (Exception e) { + if (e instanceof RasterFormatException) { + throw e; + } else { + RasterFormatException re = + new RasterFormatException("Could not create transformed image of size " + r); + re.initCause(e); + throw re; + } + } + } + private BufferedImage createCompatibleDestImageInt(BufferedImage src, + ColorModel destCM) { + + try { + return createCompatibleDestImage(src, destCM); + } catch (Exception e) { + return createCompatibleDestImage(src, destCM, src.getRaster().getBounds()); + } + } + + private BufferedImage createCompatibleDestImage(BufferedImage src, + ColorModel destCM, + Rectangle r) { + + BufferedImage image; // If r.x (or r.y) is < 0, then we want to only create an image // that is in the positive range. // If r.x (or r.y) is > 0, then we need to create an image that @@ -482,14 +520,38 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp { /** * Creates a zeroed destination {@code Raster} with the correct size * and number of bands. A {@code RasterFormatException} may be thrown - * if the transformed width or height is equal to 0. + * if the transformed width or height is less than or equal to 0, or too large. * * @param src The {@code Raster} to be transformed. * * @return The zeroed destination {@code Raster}. */ public WritableRaster createCompatibleDestRaster (Raster src) { - Rectangle2D r = getBounds2D(src); + Rectangle r = getBounds2D(src).getBounds(); + try { + return createCompatibleDestRaster(src, r); + } catch (Exception e) { + if (e instanceof RasterFormatException) { + throw e; + } else { + RasterFormatException re = + new RasterFormatException("Could not create transformed raster of size " + r); + re.initCause(e); + throw re; + } + } + } + + private WritableRaster createCompatibleDestRasterInt(Raster src) { + try { + return createCompatibleDestRaster(src); + } catch (Exception e) { + Rectangle r = src.getBounds(); + return createCompatibleDestRaster(src, r); + } + } + + private WritableRaster createCompatibleDestRaster (Raster src, Rectangle r) { return src.createCompatibleWritableRaster((int)r.getX(), (int)r.getY(), diff --git a/test/jdk/java/awt/image/AffineTransformOp/AffineTxOpSizeTest.java b/test/jdk/java/awt/image/AffineTransformOp/AffineTxOpSizeTest.java new file mode 100644 index 00000000000..86f0c1030d6 --- /dev/null +++ b/test/jdk/java/awt/image/AffineTransformOp/AffineTxOpSizeTest.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2017, 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 4690476 + * @summary Verify behaviour with transform which creates too large an image. + */ + +import java.awt.geom.AffineTransform; +import java.awt.image.AffineTransformOp; +import static java.awt.image.AffineTransformOp.*; +import java.awt.image.BufferedImage; +import java.awt.image.Raster; +import java.awt.image.RasterFormatException; + +public class AffineTxOpSizeTest { + + static final int W = 2552, H = 3300; + // This transform will require an approx 60_000 x 60_000 raster which is too large + static final AffineTransform AT = new AffineTransform(0.2, 23, 18, 0.24, -70.0, -90.0); + + public static void main(String[] args) { + BufferedImage src = new BufferedImage(W, H, BufferedImage.TYPE_INT_RGB); + testAOP(src, TYPE_BICUBIC); + testAOP(src, TYPE_BILINEAR); + testAOP(src, TYPE_NEAREST_NEIGHBOR); + } + + static void testAOP(BufferedImage src, int iType) { + AffineTransformOp aop = new AffineTransformOp(AT, iType); + System.out.println("Bounds=" + aop.getBounds2D(src)); + + aop.filter(src, null); + aop.filter(src.getRaster(), null); + try { + aop.createCompatibleDestImage(src, src.getColorModel()); + throw new RuntimeException("No exception for image"); + } catch (RasterFormatException e) { + } + try { + aop.createCompatibleDestRaster(src.getRaster()); + throw new RuntimeException("No exception for raster"); + } catch (RasterFormatException e) { + } + } + +} From 8a5db916aff1dc3eb37f25afbf0a633aa77baa20 Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Wed, 3 Dec 2025 19:58:28 +0000 Subject: [PATCH 147/706] 8171432: (fs) WindowsWatchService.Poller::run does not call ReadDirectoryChangesW after a ERROR_NOTIFY_ENUM_DIR Reviewed-by: alanb, djelinski --- .../sun/nio/fs/WindowsWatchService.java | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/java.base/windows/classes/sun/nio/fs/WindowsWatchService.java b/src/java.base/windows/classes/sun/nio/fs/WindowsWatchService.java index d051c833ee7..cd7cc38550c 100644 --- a/src/java.base/windows/classes/sun/nio/fs/WindowsWatchService.java +++ b/src/java.base/windows/classes/sun/nio/fs/WindowsWatchService.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, 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 @@ -610,23 +610,24 @@ class WindowsWatchService boolean criticalError = false; int errorCode = info.error(); int messageSize = info.bytesTransferred(); - if (errorCode == ERROR_NOTIFY_ENUM_DIR) { - // buffer overflow - key.signalEvent(StandardWatchEventKinds.OVERFLOW, null); - } else if (errorCode != 0 && errorCode != ERROR_MORE_DATA) { + if (errorCode != 0 && + errorCode != ERROR_MORE_DATA && + errorCode != ERROR_NOTIFY_ENUM_DIR) { // ReadDirectoryChangesW failed criticalError = true; } else { // ERROR_MORE_DATA is a warning about incomplete // data transfer over TCP/UDP stack. For the case - // [messageSize] is zero in the most of cases. + // [messageSize] is zero in most cases. if (messageSize > 0) { // process non-empty events. processEvents(key, messageSize); - } else if (errorCode == 0) { - // insufficient buffer size - // not described, but can happen. + } else if (errorCode == 0 || + errorCode == ERROR_NOTIFY_ENUM_DIR) { + // errorCode == 0: insufficient buffer size; + // not described, but can happen. + // errorCode == ERROR_NOTIFY_ENUM_DIR: buffer overflow key.signalEvent(StandardWatchEventKinds.OVERFLOW, null); } From ba777f6610fa3744d5f4bdfb87066b137ab543af Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Wed, 3 Dec 2025 19:58:53 +0000 Subject: [PATCH 148/706] 8372851: Modify java/io/File/GetXSpace.java to print path on failure of native call Reviewed-by: jpai, naoto --- test/jdk/java/io/File/GetXSpace.java | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/test/jdk/java/io/File/GetXSpace.java b/test/jdk/java/io/File/GetXSpace.java index e61880edb2c..96ce4ede1b2 100644 --- a/test/jdk/java/io/File/GetXSpace.java +++ b/test/jdk/java/io/File/GetXSpace.java @@ -106,7 +106,7 @@ public class GetXSpace { Space(String name) { this.name = name; long[] sizes = new long[4]; - if (Platform.isWindows() & isCDDrive(name)) { + if (Platform.isWindows() && isCDDrive(name)) { try { getCDDriveSpace(name, sizes); } catch (IOException e) { @@ -114,7 +114,7 @@ public class GetXSpace { throw new RuntimeException("can't get CDDrive sizes"); } } else { - if (getSpace0(name, sizes)) + if (getSpace(name, sizes)) System.err.println("WARNING: total space is estimated"); } this.size = sizes[0]; @@ -184,7 +184,7 @@ public class GetXSpace { out.format("%s (%d):%n", s.name(), s.size()); String fmt = " %-4s total = %12d free = %12d usable = %12d%n"; - String method = Platform.isWindows() & isCDDrive(s.name()) ? "getCDDriveSpace" : "getSpace0"; + String method = Platform.isWindows() && isCDDrive(s.name()) ? "getCDDriveSpace" : "getSpace"; out.format(fmt, method, s.total(), s.free(), s.available()); out.format(fmt, "getXSpace", ts, fs, us); @@ -336,7 +336,7 @@ public class GetXSpace { private static int testVolumes() { out.println("--- Testing volumes"); // Find all of the partitions on the machine and verify that the sizes - // returned by File::getXSpace are equivalent to those from getSpace0 or getCDDriveSpace + // returned by File::getXSpace are equivalent to those from getSpace or getCDDriveSpace ArrayList l; try { l = paths(); @@ -412,6 +412,19 @@ public class GetXSpace { private static native boolean isCDDrive(String root); + private static boolean getSpace(String root, long[] space) { + try { + return getSpace0(root, space); + } catch (RuntimeException e) { + File f = new File(root); + boolean exists = f.exists(); + boolean readable = f.canRead(); + System.err.printf("getSpace0 failed for %s (%s, %s)%n", + root, exists, readable); + throw e; + } + } + private static void getCDDriveSpace(String root, long[] sizes) throws IOException { String[] cmd = new String[] {"df", "-k", "-P", root}; From e534ee99327fed2263302a00061fb46fcdc6e302 Mon Sep 17 00:00:00 2001 From: Patricio Chilano Mateo Date: Wed, 3 Dec 2025 20:01:45 +0000 Subject: [PATCH 149/706] 8364343: Virtual Thread transition management needs to be independent of JVM TI Co-authored-by: Alan Bateman Reviewed-by: coleenp, dholmes, sspitsyn --- src/hotspot/share/classfile/javaClasses.cpp | 44 +- src/hotspot/share/classfile/javaClasses.hpp | 23 +- src/hotspot/share/classfile/vmIntrinsics.hpp | 8 +- src/hotspot/share/classfile/vmSymbols.hpp | 12 +- src/hotspot/share/code/aotCodeCache.cpp | 10 +- src/hotspot/share/include/jvm.h | 8 +- src/hotspot/share/jvmci/vmStructs_jvmci.cpp | 11 +- src/hotspot/share/opto/c2compiler.cpp | 8 +- src/hotspot/share/opto/library_call.cpp | 109 ++-- src/hotspot/share/opto/library_call.hpp | 6 +- src/hotspot/share/opto/runtime.cpp | 56 +-- src/hotspot/share/opto/runtime.hpp | 53 +- src/hotspot/share/prims/jvm.cpp | 70 +-- src/hotspot/share/prims/jvmtiEnv.cpp | 77 +-- src/hotspot/share/prims/jvmtiEnvBase.cpp | 30 +- src/hotspot/share/prims/jvmtiExport.cpp | 11 +- src/hotspot/share/prims/jvmtiExtensions.cpp | 5 +- src/hotspot/share/prims/jvmtiTagMap.cpp | 7 +- src/hotspot/share/prims/jvmtiThreadState.cpp | 473 ------------------ src/hotspot/share/prims/jvmtiThreadState.hpp | 61 --- src/hotspot/share/runtime/continuation.cpp | 63 +-- .../share/runtime/continuationFreezeThaw.cpp | 19 +- src/hotspot/share/runtime/handshake.cpp | 22 + src/hotspot/share/runtime/handshake.hpp | 1 + src/hotspot/share/runtime/javaThread.cpp | 39 +- src/hotspot/share/runtime/javaThread.hpp | 35 +- .../share/runtime/mountUnmountDisabler.cpp | 450 +++++++++++++++++ .../share/runtime/mountUnmountDisabler.hpp | 92 ++++ src/hotspot/share/runtime/mutexLocker.cpp | 8 +- src/hotspot/share/runtime/mutexLocker.hpp | 2 +- src/hotspot/share/runtime/sharedRuntime.cpp | 28 -- src/hotspot/share/runtime/sharedRuntime.hpp | 8 - .../share/runtime/stubDeclarations.hpp | 27 +- src/hotspot/share/runtime/stubInfo.cpp | 11 +- src/hotspot/share/runtime/stubInfo.hpp | 19 +- .../share/runtime/suspendResumeManager.cpp | 3 +- src/hotspot/share/services/threadService.cpp | 70 +-- .../classes/java/lang/VirtualThread.java | 39 +- .../share/native/libjava/VirtualThread.c | 8 +- .../DumpThreadsWhenParking.java | 159 ++++++ .../DumpThreadsWithEliminatedLock.java | 4 + 41 files changed, 1140 insertions(+), 1049 deletions(-) create mode 100644 src/hotspot/share/runtime/mountUnmountDisabler.cpp create mode 100644 src/hotspot/share/runtime/mountUnmountDisabler.hpp create mode 100644 test/jdk/com/sun/management/HotSpotDiagnosticMXBean/DumpThreadsWhenParking.java diff --git a/src/hotspot/share/classfile/javaClasses.cpp b/src/hotspot/share/classfile/javaClasses.cpp index ee80dbbc45c..614a0199beb 100644 --- a/src/hotspot/share/classfile/javaClasses.cpp +++ b/src/hotspot/share/classfile/javaClasses.cpp @@ -1684,8 +1684,8 @@ int java_lang_Thread::_name_offset; int java_lang_Thread::_contextClassLoader_offset; int java_lang_Thread::_eetop_offset; int java_lang_Thread::_jvmti_thread_state_offset; -int java_lang_Thread::_jvmti_VTMS_transition_disable_count_offset; -int java_lang_Thread::_jvmti_is_in_VTMS_transition_offset; +int java_lang_Thread::_vthread_transition_disable_count_offset; +int java_lang_Thread::_is_in_vthread_transition_offset; int java_lang_Thread::_interrupted_offset; int java_lang_Thread::_interruptLock_offset; int java_lang_Thread::_tid_offset; @@ -1745,34 +1745,34 @@ void java_lang_Thread::set_jvmti_thread_state(oop java_thread, JvmtiThreadState* java_thread->address_field_put(_jvmti_thread_state_offset, (address)state); } -int java_lang_Thread::VTMS_transition_disable_count(oop java_thread) { - return java_thread->int_field(_jvmti_VTMS_transition_disable_count_offset); +int java_lang_Thread::vthread_transition_disable_count(oop java_thread) { + jint* addr = java_thread->field_addr(_vthread_transition_disable_count_offset); + return AtomicAccess::load(addr); } -void java_lang_Thread::inc_VTMS_transition_disable_count(oop java_thread) { - assert(JvmtiVTMSTransition_lock->owned_by_self(), "Must be locked"); - int val = VTMS_transition_disable_count(java_thread); - java_thread->int_field_put(_jvmti_VTMS_transition_disable_count_offset, val + 1); +void java_lang_Thread::inc_vthread_transition_disable_count(oop java_thread) { + assert(VThreadTransition_lock->owned_by_self(), "Must be locked"); + jint* addr = java_thread->field_addr(_vthread_transition_disable_count_offset); + int val = AtomicAccess::load(addr); + AtomicAccess::store(addr, val + 1); } -void java_lang_Thread::dec_VTMS_transition_disable_count(oop java_thread) { - assert(JvmtiVTMSTransition_lock->owned_by_self(), "Must be locked"); - int val = VTMS_transition_disable_count(java_thread); - assert(val > 0, "VTMS_transition_disable_count should never be negative"); - java_thread->int_field_put(_jvmti_VTMS_transition_disable_count_offset, val - 1); +void java_lang_Thread::dec_vthread_transition_disable_count(oop java_thread) { + assert(VThreadTransition_lock->owned_by_self(), "Must be locked"); + jint* addr = java_thread->field_addr(_vthread_transition_disable_count_offset); + int val = AtomicAccess::load(addr); + AtomicAccess::store(addr, val - 1); } -bool java_lang_Thread::is_in_VTMS_transition(oop java_thread) { - return java_thread->bool_field_volatile(_jvmti_is_in_VTMS_transition_offset); +bool java_lang_Thread::is_in_vthread_transition(oop java_thread) { + jboolean* addr = java_thread->field_addr(_is_in_vthread_transition_offset); + return AtomicAccess::load(addr); } -void java_lang_Thread::set_is_in_VTMS_transition(oop java_thread, bool val) { - assert(is_in_VTMS_transition(java_thread) != val, "already %s transition", val ? "inside" : "outside"); - java_thread->bool_field_put_volatile(_jvmti_is_in_VTMS_transition_offset, val); -} - -int java_lang_Thread::is_in_VTMS_transition_offset() { - return _jvmti_is_in_VTMS_transition_offset; +void java_lang_Thread::set_is_in_vthread_transition(oop java_thread, bool val) { + assert(is_in_vthread_transition(java_thread) != val, "already %s transition", val ? "inside" : "outside"); + jboolean* addr = java_thread->field_addr(_is_in_vthread_transition_offset); + AtomicAccess::store(addr, (jboolean)val); } void java_lang_Thread::clear_scopedValueBindings(oop java_thread) { diff --git a/src/hotspot/share/classfile/javaClasses.hpp b/src/hotspot/share/classfile/javaClasses.hpp index 699dd39b887..33dc912404c 100644 --- a/src/hotspot/share/classfile/javaClasses.hpp +++ b/src/hotspot/share/classfile/javaClasses.hpp @@ -375,8 +375,8 @@ class java_lang_Class : AllStatic { #define THREAD_INJECTED_FIELDS(macro) \ macro(java_lang_Thread, jvmti_thread_state, intptr_signature, false) \ - macro(java_lang_Thread, jvmti_VTMS_transition_disable_count, int_signature, false) \ - macro(java_lang_Thread, jvmti_is_in_VTMS_transition, bool_signature, false) \ + macro(java_lang_Thread, vthread_transition_disable_count, int_signature, false) \ + macro(java_lang_Thread, is_in_vthread_transition, bool_signature, false) \ JFR_ONLY(macro(java_lang_Thread, jfr_epoch, short_signature, false)) class java_lang_Thread : AllStatic { @@ -390,8 +390,8 @@ class java_lang_Thread : AllStatic { static int _contextClassLoader_offset; static int _eetop_offset; static int _jvmti_thread_state_offset; - static int _jvmti_VTMS_transition_disable_count_offset; - static int _jvmti_is_in_VTMS_transition_offset; + static int _vthread_transition_disable_count_offset; + static int _is_in_vthread_transition_offset; static int _interrupted_offset; static int _interruptLock_offset; static int _tid_offset; @@ -444,12 +444,15 @@ class java_lang_Thread : AllStatic { static JvmtiThreadState* jvmti_thread_state(oop java_thread); static void set_jvmti_thread_state(oop java_thread, JvmtiThreadState* state); - static int VTMS_transition_disable_count(oop java_thread); - static void inc_VTMS_transition_disable_count(oop java_thread); - static void dec_VTMS_transition_disable_count(oop java_thread); - static bool is_in_VTMS_transition(oop java_thread); - static void set_is_in_VTMS_transition(oop java_thread, bool val); - static int is_in_VTMS_transition_offset(); + + static int vthread_transition_disable_count(oop java_thread); + static void inc_vthread_transition_disable_count(oop java_thread); + static void dec_vthread_transition_disable_count(oop java_thread); + static int vthread_transition_disable_count_offset() { return _vthread_transition_disable_count_offset; } + + static bool is_in_vthread_transition(oop java_thread); + static void set_is_in_vthread_transition(oop java_thread, bool val); + static int is_in_vthread_transition_offset() { return _is_in_vthread_transition_offset; } // Clear all scoped value bindings on error static void clear_scopedValueBindings(oop java_thread); diff --git a/src/hotspot/share/classfile/vmIntrinsics.hpp b/src/hotspot/share/classfile/vmIntrinsics.hpp index 0895418ef84..6f9c2326a45 100644 --- a/src/hotspot/share/classfile/vmIntrinsics.hpp +++ b/src/hotspot/share/classfile/vmIntrinsics.hpp @@ -649,10 +649,10 @@ class methodHandle; do_intrinsic(_Continuation_unpin, jdk_internal_vm_Continuation, unpin_name, void_method_signature, F_SN) \ \ /* java/lang/VirtualThread */ \ - do_intrinsic(_notifyJvmtiVThreadStart, java_lang_VirtualThread, notifyJvmtiStart_name, void_method_signature, F_RN) \ - do_intrinsic(_notifyJvmtiVThreadEnd, java_lang_VirtualThread, notifyJvmtiEnd_name, void_method_signature, F_RN) \ - do_intrinsic(_notifyJvmtiVThreadMount, java_lang_VirtualThread, notifyJvmtiMount_name, bool_void_signature, F_RN) \ - do_intrinsic(_notifyJvmtiVThreadUnmount, java_lang_VirtualThread, notifyJvmtiUnmount_name, bool_void_signature, F_RN) \ + do_intrinsic(_vthreadEndFirstTransition, java_lang_VirtualThread, endFirstTransition_name, void_method_signature, F_RN) \ + do_intrinsic(_vthreadStartFinalTransition, java_lang_VirtualThread, startFinalTransition_name, void_method_signature, F_RN) \ + do_intrinsic(_vthreadStartTransition, java_lang_VirtualThread, startTransition_name, bool_void_signature, F_RN) \ + do_intrinsic(_vthreadEndTransition, java_lang_VirtualThread, endTransition_name, bool_void_signature, F_RN) \ do_intrinsic(_notifyJvmtiVThreadDisableSuspend, java_lang_VirtualThread, notifyJvmtiDisableSuspend_name, bool_void_signature, F_SN) \ \ /* support for UnsafeConstants */ \ diff --git a/src/hotspot/share/classfile/vmSymbols.hpp b/src/hotspot/share/classfile/vmSymbols.hpp index d22700b8d1f..8388b98faae 100644 --- a/src/hotspot/share/classfile/vmSymbols.hpp +++ b/src/hotspot/share/classfile/vmSymbols.hpp @@ -395,10 +395,10 @@ class SerializeClosure; template(run_finalization_name, "runFinalization") \ template(dispatchUncaughtException_name, "dispatchUncaughtException") \ template(loadClass_name, "loadClass") \ - template(notifyJvmtiStart_name, "notifyJvmtiStart") \ - template(notifyJvmtiEnd_name, "notifyJvmtiEnd") \ - template(notifyJvmtiMount_name, "notifyJvmtiMount") \ - template(notifyJvmtiUnmount_name, "notifyJvmtiUnmount") \ + template(startTransition_name, "startTransition") \ + template(endTransition_name, "endTransition") \ + template(startFinalTransition_name, "startFinalTransition") \ + template(endFirstTransition_name, "endFirstTransition") \ template(notifyJvmtiDisableSuspend_name, "notifyJvmtiDisableSuspend") \ template(doYield_name, "doYield") \ template(enter_name, "enter") \ @@ -497,8 +497,8 @@ class SerializeClosure; template(java_lang_Boolean_signature, "Ljava/lang/Boolean;") \ template(url_code_signer_array_void_signature, "(Ljava/net/URL;[Ljava/security/CodeSigner;)V") \ template(jvmti_thread_state_name, "jvmti_thread_state") \ - template(jvmti_VTMS_transition_disable_count_name, "jvmti_VTMS_transition_disable_count") \ - template(jvmti_is_in_VTMS_transition_name, "jvmti_is_in_VTMS_transition") \ + template(vthread_transition_disable_count_name, "vthread_transition_disable_count") \ + template(is_in_vthread_transition_name, "is_in_vthread_transition") \ template(module_entry_name, "module_entry") \ template(resolved_references_name, "") \ template(init_lock_name, "") \ diff --git a/src/hotspot/share/code/aotCodeCache.cpp b/src/hotspot/share/code/aotCodeCache.cpp index 04776f4c16c..0314c5227d2 100644 --- a/src/hotspot/share/code/aotCodeCache.cpp +++ b/src/hotspot/share/code/aotCodeCache.cpp @@ -1346,18 +1346,16 @@ void AOTCodeAddressTable::init_extrs() { SET_ADDRESS(_extrs, OptoRuntime::multianewarray4_C); SET_ADDRESS(_extrs, OptoRuntime::multianewarray5_C); SET_ADDRESS(_extrs, OptoRuntime::multianewarrayN_C); -#if INCLUDE_JVMTI - SET_ADDRESS(_extrs, SharedRuntime::notify_jvmti_vthread_start); - SET_ADDRESS(_extrs, SharedRuntime::notify_jvmti_vthread_end); - SET_ADDRESS(_extrs, SharedRuntime::notify_jvmti_vthread_mount); - SET_ADDRESS(_extrs, SharedRuntime::notify_jvmti_vthread_unmount); -#endif SET_ADDRESS(_extrs, OptoRuntime::complete_monitor_locking_C); SET_ADDRESS(_extrs, OptoRuntime::monitor_notify_C); SET_ADDRESS(_extrs, OptoRuntime::monitor_notifyAll_C); SET_ADDRESS(_extrs, OptoRuntime::rethrow_C); SET_ADDRESS(_extrs, OptoRuntime::slow_arraycopy_C); SET_ADDRESS(_extrs, OptoRuntime::register_finalizer_C); + SET_ADDRESS(_extrs, OptoRuntime::vthread_end_first_transition_C); + SET_ADDRESS(_extrs, OptoRuntime::vthread_start_final_transition_C); + SET_ADDRESS(_extrs, OptoRuntime::vthread_start_transition_C); + SET_ADDRESS(_extrs, OptoRuntime::vthread_end_transition_C); #if defined(AARCH64) SET_ADDRESS(_extrs, JavaThread::verify_cross_modify_fence_failure); #endif // AARCH64 diff --git a/src/hotspot/share/include/jvm.h b/src/hotspot/share/include/jvm.h index ce76a95fda7..dccdcacef71 100644 --- a/src/hotspot/share/include/jvm.h +++ b/src/hotspot/share/include/jvm.h @@ -1100,16 +1100,16 @@ JVM_GetEnclosingMethodInfo(JNIEnv* env, jclass ofClass); * Virtual thread support. */ JNIEXPORT void JNICALL -JVM_VirtualThreadStart(JNIEnv* env, jobject vthread); +JVM_VirtualThreadEndFirstTransition(JNIEnv* env, jobject vthread); JNIEXPORT void JNICALL -JVM_VirtualThreadEnd(JNIEnv* env, jobject vthread); +JVM_VirtualThreadStartFinalTransition(JNIEnv* env, jobject vthread); JNIEXPORT void JNICALL -JVM_VirtualThreadMount(JNIEnv* env, jobject vthread, jboolean hide); +JVM_VirtualThreadStartTransition(JNIEnv* env, jobject vthread, jboolean is_mount); JNIEXPORT void JNICALL -JVM_VirtualThreadUnmount(JNIEnv* env, jobject vthread, jboolean hide); +JVM_VirtualThreadEndTransition(JNIEnv* env, jobject vthread, jboolean is_mount); JNIEXPORT void JNICALL JVM_VirtualThreadDisableSuspend(JNIEnv* env, jclass clazz, jboolean enter); diff --git a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp index 7ef16f6e32c..7f009eba5f1 100644 --- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp +++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp @@ -37,6 +37,7 @@ #include "runtime/continuationEntry.hpp" #include "runtime/deoptimization.hpp" #include "runtime/flags/jvmFlag.hpp" +#include "runtime/mountUnmountDisabler.hpp" #include "runtime/objectMonitor.hpp" #include "runtime/osThread.hpp" #include "runtime/sharedRuntime.hpp" @@ -259,13 +260,13 @@ nonstatic_field(JavaThread, _om_cache, OMCache) \ nonstatic_field(JavaThread, _cont_entry, ContinuationEntry*) \ nonstatic_field(JavaThread, _unlocked_inflated_monitor, ObjectMonitor*) \ - JVMTI_ONLY(nonstatic_field(JavaThread, _is_in_VTMS_transition, bool)) \ + nonstatic_field(JavaThread, _is_in_vthread_transition, bool) \ JVMTI_ONLY(nonstatic_field(JavaThread, _is_disable_suspend, bool)) \ \ nonstatic_field(ContinuationEntry, _pin_count, uint32_t) \ nonstatic_field(LockStack, _top, uint32_t) \ \ - JVMTI_ONLY(static_field(JvmtiVTMSTransitionDisabler, _VTMS_notify_jvmti_events, bool)) \ + static_field(MountUnmountDisabler, _notify_jvmti_events, bool) \ \ static_field(java_lang_Class, _klass_offset, int) \ static_field(java_lang_Class, _array_klass_offset, int) \ @@ -435,7 +436,7 @@ JFR_ONLY(nonstatic_field(Thread, _jfr_thread_local, JfrThreadLocal)) \ \ static_field(java_lang_Thread, _tid_offset, int) \ - static_field(java_lang_Thread, _jvmti_is_in_VTMS_transition_offset, int) \ + static_field(java_lang_Thread, _is_in_vthread_transition_offset, int) \ JFR_ONLY(static_field(java_lang_Thread, _jfr_epoch_offset, int)) \ \ JFR_ONLY(nonstatic_field(JfrThreadLocal, _vthread_id, traceid)) \ @@ -877,10 +878,6 @@ declare_function(SharedRuntime::enable_stack_reserved_zone) \ declare_function(SharedRuntime::frem) \ declare_function(SharedRuntime::drem) \ - JVMTI_ONLY(declare_function(SharedRuntime::notify_jvmti_vthread_start)) \ - JVMTI_ONLY(declare_function(SharedRuntime::notify_jvmti_vthread_end)) \ - JVMTI_ONLY(declare_function(SharedRuntime::notify_jvmti_vthread_mount)) \ - JVMTI_ONLY(declare_function(SharedRuntime::notify_jvmti_vthread_unmount)) \ \ declare_function(os::dll_load) \ declare_function(os::dll_lookup) \ diff --git a/src/hotspot/share/opto/c2compiler.cpp b/src/hotspot/share/opto/c2compiler.cpp index acc28964627..ead1b78cdea 100644 --- a/src/hotspot/share/opto/c2compiler.cpp +++ b/src/hotspot/share/opto/c2compiler.cpp @@ -859,11 +859,11 @@ bool C2Compiler::is_intrinsic_supported(vmIntrinsics::ID id) { case vmIntrinsics::_VectorBinaryLibOp: return EnableVectorSupport && Matcher::supports_vector_calling_convention(); case vmIntrinsics::_blackhole: + case vmIntrinsics::_vthreadEndFirstTransition: + case vmIntrinsics::_vthreadStartFinalTransition: + case vmIntrinsics::_vthreadStartTransition: + case vmIntrinsics::_vthreadEndTransition: #if INCLUDE_JVMTI - case vmIntrinsics::_notifyJvmtiVThreadStart: - case vmIntrinsics::_notifyJvmtiVThreadEnd: - case vmIntrinsics::_notifyJvmtiVThreadMount: - case vmIntrinsics::_notifyJvmtiVThreadUnmount: case vmIntrinsics::_notifyJvmtiVThreadDisableSuspend: #endif break; diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index dc53cb08396..6d4a9104580 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -55,6 +55,7 @@ #include "prims/jvmtiThreadState.hpp" #include "prims/unsafe.hpp" #include "runtime/jniHandles.inline.hpp" +#include "runtime/mountUnmountDisabler.hpp" #include "runtime/objectMonitor.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/stubRoutines.hpp" @@ -479,15 +480,15 @@ bool LibraryCallKit::try_to_inline(int predicate) { case vmIntrinsics::_Continuation_pin: return inline_native_Continuation_pinning(false); case vmIntrinsics::_Continuation_unpin: return inline_native_Continuation_pinning(true); + case vmIntrinsics::_vthreadEndFirstTransition: return inline_native_vthread_end_transition(CAST_FROM_FN_PTR(address, OptoRuntime::vthread_end_first_transition_Java()), + "endFirstTransition", true); + case vmIntrinsics::_vthreadStartFinalTransition: return inline_native_vthread_start_transition(CAST_FROM_FN_PTR(address, OptoRuntime::vthread_start_final_transition_Java()), + "startFinalTransition", true); + case vmIntrinsics::_vthreadStartTransition: return inline_native_vthread_start_transition(CAST_FROM_FN_PTR(address, OptoRuntime::vthread_start_transition_Java()), + "startTransition", false); + case vmIntrinsics::_vthreadEndTransition: return inline_native_vthread_end_transition(CAST_FROM_FN_PTR(address, OptoRuntime::vthread_end_transition_Java()), + "endTransition", false); #if INCLUDE_JVMTI - case vmIntrinsics::_notifyJvmtiVThreadStart: return inline_native_notify_jvmti_funcs(CAST_FROM_FN_PTR(address, OptoRuntime::notify_jvmti_vthread_start()), - "notifyJvmtiStart", true, false); - case vmIntrinsics::_notifyJvmtiVThreadEnd: return inline_native_notify_jvmti_funcs(CAST_FROM_FN_PTR(address, OptoRuntime::notify_jvmti_vthread_end()), - "notifyJvmtiEnd", false, true); - case vmIntrinsics::_notifyJvmtiVThreadMount: return inline_native_notify_jvmti_funcs(CAST_FROM_FN_PTR(address, OptoRuntime::notify_jvmti_vthread_mount()), - "notifyJvmtiMount", false, false); - case vmIntrinsics::_notifyJvmtiVThreadUnmount: return inline_native_notify_jvmti_funcs(CAST_FROM_FN_PTR(address, OptoRuntime::notify_jvmti_vthread_unmount()), - "notifyJvmtiUnmount", false, false); case vmIntrinsics::_notifyJvmtiVThreadDisableSuspend: return inline_native_notify_jvmti_sync(); #endif @@ -3042,46 +3043,80 @@ bool LibraryCallKit::inline_native_time_funcs(address funcAddr, const char* func return true; } - -#if INCLUDE_JVMTI - -// When notifications are disabled then just update the VTMS transition bit and return. -// Otherwise, the bit is updated in the given function call implementing JVMTI notification protocol. -bool LibraryCallKit::inline_native_notify_jvmti_funcs(address funcAddr, const char* funcName, bool is_start, bool is_end) { - if (!DoJVMTIVirtualThreadTransitions) { - return true; - } +//--------------------inline_native_vthread_start_transition-------------------- +// inline void startTransition(boolean is_mount); +// inline void startFinalTransition(); +// Pseudocode of implementation: +// +// java_lang_Thread::set_is_in_vthread_transition(vthread, true); +// carrier->set_is_in_vthread_transition(true); +// OrderAccess::storeload(); +// int disable_requests = java_lang_Thread::vthread_transition_disable_count(vthread) +// + global_vthread_transition_disable_count(); +// if (disable_requests > 0) { +// slow path: runtime call +// } +bool LibraryCallKit::inline_native_vthread_start_transition(address funcAddr, const char* funcName, bool is_final_transition) { Node* vt_oop = _gvn.transform(must_be_not_null(argument(0), true)); // VirtualThread this argument IdealKit ideal(this); - Node* ONE = ideal.ConI(1); - Node* hide = is_start ? ideal.ConI(0) : (is_end ? ideal.ConI(1) : _gvn.transform(argument(1))); - Node* addr = makecon(TypeRawPtr::make((address)&JvmtiVTMSTransitionDisabler::_VTMS_notify_jvmti_events)); - Node* notify_jvmti_enabled = ideal.load(ideal.ctrl(), addr, TypeInt::BOOL, T_BOOLEAN, Compile::AliasIdxRaw); + Node* thread = ideal.thread(); + Node* jt_addr = basic_plus_adr(thread, in_bytes(JavaThread::is_in_vthread_transition_offset())); + Node* vt_addr = basic_plus_adr(vt_oop, java_lang_Thread::is_in_vthread_transition_offset()); + access_store_at(nullptr, jt_addr, _gvn.type(jt_addr)->is_ptr(), ideal.ConI(1), TypeInt::BOOL, T_BOOLEAN, IN_NATIVE | MO_UNORDERED); + access_store_at(nullptr, vt_addr, _gvn.type(vt_addr)->is_ptr(), ideal.ConI(1), TypeInt::BOOL, T_BOOLEAN, IN_NATIVE | MO_UNORDERED); + insert_mem_bar(Op_MemBarVolatile); + ideal.sync_kit(this); - ideal.if_then(notify_jvmti_enabled, BoolTest::eq, ONE); { + Node* global_disable_addr = makecon(TypeRawPtr::make((address)MountUnmountDisabler::global_vthread_transition_disable_count_address())); + Node* global_disable = ideal.load(ideal.ctrl(), global_disable_addr, TypeInt::INT, T_INT, Compile::AliasIdxRaw, true /*require_atomic_access*/); + Node* vt_disable_addr = basic_plus_adr(vt_oop, java_lang_Thread::vthread_transition_disable_count_offset()); + Node* vt_disable = ideal.load(ideal.ctrl(), vt_disable_addr, TypeInt::INT, T_INT, Compile::AliasIdxRaw, true /*require_atomic_access*/); + Node* disabled = _gvn.transform(new AddINode(global_disable, vt_disable)); + + ideal.if_then(disabled, BoolTest::ne, ideal.ConI(0)); { sync_kit(ideal); - // if notifyJvmti enabled then make a call to the given SharedRuntime function - const TypeFunc* tf = OptoRuntime::notify_jvmti_vthread_Type(); - make_runtime_call(RC_NO_LEAF, tf, funcAddr, funcName, TypePtr::BOTTOM, vt_oop, hide); + Node* is_mount = is_final_transition ? ideal.ConI(0) : _gvn.transform(argument(1)); + const TypeFunc* tf = OptoRuntime::vthread_transition_Type(); + make_runtime_call(RC_NO_LEAF, tf, funcAddr, funcName, TypePtr::BOTTOM, vt_oop, is_mount); ideal.sync_kit(this); - } ideal.else_(); { - // set hide value to the VTMS transition bit in current JavaThread and VirtualThread object - Node* thread = ideal.thread(); - Node* jt_addr = basic_plus_adr(thread, in_bytes(JavaThread::is_in_VTMS_transition_offset())); - Node* vt_addr = basic_plus_adr(vt_oop, java_lang_Thread::is_in_VTMS_transition_offset()); + } + ideal.end_if(); - sync_kit(ideal); - access_store_at(nullptr, jt_addr, _gvn.type(jt_addr)->is_ptr(), hide, _gvn.type(hide), T_BOOLEAN, IN_NATIVE | MO_UNORDERED); - access_store_at(nullptr, vt_addr, _gvn.type(vt_addr)->is_ptr(), hide, _gvn.type(hide), T_BOOLEAN, IN_NATIVE | MO_UNORDERED); - - ideal.sync_kit(this); - } ideal.end_if(); final_sync(ideal); - return true; } +bool LibraryCallKit::inline_native_vthread_end_transition(address funcAddr, const char* funcName, bool is_first_transition) { + Node* vt_oop = _gvn.transform(must_be_not_null(argument(0), true)); // VirtualThread this argument + IdealKit ideal(this); + + Node* _notify_jvmti_addr = makecon(TypeRawPtr::make((address)MountUnmountDisabler::notify_jvmti_events_address())); + Node* _notify_jvmti = ideal.load(ideal.ctrl(), _notify_jvmti_addr, TypeInt::BOOL, T_BOOLEAN, Compile::AliasIdxRaw); + + ideal.if_then(_notify_jvmti, BoolTest::eq, ideal.ConI(1)); { + sync_kit(ideal); + Node* is_mount = is_first_transition ? ideal.ConI(1) : _gvn.transform(argument(1)); + const TypeFunc* tf = OptoRuntime::vthread_transition_Type(); + make_runtime_call(RC_NO_LEAF, tf, funcAddr, funcName, TypePtr::BOTTOM, vt_oop, is_mount); + ideal.sync_kit(this); + } ideal.else_(); { + Node* thread = ideal.thread(); + Node* jt_addr = basic_plus_adr(thread, in_bytes(JavaThread::is_in_vthread_transition_offset())); + Node* vt_addr = basic_plus_adr(vt_oop, java_lang_Thread::is_in_vthread_transition_offset()); + + sync_kit(ideal); + access_store_at(nullptr, jt_addr, _gvn.type(jt_addr)->is_ptr(), ideal.ConI(0), TypeInt::BOOL, T_BOOLEAN, IN_NATIVE | MO_UNORDERED); + access_store_at(nullptr, vt_addr, _gvn.type(vt_addr)->is_ptr(), ideal.ConI(0), TypeInt::BOOL, T_BOOLEAN, IN_NATIVE | MO_UNORDERED); + ideal.sync_kit(this); + } ideal.end_if(); + + final_sync(ideal); + return true; +} + +#if INCLUDE_JVMTI + // Always update the is_disable_suspend bit. bool LibraryCallKit::inline_native_notify_jvmti_sync() { if (!DoJVMTIVirtualThreadTransitions) { diff --git a/src/hotspot/share/opto/library_call.hpp b/src/hotspot/share/opto/library_call.hpp index 7dbb57c1e5c..bfe29814dec 100644 --- a/src/hotspot/share/opto/library_call.hpp +++ b/src/hotspot/share/opto/library_call.hpp @@ -275,9 +275,11 @@ class LibraryCallKit : public GraphKit { bool inline_native_Continuation_pinning(bool unpin); bool inline_native_time_funcs(address method, const char* funcName); + + bool inline_native_vthread_start_transition(address funcAddr, const char* funcName, bool is_final_transition); + bool inline_native_vthread_end_transition(address funcAddr, const char* funcName, bool is_first_transition); + #if INCLUDE_JVMTI - bool inline_native_notify_jvmti_funcs(address funcAddr, const char* funcName, bool is_start, bool is_end); - bool inline_native_notify_jvmti_hide(); bool inline_native_notify_jvmti_sync(); #endif diff --git a/src/hotspot/share/opto/runtime.cpp b/src/hotspot/share/opto/runtime.cpp index 32acbe57951..6dbbfb0a130 100644 --- a/src/hotspot/share/opto/runtime.cpp +++ b/src/hotspot/share/opto/runtime.cpp @@ -66,6 +66,7 @@ #include "runtime/handles.inline.hpp" #include "runtime/interfaceSupport.inline.hpp" #include "runtime/javaCalls.hpp" +#include "runtime/mountUnmountDisabler.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/signature.hpp" #include "runtime/stackWatermarkSet.hpp" @@ -92,12 +93,9 @@ #define C2_STUB_FIELD_NAME(name) _ ## name ## _Java #define C2_STUB_FIELD_DEFINE(name, f, t, r) \ address OptoRuntime:: C2_STUB_FIELD_NAME(name) = nullptr; -#define C2_JVMTI_STUB_FIELD_DEFINE(name) \ - address OptoRuntime:: STUB_FIELD_NAME(name) = nullptr; -C2_STUBS_DO(C2_BLOB_FIELD_DEFINE, C2_STUB_FIELD_DEFINE, C2_JVMTI_STUB_FIELD_DEFINE) +C2_STUBS_DO(C2_BLOB_FIELD_DEFINE, C2_STUB_FIELD_DEFINE) #undef C2_BLOB_FIELD_DEFINE #undef C2_STUB_FIELD_DEFINE -#undef C2_JVMTI_STUB_FIELD_DEFINE // This should be called in an assertion at the start of OptoRuntime routines // which are entered from compiled code (all of them) @@ -153,23 +151,9 @@ static bool check_compiled_frame(JavaThread* thread) { pass_retpc); \ if (C2_STUB_FIELD_NAME(name) == nullptr) { return false; } \ -#define C2_JVMTI_STUB_C_FUNC(name) CAST_FROM_FN_PTR(address, SharedRuntime::name) - -#define GEN_C2_JVMTI_STUB(name) \ - STUB_FIELD_NAME(name) = \ - generate_stub(env, \ - notify_jvmti_vthread_Type, \ - C2_JVMTI_STUB_C_FUNC(name), \ - C2_STUB_NAME(name), \ - C2_STUB_ID(name), \ - 0, \ - true, \ - false); \ - if (STUB_FIELD_NAME(name) == nullptr) { return false; } \ - bool OptoRuntime::generate(ciEnv* env) { - C2_STUBS_DO(GEN_C2_BLOB, GEN_C2_STUB, GEN_C2_JVMTI_STUB) + C2_STUBS_DO(GEN_C2_BLOB, GEN_C2_STUB) return true; } @@ -182,8 +166,6 @@ bool OptoRuntime::generate(ciEnv* env) { #undef C2_STUB_NAME #undef GEN_C2_STUB -#undef C2_JVMTI_STUB_C_FUNC -#undef GEN_C2_JVMTI_STUB // #undef gen const TypeFunc* OptoRuntime::_new_instance_Type = nullptr; @@ -257,12 +239,10 @@ const TypeFunc* OptoRuntime::_updateBytesCRC32C_Type = nullptr; const TypeFunc* OptoRuntime::_updateBytesAdler32_Type = nullptr; const TypeFunc* OptoRuntime::_osr_end_Type = nullptr; const TypeFunc* OptoRuntime::_register_finalizer_Type = nullptr; +const TypeFunc* OptoRuntime::_vthread_transition_Type = nullptr; #if INCLUDE_JFR const TypeFunc* OptoRuntime::_class_id_load_barrier_Type = nullptr; #endif // INCLUDE_JFR -#if INCLUDE_JVMTI -const TypeFunc* OptoRuntime::_notify_jvmti_vthread_Type = nullptr; -#endif // INCLUDE_JVMTI const TypeFunc* OptoRuntime::_dtrace_method_entry_exit_Type = nullptr; const TypeFunc* OptoRuntime::_dtrace_object_alloc_Type = nullptr; @@ -572,6 +552,26 @@ JRT_BLOCK_ENTRY(void, OptoRuntime::monitor_notifyAll_C(oopDesc* obj, JavaThread* JRT_BLOCK_END; JRT_END +JRT_ENTRY(void, OptoRuntime::vthread_end_first_transition_C(oopDesc* vt, jboolean is_mount, JavaThread* current)) + MountUnmountDisabler::end_transition(current, vt, true /*is_mount*/, true /*is_thread_start*/); +JRT_END + +JRT_ENTRY(void, OptoRuntime::vthread_start_final_transition_C(oopDesc* vt, jboolean is_mount, JavaThread* current)) + java_lang_Thread::set_is_in_vthread_transition(vt, false); + current->set_is_in_vthread_transition(false); + MountUnmountDisabler::start_transition(current, vt, false /*is_mount */, true /*is_thread_end*/); +JRT_END + +JRT_ENTRY(void, OptoRuntime::vthread_start_transition_C(oopDesc* vt, jboolean is_mount, JavaThread* current)) + java_lang_Thread::set_is_in_vthread_transition(vt, false); + current->set_is_in_vthread_transition(false); + MountUnmountDisabler::start_transition(current, vt, is_mount, false /*is_thread_end*/); +JRT_END + +JRT_ENTRY(void, OptoRuntime::vthread_end_transition_C(oopDesc* vt, jboolean is_mount, JavaThread* current)) + MountUnmountDisabler::end_transition(current, vt, is_mount, false /*is_thread_start*/); +JRT_END + static const TypeFunc* make_new_instance_Type() { // create input type (domain) const Type **fields = TypeTuple::fields(1); @@ -587,8 +587,7 @@ static const TypeFunc* make_new_instance_Type() { return TypeFunc::make(domain, range); } -#if INCLUDE_JVMTI -static const TypeFunc* make_notify_jvmti_vthread_Type() { +static const TypeFunc* make_vthread_transition_Type() { // create input type (domain) const Type **fields = TypeTuple::fields(2); fields[TypeFunc::Parms+0] = TypeInstPtr::NOTNULL; // VirtualThread oop @@ -602,7 +601,6 @@ static const TypeFunc* make_notify_jvmti_vthread_Type() { return TypeFunc::make(domain,range); } -#endif static const TypeFunc* make_athrow_Type() { // create input type (domain) @@ -2336,12 +2334,10 @@ void OptoRuntime::initialize_types() { _updateBytesAdler32_Type = make_updateBytesAdler32_Type(); _osr_end_Type = make_osr_end_Type(); _register_finalizer_Type = make_register_finalizer_Type(); + _vthread_transition_Type = make_vthread_transition_Type(); JFR_ONLY( _class_id_load_barrier_Type = make_class_id_load_barrier_Type(); ) -#if INCLUDE_JVMTI - _notify_jvmti_vthread_Type = make_notify_jvmti_vthread_Type(); -#endif // INCLUDE_JVMTI _dtrace_method_entry_exit_Type = make_dtrace_method_entry_exit_Type(); _dtrace_object_alloc_Type = make_dtrace_object_alloc_Type(); } diff --git a/src/hotspot/share/opto/runtime.hpp b/src/hotspot/share/opto/runtime.hpp index eb2b49311cf..b8cdd9a962a 100644 --- a/src/hotspot/share/opto/runtime.hpp +++ b/src/hotspot/share/opto/runtime.hpp @@ -115,15 +115,12 @@ class OptoRuntime : public AllStatic { #define C2_STUB_FIELD_NAME(name) _ ## name ## _Java #define C2_STUB_FIELD_DECLARE(name, f, t, r) \ static address C2_STUB_FIELD_NAME(name) ; -#define C2_JVMTI_STUB_FIELD_DECLARE(name) \ - static address STUB_FIELD_NAME(name); - C2_STUBS_DO(C2_BLOB_FIELD_DECLARE, C2_STUB_FIELD_DECLARE, C2_JVMTI_STUB_FIELD_DECLARE) + C2_STUBS_DO(C2_BLOB_FIELD_DECLARE, C2_STUB_FIELD_DECLARE) #undef C2_BLOB_FIELD_DECLARE #undef C2_STUB_FIELD_NAME #undef C2_STUB_FIELD_DECLARE -#undef C2_JVMTI_STUB_FIELD_DECLARE // static TypeFunc* data members static const TypeFunc* _new_instance_Type; @@ -197,12 +194,10 @@ class OptoRuntime : public AllStatic { static const TypeFunc* _updateBytesAdler32_Type; static const TypeFunc* _osr_end_Type; static const TypeFunc* _register_finalizer_Type; + static const TypeFunc* _vthread_transition_Type; #if INCLUDE_JFR static const TypeFunc* _class_id_load_barrier_Type; #endif // INCLUDE_JFR -#if INCLUDE_JVMTI - static const TypeFunc* _notify_jvmti_vthread_Type; -#endif // INCLUDE_JVMTI static const TypeFunc* _dtrace_method_entry_exit_Type; static const TypeFunc* _dtrace_object_alloc_Type; @@ -239,6 +234,11 @@ public: static void monitor_notify_C(oopDesc* obj, JavaThread* current); static void monitor_notifyAll_C(oopDesc* obj, JavaThread* current); + static void vthread_end_first_transition_C(oopDesc* vt, jboolean hide, JavaThread* current); + static void vthread_start_final_transition_C(oopDesc* vt, jboolean hide, JavaThread* current); + static void vthread_start_transition_C(oopDesc* vt, jboolean hide, JavaThread* current); + static void vthread_end_transition_C(oopDesc* vt, jboolean hide, JavaThread* current); + private: // Implicit exception support @@ -293,12 +293,11 @@ private: static address slow_arraycopy_Java() { return _slow_arraycopy_Java; } static address register_finalizer_Java() { return _register_finalizer_Java; } -#if INCLUDE_JVMTI - static address notify_jvmti_vthread_start() { return _notify_jvmti_vthread_start; } - static address notify_jvmti_vthread_end() { return _notify_jvmti_vthread_end; } - static address notify_jvmti_vthread_mount() { return _notify_jvmti_vthread_mount; } - static address notify_jvmti_vthread_unmount() { return _notify_jvmti_vthread_unmount; } -#endif + + static address vthread_end_first_transition_Java() { return _vthread_end_first_transition_Java; } + static address vthread_start_final_transition_Java() { return _vthread_start_final_transition_Java; } + static address vthread_start_transition_Java() { return _vthread_start_transition_Java; } + static address vthread_end_transition_Java() { return _vthread_end_transition_Java; } static UncommonTrapBlob* uncommon_trap_blob() { return _uncommon_trap_blob; } static ExceptionBlob* exception_blob() { return _exception_blob; } @@ -718,6 +717,27 @@ private: return _register_finalizer_Type; } + static inline const TypeFunc* vthread_transition_Type() { + assert(_vthread_transition_Type != nullptr, "should be initialized"); + return _vthread_transition_Type; + } + + static inline const TypeFunc* vthread_end_first_transition_Type() { + return vthread_transition_Type(); + } + + static inline const TypeFunc* vthread_start_final_transition_Type() { + return vthread_transition_Type(); + } + + static inline const TypeFunc* vthread_start_transition_Type() { + return vthread_transition_Type(); + } + + static inline const TypeFunc* vthread_end_transition_Type() { + return vthread_transition_Type(); + } + #if INCLUDE_JFR static inline const TypeFunc* class_id_load_barrier_Type() { assert(_class_id_load_barrier_Type != nullptr, "should be initialized"); @@ -725,13 +745,6 @@ private: } #endif // INCLUDE_JFR -#if INCLUDE_JVMTI - static inline const TypeFunc* notify_jvmti_vthread_Type() { - assert(_notify_jvmti_vthread_Type != nullptr, "should be initialized"); - return _notify_jvmti_vthread_Type; - } -#endif - // Dtrace support. entry and exit probes have the same signature static inline const TypeFunc* dtrace_method_entry_exit_Type() { assert(_dtrace_method_entry_exit_Type != nullptr, "should be initialized"); diff --git a/src/hotspot/share/prims/jvm.cpp b/src/hotspot/share/prims/jvm.cpp index a868f6337e2..16d9efde410 100644 --- a/src/hotspot/share/prims/jvm.cpp +++ b/src/hotspot/share/prims/jvm.cpp @@ -84,6 +84,7 @@ #include "runtime/javaThread.hpp" #include "runtime/jfieldIDWorkaround.hpp" #include "runtime/jniHandles.inline.hpp" +#include "runtime/mountUnmountDisabler.hpp" #include "runtime/os.inline.hpp" #include "runtime/osThread.hpp" #include "runtime/perfData.hpp" @@ -3661,68 +3662,24 @@ JVM_LEAF(jint, JVM_FindSignal(const char *name)) return os::get_signal_number(name); JVM_END -JVM_ENTRY(void, JVM_VirtualThreadStart(JNIEnv* env, jobject vthread)) -#if INCLUDE_JVMTI - if (!DoJVMTIVirtualThreadTransitions) { - assert(!JvmtiExport::can_support_virtual_threads(), "sanity check"); - return; - } - if (JvmtiVTMSTransitionDisabler::VTMS_notify_jvmti_events()) { - JvmtiVTMSTransitionDisabler::VTMS_vthread_start(vthread); - } else { - // set VTMS transition bit value in JavaThread and java.lang.VirtualThread object - JvmtiVTMSTransitionDisabler::set_is_in_VTMS_transition(thread, vthread, false); - } -#endif +JVM_ENTRY(void, JVM_VirtualThreadEndFirstTransition(JNIEnv* env, jobject vthread)) + oop vt = JNIHandles::resolve_external_guard(vthread); + MountUnmountDisabler::end_transition(thread, vt, true /*is_mount*/, true /*is_thread_start*/); JVM_END -JVM_ENTRY(void, JVM_VirtualThreadEnd(JNIEnv* env, jobject vthread)) -#if INCLUDE_JVMTI - if (!DoJVMTIVirtualThreadTransitions) { - assert(!JvmtiExport::can_support_virtual_threads(), "sanity check"); - return; - } - if (JvmtiVTMSTransitionDisabler::VTMS_notify_jvmti_events()) { - JvmtiVTMSTransitionDisabler::VTMS_vthread_end(vthread); - } else { - // set VTMS transition bit value in JavaThread and java.lang.VirtualThread object - JvmtiVTMSTransitionDisabler::set_is_in_VTMS_transition(thread, vthread, true); - } -#endif +JVM_ENTRY(void, JVM_VirtualThreadStartFinalTransition(JNIEnv* env, jobject vthread)) + oop vt = JNIHandles::resolve_external_guard(vthread); + MountUnmountDisabler::start_transition(thread, vt, false /*is_mount */, true /*is_thread_end*/); JVM_END -// If notifications are disabled then just update the VTMS transition bit and return. -// Otherwise, the bit is updated in the given jvmtiVTMSTransitionDisabler function call. -JVM_ENTRY(void, JVM_VirtualThreadMount(JNIEnv* env, jobject vthread, jboolean hide)) -#if INCLUDE_JVMTI - if (!DoJVMTIVirtualThreadTransitions) { - assert(!JvmtiExport::can_support_virtual_threads(), "sanity check"); - return; - } - if (JvmtiVTMSTransitionDisabler::VTMS_notify_jvmti_events()) { - JvmtiVTMSTransitionDisabler::VTMS_vthread_mount(vthread, hide); - } else { - // set VTMS transition bit value in JavaThread and java.lang.VirtualThread object - JvmtiVTMSTransitionDisabler::set_is_in_VTMS_transition(thread, vthread, hide); - } -#endif +JVM_ENTRY(void, JVM_VirtualThreadStartTransition(JNIEnv* env, jobject vthread, jboolean is_mount)) + oop vt = JNIHandles::resolve_external_guard(vthread); + MountUnmountDisabler::start_transition(thread, vt, is_mount, false /*is_thread_end*/); JVM_END -// If notifications are disabled then just update the VTMS transition bit and return. -// Otherwise, the bit is updated in the given jvmtiVTMSTransitionDisabler function call below. -JVM_ENTRY(void, JVM_VirtualThreadUnmount(JNIEnv* env, jobject vthread, jboolean hide)) -#if INCLUDE_JVMTI - if (!DoJVMTIVirtualThreadTransitions) { - assert(!JvmtiExport::can_support_virtual_threads(), "sanity check"); - return; - } - if (JvmtiVTMSTransitionDisabler::VTMS_notify_jvmti_events()) { - JvmtiVTMSTransitionDisabler::VTMS_vthread_unmount(vthread, hide); - } else { - // set VTMS transition bit value in JavaThread and java.lang.VirtualThread object - JvmtiVTMSTransitionDisabler::set_is_in_VTMS_transition(thread, vthread, hide); - } -#endif +JVM_ENTRY(void, JVM_VirtualThreadEndTransition(JNIEnv* env, jobject vthread, jboolean is_mount)) + oop vt = JNIHandles::resolve_external_guard(vthread); + MountUnmountDisabler::end_transition(thread, vt, is_mount, false /*is_thread_start*/); JVM_END // Notification from VirtualThread about disabling JVMTI Suspend in a sync critical section. @@ -3772,6 +3729,7 @@ JVM_ENTRY(jobject, JVM_TakeVirtualThreadListToUnblock(JNIEnv* env, jclass ignore parkEvent->park(); } JVM_END + /* * Return the current class's class file version. The low order 16 bits of the * returned jint contain the class's major version. The high order 16 bits diff --git a/src/hotspot/share/prims/jvmtiEnv.cpp b/src/hotspot/share/prims/jvmtiEnv.cpp index 5642cd9ff8f..e0863c07f4f 100644 --- a/src/hotspot/share/prims/jvmtiEnv.cpp +++ b/src/hotspot/share/prims/jvmtiEnv.cpp @@ -66,6 +66,7 @@ #include "runtime/javaThread.inline.hpp" #include "runtime/jfieldIDWorkaround.hpp" #include "runtime/jniHandles.inline.hpp" +#include "runtime/mountUnmountDisabler.hpp" #include "runtime/objectMonitor.inline.hpp" #include "runtime/os.hpp" #include "runtime/osThread.hpp" @@ -147,7 +148,7 @@ jvmtiError JvmtiEnv::SetThreadLocalStorage(jthread thread, const void* data) { JavaThread* current = JavaThread::current(); JvmtiThreadState* state = nullptr; - JvmtiVTMSTransitionDisabler disabler(thread); + MountUnmountDisabler disabler(thread); ThreadsListHandle tlh(current); JavaThread* java_thread = nullptr; @@ -200,7 +201,7 @@ JvmtiEnv::GetThreadLocalStorage(jthread thread, void** data_ptr) { VM_ENTRY_BASE(jvmtiError, JvmtiEnv::GetThreadLocalStorage , current_thread) DEBUG_ONLY(VMNativeEntryWrapper __vew;) - JvmtiVTMSTransitionDisabler disabler(thread); + MountUnmountDisabler disabler(thread); ThreadsListHandle tlh(current_thread); JavaThread* java_thread = nullptr; @@ -561,7 +562,7 @@ JvmtiEnv::SetNativeMethodPrefixes(jint prefix_count, char** prefixes) { // size_of_callbacks - pre-checked to be greater than or equal to 0 jvmtiError JvmtiEnv::SetEventCallbacks(const jvmtiEventCallbacks* callbacks, jint size_of_callbacks) { - JvmtiVTMSTransitionDisabler disabler; + MountUnmountDisabler disabler; JvmtiEventController::set_event_callbacks(this, callbacks, size_of_callbacks); return JVMTI_ERROR_NONE; } /* end SetEventCallbacks */ @@ -585,7 +586,7 @@ JvmtiEnv::SetEventNotificationMode(jvmtiEventMode mode, jvmtiEvent event_type, j if (event_type == JVMTI_EVENT_CLASS_FILE_LOAD_HOOK && enabled) { record_class_file_load_hook_enabled(); } - JvmtiVTMSTransitionDisabler disabler; + MountUnmountDisabler disabler; if (event_thread == nullptr) { // Can be called at Agent_OnLoad() time with event_thread == nullptr @@ -867,7 +868,7 @@ JvmtiEnv::GetJLocationFormat(jvmtiJlocationFormat* format_ptr) { jvmtiError JvmtiEnv::GetThreadState(jthread thread, jint* thread_state_ptr) { JavaThread* current_thread = JavaThread::current(); - JvmtiVTMSTransitionDisabler disabler(thread); + MountUnmountDisabler disabler(thread); ThreadsListHandle tlh(current_thread); JavaThread* java_thread = nullptr; @@ -939,7 +940,7 @@ JvmtiEnv::SuspendThread(jthread thread) { jvmtiError err; { - JvmtiVTMSTransitionDisabler disabler(true); + MountUnmountDisabler disabler(true); ThreadsListHandle tlh(current); JavaThread* java_thread = nullptr; oop thread_oop = nullptr; @@ -949,7 +950,7 @@ JvmtiEnv::SuspendThread(jthread thread) { return err; } - // Do not use JvmtiVTMSTransitionDisabler in context of self suspend to avoid deadlocks. + // Do not use MountUnmountDisabler in context of self suspend to avoid deadlocks. if (java_thread != current) { err = suspend_thread(thread_oop, java_thread, /* single_suspend */ true); return err; @@ -974,7 +975,7 @@ JvmtiEnv::SuspendThreadList(jint request_count, const jthread* request_list, jvm int self_idx = -1; { - JvmtiVTMSTransitionDisabler disabler(true); + MountUnmountDisabler disabler(true); ThreadsListHandle tlh(current); for (int i = 0; i < request_count; i++) { @@ -1007,7 +1008,7 @@ JvmtiEnv::SuspendThreadList(jint request_count, const jthread* request_list, jvm } } // Self suspend after all other suspends if necessary. - // Do not use JvmtiVTMSTransitionDisabler in context of self suspend to avoid deadlocks. + // Do not use MountUnmountDisabler in context of self suspend to avoid deadlocks. if (self_tobj() != nullptr) { // there should not be any error for current java_thread results[self_idx] = suspend_thread(self_tobj(), current, /* single_suspend */ true); @@ -1028,7 +1029,7 @@ JvmtiEnv::SuspendAllVirtualThreads(jint except_count, const jthread* except_list { ResourceMark rm(current); - JvmtiVTMSTransitionDisabler disabler(true); + MountUnmountDisabler disabler(true); ThreadsListHandle tlh(current); GrowableArray* elist = new GrowableArray(except_count); @@ -1078,7 +1079,7 @@ JvmtiEnv::SuspendAllVirtualThreads(jint except_count, const jthread* except_list } } // Self suspend after all other suspends if necessary. - // Do not use JvmtiVTMSTransitionDisabler in context of self suspend to avoid deadlocks. + // Do not use MountUnmountDisabler in context of self suspend to avoid deadlocks. if (self_tobj() != nullptr) { suspend_thread(self_tobj(), current, /* single_suspend */ false); } @@ -1089,7 +1090,7 @@ JvmtiEnv::SuspendAllVirtualThreads(jint except_count, const jthread* except_list // thread - NOT protected by ThreadsListHandle and NOT pre-checked jvmtiError JvmtiEnv::ResumeThread(jthread thread) { - JvmtiVTMSTransitionDisabler disabler(true); + MountUnmountDisabler disabler(true); JavaThread* current = JavaThread::current(); ThreadsListHandle tlh(current); @@ -1111,7 +1112,7 @@ jvmtiError JvmtiEnv::ResumeThreadList(jint request_count, const jthread* request_list, jvmtiError* results) { oop thread_oop = nullptr; JavaThread* java_thread = nullptr; - JvmtiVTMSTransitionDisabler disabler(true); + MountUnmountDisabler disabler(true); ThreadsListHandle tlh; for (int i = 0; i < request_count; i++) { @@ -1150,7 +1151,7 @@ JvmtiEnv::ResumeAllVirtualThreads(jint except_count, const jthread* except_list) return err; } ResourceMark rm; - JvmtiVTMSTransitionDisabler disabler(true); + MountUnmountDisabler disabler(true); GrowableArray* elist = new GrowableArray(except_count); // Collect threads from except_list for which suspended status must be restored (only for VirtualThread case) @@ -1196,7 +1197,7 @@ jvmtiError JvmtiEnv::StopThread(jthread thread, jobject exception) { JavaThread* current_thread = JavaThread::current(); - JvmtiVTMSTransitionDisabler disabler(thread); + MountUnmountDisabler disabler(thread); ThreadsListHandle tlh(current_thread); JavaThread* java_thread = nullptr; oop thread_oop = nullptr; @@ -1234,7 +1235,7 @@ JvmtiEnv::InterruptThread(jthread thread) { JavaThread* current_thread = JavaThread::current(); HandleMark hm(current_thread); - JvmtiVTMSTransitionDisabler disabler(thread); + MountUnmountDisabler disabler(thread); ThreadsListHandle tlh(current_thread); JavaThread* java_thread = nullptr; @@ -1280,7 +1281,7 @@ JvmtiEnv::GetThreadInfo(jthread thread, jvmtiThreadInfo* info_ptr) { JavaThread* java_thread = nullptr; oop thread_oop = nullptr; - JvmtiVTMSTransitionDisabler disabler(thread); + MountUnmountDisabler disabler(thread); ThreadsListHandle tlh(current_thread); // if thread is null the current thread is used @@ -1369,7 +1370,7 @@ JvmtiEnv::GetOwnedMonitorInfo(jthread thread, jint* owned_monitor_count_ptr, job JavaThread* calling_thread = JavaThread::current(); HandleMark hm(calling_thread); - JvmtiVTMSTransitionDisabler disabler(thread); + MountUnmountDisabler disabler(thread); ThreadsListHandle tlh(calling_thread); JavaThread* java_thread = nullptr; @@ -1424,7 +1425,7 @@ JvmtiEnv::GetOwnedMonitorStackDepthInfo(jthread thread, jint* monitor_info_count JavaThread* calling_thread = JavaThread::current(); HandleMark hm(calling_thread); - JvmtiVTMSTransitionDisabler disabler(thread); + MountUnmountDisabler disabler(thread); ThreadsListHandle tlh(calling_thread); JavaThread* java_thread = nullptr; @@ -1707,7 +1708,7 @@ JvmtiEnv::GetThreadListStackTraces(jint thread_count, const jthread* thread_list *stack_info_ptr = op.stack_info(); } } else { - JvmtiVTMSTransitionDisabler disabler; + MountUnmountDisabler disabler; // JVMTI get stack traces at safepoint. VM_GetThreadListStackTraces op(this, thread_count, thread_list, max_frame_count); @@ -1740,7 +1741,7 @@ JvmtiEnv::PopFrame(jthread thread) { if (thread == nullptr) { return JVMTI_ERROR_INVALID_THREAD; } - JvmtiVTMSTransitionDisabler disabler(thread); + MountUnmountDisabler disabler(thread); ThreadsListHandle tlh(current_thread); JavaThread* java_thread = nullptr; @@ -1795,7 +1796,7 @@ JvmtiEnv::GetFrameLocation(jthread thread, jint depth, jmethodID* method_ptr, jl jvmtiError JvmtiEnv::NotifyFramePop(jthread thread, jint depth) { ResourceMark rm; - JvmtiVTMSTransitionDisabler disabler(thread); + MountUnmountDisabler disabler(thread); JavaThread* current = JavaThread::current(); ThreadsListHandle tlh(current); @@ -1823,7 +1824,7 @@ JvmtiEnv::NotifyFramePop(jthread thread, jint depth) { jvmtiError JvmtiEnv::ClearAllFramePops(jthread thread) { ResourceMark rm; - JvmtiVTMSTransitionDisabler disabler(thread); + MountUnmountDisabler disabler(thread); JavaThread* current = JavaThread::current(); ThreadsListHandle tlh(current); @@ -2084,7 +2085,7 @@ JvmtiEnv::GetLocalObject(jthread thread, jint depth, jint slot, jobject* value_p // doit_prologue(), but after doit() is finished with it. ResourceMark rm(current_thread); HandleMark hm(current_thread); - JvmtiVTMSTransitionDisabler disabler(thread); + MountUnmountDisabler disabler(thread); ThreadsListHandle tlh(current_thread); JavaThread* java_thread = nullptr; @@ -2125,7 +2126,7 @@ JvmtiEnv::GetLocalInstance(jthread thread, jint depth, jobject* value_ptr){ // doit_prologue(), but after doit() is finished with it. ResourceMark rm(current_thread); HandleMark hm(current_thread); - JvmtiVTMSTransitionDisabler disabler(thread); + MountUnmountDisabler disabler(thread); ThreadsListHandle tlh(current_thread); JavaThread* java_thread = nullptr; @@ -2167,7 +2168,7 @@ JvmtiEnv::GetLocalInt(jthread thread, jint depth, jint slot, jint* value_ptr) { // doit_prologue(), but after doit() is finished with it. ResourceMark rm(current_thread); HandleMark hm(current_thread); - JvmtiVTMSTransitionDisabler disabler(thread); + MountUnmountDisabler disabler(thread); ThreadsListHandle tlh(current_thread); JavaThread* java_thread = nullptr; @@ -2209,7 +2210,7 @@ JvmtiEnv::GetLocalLong(jthread thread, jint depth, jint slot, jlong* value_ptr) // doit_prologue(), but after doit() is finished with it. ResourceMark rm(current_thread); HandleMark hm(current_thread); - JvmtiVTMSTransitionDisabler disabler(thread); + MountUnmountDisabler disabler(thread); ThreadsListHandle tlh(current_thread); JavaThread* java_thread = nullptr; @@ -2251,7 +2252,7 @@ JvmtiEnv::GetLocalFloat(jthread thread, jint depth, jint slot, jfloat* value_ptr // doit_prologue(), but after doit() is finished with it. ResourceMark rm(current_thread); HandleMark hm(current_thread); - JvmtiVTMSTransitionDisabler disabler(thread); + MountUnmountDisabler disabler(thread); ThreadsListHandle tlh(current_thread); JavaThread* java_thread = nullptr; @@ -2293,7 +2294,7 @@ JvmtiEnv::GetLocalDouble(jthread thread, jint depth, jint slot, jdouble* value_p // doit_prologue(), but after doit() is finished with it. ResourceMark rm(current_thread); HandleMark hm(current_thread); - JvmtiVTMSTransitionDisabler disabler(thread); + MountUnmountDisabler disabler(thread); ThreadsListHandle tlh(current_thread); JavaThread* java_thread = nullptr; @@ -2334,7 +2335,7 @@ JvmtiEnv::SetLocalObject(jthread thread, jint depth, jint slot, jobject value) { // doit_prologue(), but after doit() is finished with it. ResourceMark rm(current_thread); HandleMark hm(current_thread); - JvmtiVTMSTransitionDisabler disabler(thread); + MountUnmountDisabler disabler(thread); ThreadsListHandle tlh(current_thread); JavaThread* java_thread = nullptr; @@ -2371,7 +2372,7 @@ JvmtiEnv::SetLocalInt(jthread thread, jint depth, jint slot, jint value) { // doit_prologue(), but after doit() is finished with it. ResourceMark rm(current_thread); HandleMark hm(current_thread); - JvmtiVTMSTransitionDisabler disabler(thread); + MountUnmountDisabler disabler(thread); ThreadsListHandle tlh(current_thread); JavaThread* java_thread = nullptr; @@ -2408,7 +2409,7 @@ JvmtiEnv::SetLocalLong(jthread thread, jint depth, jint slot, jlong value) { // doit_prologue(), but after doit() is finished with it. ResourceMark rm(current_thread); HandleMark hm(current_thread); - JvmtiVTMSTransitionDisabler disabler(thread); + MountUnmountDisabler disabler(thread); ThreadsListHandle tlh(current_thread); JavaThread* java_thread = nullptr; @@ -2445,7 +2446,7 @@ JvmtiEnv::SetLocalFloat(jthread thread, jint depth, jint slot, jfloat value) { // doit_prologue(), but after doit() is finished with it. ResourceMark rm(current_thread); HandleMark hm(current_thread); - JvmtiVTMSTransitionDisabler disabler(thread); + MountUnmountDisabler disabler(thread); ThreadsListHandle tlh(current_thread); JavaThread* java_thread = nullptr; @@ -2482,7 +2483,7 @@ JvmtiEnv::SetLocalDouble(jthread thread, jint depth, jint slot, jdouble value) { // doit_prologue(), but after doit() is finished with it. ResourceMark rm(current_thread); HandleMark hm(current_thread); - JvmtiVTMSTransitionDisabler disabler(thread); + MountUnmountDisabler disabler(thread); ThreadsListHandle tlh(current_thread); JavaThread* java_thread = nullptr; @@ -2574,7 +2575,7 @@ JvmtiEnv::ClearBreakpoint(Method* method, jlocation location) { jvmtiError JvmtiEnv::SetFieldAccessWatch(fieldDescriptor* fdesc_ptr) { - JvmtiVTMSTransitionDisabler disabler; + MountUnmountDisabler disabler; // make sure we haven't set this watch before if (fdesc_ptr->is_field_access_watched()) return JVMTI_ERROR_DUPLICATE; fdesc_ptr->set_is_field_access_watched(true); @@ -2587,7 +2588,7 @@ JvmtiEnv::SetFieldAccessWatch(fieldDescriptor* fdesc_ptr) { jvmtiError JvmtiEnv::ClearFieldAccessWatch(fieldDescriptor* fdesc_ptr) { - JvmtiVTMSTransitionDisabler disabler; + MountUnmountDisabler disabler; // make sure we have a watch to clear if (!fdesc_ptr->is_field_access_watched()) return JVMTI_ERROR_NOT_FOUND; fdesc_ptr->set_is_field_access_watched(false); @@ -2600,7 +2601,7 @@ JvmtiEnv::ClearFieldAccessWatch(fieldDescriptor* fdesc_ptr) { jvmtiError JvmtiEnv::SetFieldModificationWatch(fieldDescriptor* fdesc_ptr) { - JvmtiVTMSTransitionDisabler disabler; + MountUnmountDisabler disabler; // make sure we haven't set this watch before if (fdesc_ptr->is_field_modification_watched()) return JVMTI_ERROR_DUPLICATE; fdesc_ptr->set_is_field_modification_watched(true); @@ -2613,7 +2614,7 @@ JvmtiEnv::SetFieldModificationWatch(fieldDescriptor* fdesc_ptr) { jvmtiError JvmtiEnv::ClearFieldModificationWatch(fieldDescriptor* fdesc_ptr) { - JvmtiVTMSTransitionDisabler disabler; + MountUnmountDisabler disabler; // make sure we have a watch to clear if (!fdesc_ptr->is_field_modification_watched()) return JVMTI_ERROR_NOT_FOUND; fdesc_ptr->set_is_field_modification_watched(false); diff --git a/src/hotspot/share/prims/jvmtiEnvBase.cpp b/src/hotspot/share/prims/jvmtiEnvBase.cpp index 2b17eddbe94..4894a4dd21a 100644 --- a/src/hotspot/share/prims/jvmtiEnvBase.cpp +++ b/src/hotspot/share/prims/jvmtiEnvBase.cpp @@ -51,6 +51,7 @@ #include "runtime/javaThread.inline.hpp" #include "runtime/jfieldIDWorkaround.hpp" #include "runtime/jniHandles.inline.hpp" +#include "runtime/mountUnmountDisabler.hpp" #include "runtime/objectMonitor.inline.hpp" #include "runtime/osThread.hpp" #include "runtime/signature.hpp" @@ -697,7 +698,7 @@ JvmtiEnvBase::check_and_skip_hidden_frames(bool is_in_VTMS_transition, javaVFram javaVFrame* JvmtiEnvBase::check_and_skip_hidden_frames(JavaThread* jt, javaVFrame* jvf) { - jvf = check_and_skip_hidden_frames(jt->is_in_VTMS_transition(), jvf); + jvf = check_and_skip_hidden_frames(jt->is_in_vthread_transition(), jvf); return jvf; } @@ -719,7 +720,7 @@ JvmtiEnvBase::get_vthread_jvf(oop vthread) { return nullptr; } vframeStream vfs(java_thread); - assert(!java_thread->is_in_VTMS_transition(), "invariant"); + assert(!java_thread->is_in_vthread_transition(), "invariant"); jvf = vfs.at_end() ? nullptr : vfs.asJavaVFrame(); jvf = check_and_skip_hidden_frames(false, jvf); } else { @@ -1693,8 +1694,7 @@ private: // jt->jvmti_vthread() for VTMS transition protocol. void correct_jvmti_thread_states() { for (JavaThread* jt : ThreadsListHandle()) { - if (jt->is_in_VTMS_transition()) { - jt->set_VTMS_transition_mark(true); + if (jt->is_in_vthread_transition()) { continue; // no need in JvmtiThreadState correction below if in transition } correct_jvmti_thread_state(jt); @@ -1711,7 +1711,7 @@ public: if (_enable) { correct_jvmti_thread_states(); } - JvmtiVTMSTransitionDisabler::set_VTMS_notify_jvmti_events(_enable); + MountUnmountDisabler::set_notify_jvmti_events(_enable); } }; @@ -1722,7 +1722,7 @@ JvmtiEnvBase::enable_virtual_threads_notify_jvmti() { if (!Continuations::enabled()) { return false; } - if (JvmtiVTMSTransitionDisabler::VTMS_notify_jvmti_events()) { + if (MountUnmountDisabler::notify_jvmti_events()) { return false; // already enabled } VM_SetNotifyJvmtiEventsMode op(true); @@ -1738,10 +1738,10 @@ JvmtiEnvBase::disable_virtual_threads_notify_jvmti() { if (!Continuations::enabled()) { return false; } - if (!JvmtiVTMSTransitionDisabler::VTMS_notify_jvmti_events()) { + if (!MountUnmountDisabler::notify_jvmti_events()) { return false; // already disabled } - JvmtiVTMSTransitionDisabler disabler(true); // ensure there are no other disablers + MountUnmountDisabler disabler(true); // ensure there are no other disablers VM_SetNotifyJvmtiEventsMode op(false); VMThread::execute(&op); return true; @@ -1769,7 +1769,6 @@ JvmtiEnvBase::suspend_thread(oop thread_oop, JavaThread* java_thread, bool singl // Platform thread or mounted vthread cases. assert(java_thread != nullptr, "sanity check"); - assert(!java_thread->is_in_VTMS_transition(), "sanity check"); // Don't allow hidden thread suspend request. if (java_thread->is_hidden_from_external_view()) { @@ -1828,7 +1827,6 @@ JvmtiEnvBase::resume_thread(oop thread_oop, JavaThread* java_thread, bool single // Platform thread or mounted vthread cases. assert(java_thread != nullptr, "sanity check"); - assert(!java_thread->is_in_VTMS_transition(), "sanity check"); // Don't allow hidden thread resume request. if (java_thread->is_hidden_from_external_view()) { @@ -2008,12 +2006,12 @@ class AdapterClosure : public HandshakeClosure { }; // Supports platform and virtual threads. -// JvmtiVTMSTransitionDisabler is always set by this function. +// MountUnmountDisabler is always set by this function. void JvmtiHandshake::execute(JvmtiUnitedHandshakeClosure* hs_cl, jthread target) { JavaThread* current = JavaThread::current(); HandleMark hm(current); - JvmtiVTMSTransitionDisabler disabler(target); + MountUnmountDisabler disabler(target); ThreadsListHandle tlh(current); JavaThread* java_thread = nullptr; oop thread_obj = nullptr; @@ -2030,7 +2028,7 @@ JvmtiHandshake::execute(JvmtiUnitedHandshakeClosure* hs_cl, jthread target) { // Supports platform and virtual threads. // A virtual thread is always identified by the target_h oop handle. // The target_jt is always nullptr for an unmounted virtual thread. -// JvmtiVTMSTransitionDisabler has to be set before call to this function. +// MountUnmountDisabler has to be set before call to this function. void JvmtiHandshake::execute(JvmtiUnitedHandshakeClosure* hs_cl, ThreadsListHandle* tlh, JavaThread* target_jt, Handle target_h) { @@ -2038,7 +2036,7 @@ JvmtiHandshake::execute(JvmtiUnitedHandshakeClosure* hs_cl, ThreadsListHandle* t bool is_virtual = java_lang_VirtualThread::is_instance(target_h()); bool self = target_jt == current; - assert(!Continuations::enabled() || self || !is_virtual || current->is_VTMS_transition_disabler(), "sanity check"); + assert(!Continuations::enabled() || self || !is_virtual || current->is_vthread_transition_disabler(), "sanity check"); hs_cl->set_target_jt(target_jt); // can be needed in the virtual thread case hs_cl->set_is_virtual(is_virtual); // can be needed in the virtual thread case @@ -2211,7 +2209,7 @@ JvmtiEnvBase::force_early_return(jthread thread, jvalue value, TosState tos) { JavaThread* current_thread = JavaThread::current(); HandleMark hm(current_thread); - JvmtiVTMSTransitionDisabler disabler(thread); + MountUnmountDisabler disabler(thread); ThreadsListHandle tlh(current_thread); JavaThread* java_thread = nullptr; @@ -2612,7 +2610,7 @@ PrintStackTraceClosure::do_thread_impl(Thread *target) { "is_VTMS_transition_disabler: %d, is_in_VTMS_transition = %d\n", tname, java_thread->name(), java_thread->is_exiting(), java_thread->is_suspended(), java_thread->is_carrier_thread_suspended(), is_vt_suspended, - java_thread->is_VTMS_transition_disabler(), java_thread->is_in_VTMS_transition()); + java_thread->is_vthread_transition_disabler(), java_thread->is_in_vthread_transition()); if (java_thread->has_last_Java_frame()) { RegisterMap reg_map(java_thread, diff --git a/src/hotspot/share/prims/jvmtiExport.cpp b/src/hotspot/share/prims/jvmtiExport.cpp index 14b7d886bce..02f39460ff6 100644 --- a/src/hotspot/share/prims/jvmtiExport.cpp +++ b/src/hotspot/share/prims/jvmtiExport.cpp @@ -61,6 +61,7 @@ #include "runtime/javaThread.hpp" #include "runtime/jniHandles.inline.hpp" #include "runtime/keepStackGCProcessed.hpp" +#include "runtime/mountUnmountDisabler.hpp" #include "runtime/objectMonitor.inline.hpp" #include "runtime/os.hpp" #include "runtime/osThread.hpp" @@ -412,7 +413,7 @@ JvmtiExport::get_jvmti_interface(JavaVM *jvm, void **penv, jint version) { if (Continuations::enabled()) { // Virtual threads support for agents loaded into running VM. // There is a performance impact when VTMS transitions are enabled. - if (!JvmtiVTMSTransitionDisabler::VTMS_notify_jvmti_events()) { + if (!MountUnmountDisabler::notify_jvmti_events()) { JvmtiEnvBase::enable_virtual_threads_notify_jvmti(); } } @@ -426,7 +427,7 @@ JvmtiExport::get_jvmti_interface(JavaVM *jvm, void **penv, jint version) { if (Continuations::enabled()) { // Virtual threads support for agents loaded at startup. // There is a performance impact when VTMS transitions are enabled. - JvmtiVTMSTransitionDisabler::set_VTMS_notify_jvmti_events(true); + MountUnmountDisabler::set_notify_jvmti_events(true, true /*is_onload*/); } return JNI_OK; @@ -1639,7 +1640,7 @@ void JvmtiExport::post_vthread_end(jobject vthread) { JVMTI_JAVA_THREAD_EVENT_CALLBACK_BLOCK(thread) jvmtiEventVirtualThreadEnd callback = env->callbacks()->VirtualThreadEnd; if (callback != nullptr) { - (*callback)(env->jvmti_external(), jem.jni_env(), vthread); + (*callback)(env->jvmti_external(), jem.jni_env(), jem.jni_thread()); } } } @@ -2924,13 +2925,13 @@ void JvmtiExport::vthread_post_monitor_waited(JavaThread *current, ObjectMonitor Handle vthread(current, current->vthread()); // Finish the VTMS transition temporarily to post the event. - JvmtiVTMSTransitionDisabler::VTMS_vthread_mount((jthread)vthread.raw_value(), false); + MountUnmountDisabler::end_transition(current, vthread(), true /*is_mount*/, false /*is_thread_start*/); // Post event. JvmtiExport::post_monitor_waited(current, obj_mntr, timed_out); // Go back to VTMS transition state. - JvmtiVTMSTransitionDisabler::VTMS_vthread_unmount((jthread)vthread.raw_value(), true); + MountUnmountDisabler::start_transition(current, vthread(), false /*is_mount*/, false /*is_thread_start*/); } void JvmtiExport::post_vm_object_alloc(JavaThread *thread, oop object) { diff --git a/src/hotspot/share/prims/jvmtiExtensions.cpp b/src/hotspot/share/prims/jvmtiExtensions.cpp index 603d62eff85..855c7bd4eba 100644 --- a/src/hotspot/share/prims/jvmtiExtensions.cpp +++ b/src/hotspot/share/prims/jvmtiExtensions.cpp @@ -29,6 +29,7 @@ #include "runtime/handles.inline.hpp" #include "runtime/interfaceSupport.inline.hpp" #include "runtime/jniHandles.inline.hpp" +#include "runtime/mountUnmountDisabler.hpp" // the list of extension functions GrowableArray* JvmtiExtensions::_ext_functions; @@ -77,7 +78,7 @@ static jvmtiError JNICALL GetVirtualThread(const jvmtiEnv* env, ...) { va_end(ap); ThreadInVMfromNative tiv(current_thread); - JvmtiVTMSTransitionDisabler disabler; + MountUnmountDisabler disabler; ThreadsListHandle tlh(current_thread); jvmtiError err; @@ -135,7 +136,7 @@ static jvmtiError JNICALL GetCarrierThread(const jvmtiEnv* env, ...) { MACOS_AARCH64_ONLY(ThreadWXEnable __wx(WXWrite, current_thread)); ThreadInVMfromNative tiv(current_thread); - JvmtiVTMSTransitionDisabler disabler; + MountUnmountDisabler disabler; ThreadsListHandle tlh(current_thread); JavaThread* java_thread; diff --git a/src/hotspot/share/prims/jvmtiTagMap.cpp b/src/hotspot/share/prims/jvmtiTagMap.cpp index c923f91f69d..90a3461f321 100644 --- a/src/hotspot/share/prims/jvmtiTagMap.cpp +++ b/src/hotspot/share/prims/jvmtiTagMap.cpp @@ -57,6 +57,7 @@ #include "runtime/javaCalls.hpp" #include "runtime/javaThread.inline.hpp" #include "runtime/jniHandles.inline.hpp" +#include "runtime/mountUnmountDisabler.hpp" #include "runtime/mutex.hpp" #include "runtime/mutexLocker.hpp" #include "runtime/safepoint.hpp" @@ -3028,7 +3029,7 @@ void JvmtiTagMap::iterate_over_reachable_objects(jvmtiHeapRootCallback heap_root jvmtiObjectReferenceCallback object_ref_callback, const void* user_data) { // VTMS transitions must be disabled before the EscapeBarrier. - JvmtiVTMSTransitionDisabler disabler; + MountUnmountDisabler disabler; JavaThread* jt = JavaThread::current(); EscapeBarrier eb(true, jt); @@ -3056,7 +3057,7 @@ void JvmtiTagMap::iterate_over_objects_reachable_from_object(jobject object, Arena dead_object_arena(mtServiceability); GrowableArray dead_objects(&dead_object_arena, 10, 0, 0); - JvmtiVTMSTransitionDisabler disabler; + MountUnmountDisabler disabler; { MutexLocker ml(Heap_lock); @@ -3076,7 +3077,7 @@ void JvmtiTagMap::follow_references(jint heap_filter, const void* user_data) { // VTMS transitions must be disabled before the EscapeBarrier. - JvmtiVTMSTransitionDisabler disabler; + MountUnmountDisabler disabler; oop obj = JNIHandles::resolve(object); JavaThread* jt = JavaThread::current(); diff --git a/src/hotspot/share/prims/jvmtiThreadState.cpp b/src/hotspot/share/prims/jvmtiThreadState.cpp index 00a48dec111..fc965e568f7 100644 --- a/src/hotspot/share/prims/jvmtiThreadState.cpp +++ b/src/hotspot/share/prims/jvmtiThreadState.cpp @@ -209,479 +209,6 @@ JvmtiThreadState::periodic_clean_up() { } } -// -// Virtual Threads Mount State transition (VTMS transition) mechanism -// - -// VTMS transitions for one virtual thread are disabled while it is positive -volatile int JvmtiVTMSTransitionDisabler::_VTMS_transition_disable_for_one_count = 0; - -// VTMS transitions for all virtual threads are disabled while it is positive -volatile int JvmtiVTMSTransitionDisabler::_VTMS_transition_disable_for_all_count = 0; - -// There is an active suspender or resumer. -volatile bool JvmtiVTMSTransitionDisabler::_SR_mode = false; - -// Notifications from VirtualThread about VTMS events are enabled. -bool JvmtiVTMSTransitionDisabler::_VTMS_notify_jvmti_events = false; - -// The JvmtiVTMSTransitionDisabler sync protocol is enabled if this count > 0. -volatile int JvmtiVTMSTransitionDisabler::_sync_protocol_enabled_count = 0; - -// JvmtiVTMSTraansitionDisabler sync protocol is enabled permanently after seeing a suspender. -volatile bool JvmtiVTMSTransitionDisabler::_sync_protocol_enabled_permanently = false; - -#ifdef ASSERT -void -JvmtiVTMSTransitionDisabler::print_info() { - log_error(jvmti)("_VTMS_transition_disable_for_one_count: %d\n", _VTMS_transition_disable_for_one_count); - log_error(jvmti)("_VTMS_transition_disable_for_all_count: %d\n\n", _VTMS_transition_disable_for_all_count); - int attempts = 10000; - for (JavaThreadIteratorWithHandle jtiwh; JavaThread *java_thread = jtiwh.next(); ) { - if (java_thread->VTMS_transition_mark()) { - log_error(jvmti)("jt: %p VTMS_transition_mark: %d\n", - (void*)java_thread, java_thread->VTMS_transition_mark()); - } - ResourceMark rm; - // Handshake with target. - PrintStackTraceClosure pstc; - Handshake::execute(&pstc, java_thread); - } -} -#endif - -// disable VTMS transitions for one virtual thread -// disable VTMS transitions for all threads if thread is nullptr or a platform thread -JvmtiVTMSTransitionDisabler::JvmtiVTMSTransitionDisabler(jthread thread) - : _is_SR(false), - _is_virtual(false), - _is_self(false), - _thread(thread) -{ - if (!Continuations::enabled()) { - return; // JvmtiVTMSTransitionDisabler is no-op without virtual threads - } - if (Thread::current_or_null() == nullptr) { - return; // Detached thread, can be a call from Agent_OnLoad. - } - JavaThread* current = JavaThread::current(); - oop thread_oop = JNIHandles::resolve_external_guard(thread); - _is_virtual = java_lang_VirtualThread::is_instance(thread_oop); - - if (thread == nullptr || - (!_is_virtual && thread_oop == current->threadObj()) || - (_is_virtual && thread_oop == current->vthread())) { - _is_self = true; - return; // no need for current thread to disable and enable transitions for itself - } - if (!sync_protocol_enabled_permanently()) { - JvmtiVTMSTransitionDisabler::inc_sync_protocol_enabled_count(); - } - - // Target can be virtual or platform thread. - // If target is a platform thread then we have to disable VTMS transitions for all threads. - // It is by several reasons: - // - carrier threads can mount virtual threads which may cause incorrect behavior - // - there is no mechanism to disable transitions for a specific carrier thread yet - if (_is_virtual) { - VTMS_transition_disable_for_one(); // disable VTMS transitions for one virtual thread - } else { - VTMS_transition_disable_for_all(); // disable VTMS transitions for all virtual threads - } -} - -// disable VTMS transitions for all virtual threads -JvmtiVTMSTransitionDisabler::JvmtiVTMSTransitionDisabler(bool is_SR) - : _is_SR(is_SR), - _is_virtual(false), - _is_self(false), - _thread(nullptr) -{ - if (!Continuations::enabled()) { - return; // JvmtiVTMSTransitionDisabler is no-op without virtual threads - } - if (Thread::current_or_null() == nullptr) { - return; // Detached thread, can be a call from Agent_OnLoad. - } - if (!sync_protocol_enabled_permanently()) { - JvmtiVTMSTransitionDisabler::inc_sync_protocol_enabled_count(); - if (is_SR) { - AtomicAccess::store(&_sync_protocol_enabled_permanently, true); - } - } - VTMS_transition_disable_for_all(); -} - -JvmtiVTMSTransitionDisabler::~JvmtiVTMSTransitionDisabler() { - if (!Continuations::enabled()) { - return; // JvmtiVTMSTransitionDisabler is a no-op without virtual threads - } - if (Thread::current_or_null() == nullptr) { - return; // Detached thread, can be a call from Agent_OnLoad. - } - if (_is_self) { - return; // no need for current thread to disable and enable transitions for itself - } - if (_is_virtual) { - VTMS_transition_enable_for_one(); // enable VTMS transitions for one virtual thread - } else { - VTMS_transition_enable_for_all(); // enable VTMS transitions for all virtual threads - } - if (!sync_protocol_enabled_permanently()) { - JvmtiVTMSTransitionDisabler::dec_sync_protocol_enabled_count(); - } -} - -// disable VTMS transitions for one virtual thread -void -JvmtiVTMSTransitionDisabler::VTMS_transition_disable_for_one() { - assert(_thread != nullptr, "sanity check"); - JavaThread* thread = JavaThread::current(); - HandleMark hm(thread); - Handle vth = Handle(thread, JNIHandles::resolve_external_guard(_thread)); - assert(java_lang_VirtualThread::is_instance(vth()), "sanity check"); - - MonitorLocker ml(JvmtiVTMSTransition_lock); - - while (_SR_mode) { // suspender or resumer is a JvmtiVTMSTransitionDisabler monopolist - ml.wait(10); // wait while there is an active suspender or resumer - } - AtomicAccess::inc(&_VTMS_transition_disable_for_one_count); - java_lang_Thread::inc_VTMS_transition_disable_count(vth()); - - while (java_lang_Thread::is_in_VTMS_transition(vth())) { - ml.wait(10); // wait while the virtual thread is in transition - } -#ifdef ASSERT - thread->set_is_VTMS_transition_disabler(true); -#endif -} - -// disable VTMS transitions for all virtual threads -void -JvmtiVTMSTransitionDisabler::VTMS_transition_disable_for_all() { - JavaThread* thread = JavaThread::current(); - int attempts = 50000; - { - MonitorLocker ml(JvmtiVTMSTransition_lock); - - assert(!thread->is_in_VTMS_transition(), "VTMS_transition sanity check"); - while (_SR_mode) { // Suspender or resumer is a JvmtiVTMSTransitionDisabler monopolist. - ml.wait(10); // Wait while there is an active suspender or resumer. - } - if (_is_SR) { - _SR_mode = true; - while (_VTMS_transition_disable_for_all_count > 0 || - _VTMS_transition_disable_for_one_count > 0) { - ml.wait(10); // Wait while there is any active jvmtiVTMSTransitionDisabler. - } - } - AtomicAccess::inc(&_VTMS_transition_disable_for_all_count); - - // Block while some mount/unmount transitions are in progress. - // Debug version fails and prints diagnostic information. - for (JavaThreadIteratorWithHandle jtiwh; JavaThread *jt = jtiwh.next(); ) { - while (jt->VTMS_transition_mark()) { - if (ml.wait(10)) { - attempts--; - } - DEBUG_ONLY(if (attempts == 0) break;) - } - } - assert(!thread->is_VTMS_transition_disabler(), "VTMS_transition sanity check"); -#ifdef ASSERT - if (attempts > 0) { - thread->set_is_VTMS_transition_disabler(true); - } -#endif - } -#ifdef ASSERT - if (attempts == 0) { - print_info(); - fatal("stuck in JvmtiVTMSTransitionDisabler::VTMS_transition_disable"); - } -#endif -} - -// enable VTMS transitions for one virtual thread -void -JvmtiVTMSTransitionDisabler::VTMS_transition_enable_for_one() { - JavaThread* thread = JavaThread::current(); - HandleMark hm(thread); - Handle vth = Handle(thread, JNIHandles::resolve_external_guard(_thread)); - if (!java_lang_VirtualThread::is_instance(vth())) { - return; // no-op if _thread is not a virtual thread - } - MonitorLocker ml(JvmtiVTMSTransition_lock); - java_lang_Thread::dec_VTMS_transition_disable_count(vth()); - AtomicAccess::dec(&_VTMS_transition_disable_for_one_count); - if (_VTMS_transition_disable_for_one_count == 0) { - ml.notify_all(); - } -#ifdef ASSERT - thread->set_is_VTMS_transition_disabler(false); -#endif -} - -// enable VTMS transitions for all virtual threads -void -JvmtiVTMSTransitionDisabler::VTMS_transition_enable_for_all() { - JavaThread* current = JavaThread::current(); - { - MonitorLocker ml(JvmtiVTMSTransition_lock); - assert(_VTMS_transition_disable_for_all_count > 0, "VTMS_transition sanity check"); - - if (_is_SR) { // Disabler is suspender or resumer. - _SR_mode = false; - } - AtomicAccess::dec(&_VTMS_transition_disable_for_all_count); - if (_VTMS_transition_disable_for_all_count == 0 || _is_SR) { - ml.notify_all(); - } -#ifdef ASSERT - current->set_is_VTMS_transition_disabler(false); -#endif - } -} - -void -JvmtiVTMSTransitionDisabler::start_VTMS_transition(jthread vthread, bool is_mount) { - JavaThread* thread = JavaThread::current(); - oop vt = JNIHandles::resolve_external_guard(vthread); - assert(!thread->is_in_VTMS_transition(), "VTMS_transition sanity check"); - - // Avoid using MonitorLocker on performance critical path, use - // two-level synchronization with lock-free operations on state bits. - assert(!thread->VTMS_transition_mark(), "sanity check"); - thread->set_VTMS_transition_mark(true); // Try to enter VTMS transition section optmistically. - java_lang_Thread::set_is_in_VTMS_transition(vt, true); - - if (!sync_protocol_enabled()) { - thread->set_is_in_VTMS_transition(true); - return; - } - HandleMark hm(thread); - Handle vth = Handle(thread, vt); - int attempts = 50000; - - // Do not allow suspends inside VTMS transitions. - // Block while transitions are disabled or there are suspend requests. - int64_t thread_id = java_lang_Thread::thread_id(vth()); // Cannot use oops while blocked. - - if (_VTMS_transition_disable_for_all_count > 0 || - java_lang_Thread::VTMS_transition_disable_count(vth()) > 0 || - thread->is_suspended() || - JvmtiVTSuspender::is_vthread_suspended(thread_id) - ) { - // Slow path: undo unsuccessful optimistic set of the VTMS_transition_mark. - // It can cause an extra waiting cycle for VTMS transition disablers. - thread->set_VTMS_transition_mark(false); - java_lang_Thread::set_is_in_VTMS_transition(vth(), false); - - while (true) { - MonitorLocker ml(JvmtiVTMSTransition_lock); - - // Do not allow suspends inside VTMS transitions. - // Block while transitions are disabled or there are suspend requests. - if (_VTMS_transition_disable_for_all_count > 0 || - java_lang_Thread::VTMS_transition_disable_count(vth()) > 0 || - thread->is_suspended() || - JvmtiVTSuspender::is_vthread_suspended(thread_id) - ) { - // Block while transitions are disabled or there are suspend requests. - if (ml.wait(200)) { - attempts--; - } - DEBUG_ONLY(if (attempts == 0) break;) - continue; // ~ThreadBlockInVM has handshake-based suspend point. - } - thread->set_VTMS_transition_mark(true); - java_lang_Thread::set_is_in_VTMS_transition(vth(), true); - break; - } - } -#ifdef ASSERT - if (attempts == 0) { - log_error(jvmti)("start_VTMS_transition: thread->is_suspended: %d is_vthread_suspended: %d\n\n", - thread->is_suspended(), JvmtiVTSuspender::is_vthread_suspended(thread_id)); - print_info(); - fatal("stuck in JvmtiVTMSTransitionDisabler::start_VTMS_transition"); - } -#endif - // Enter VTMS transition section. - thread->set_is_in_VTMS_transition(true); -} - -void -JvmtiVTMSTransitionDisabler::finish_VTMS_transition(jthread vthread, bool is_mount) { - JavaThread* thread = JavaThread::current(); - - assert(thread->is_in_VTMS_transition(), "sanity check"); - thread->set_is_in_VTMS_transition(false); - oop vt = JNIHandles::resolve_external_guard(vthread); - java_lang_Thread::set_is_in_VTMS_transition(vt, false); - assert(thread->VTMS_transition_mark(), "sanity check"); - thread->set_VTMS_transition_mark(false); - - if (!sync_protocol_enabled()) { - return; - } - int64_t thread_id = java_lang_Thread::thread_id(vt); - - // Unblock waiting VTMS transition disablers. - if (_VTMS_transition_disable_for_one_count > 0 || - _VTMS_transition_disable_for_all_count > 0) { - MonitorLocker ml(JvmtiVTMSTransition_lock); - ml.notify_all(); - } - // In unmount case the carrier thread is attached after unmount transition. - // Check and block it if there was external suspend request. - int attempts = 10000; - if (!is_mount && thread->is_carrier_thread_suspended()) { - while (true) { - MonitorLocker ml(JvmtiVTMSTransition_lock); - - // Block while there are suspend requests. - if ((!is_mount && thread->is_carrier_thread_suspended()) || - (is_mount && JvmtiVTSuspender::is_vthread_suspended(thread_id)) - ) { - // Block while there are suspend requests. - if (ml.wait(200)) { - attempts--; - } - DEBUG_ONLY(if (attempts == 0) break;) - continue; - } - break; - } - } -#ifdef ASSERT - if (attempts == 0) { - log_error(jvmti)("finish_VTMS_transition: thread->is_suspended: %d is_vthread_suspended: %d\n\n", - thread->is_suspended(), JvmtiVTSuspender::is_vthread_suspended(thread_id)); - print_info(); - fatal("stuck in JvmtiVTMSTransitionDisabler::finish_VTMS_transition"); - } -#endif -} - -// set VTMS transition bit value in JavaThread and java.lang.VirtualThread object -void JvmtiVTMSTransitionDisabler::set_is_in_VTMS_transition(JavaThread* thread, jobject vthread, bool in_trans) { - oop vt = JNIHandles::resolve_external_guard(vthread); - java_lang_Thread::set_is_in_VTMS_transition(vt, in_trans); - thread->set_is_in_VTMS_transition(in_trans); -} - -void -JvmtiVTMSTransitionDisabler::VTMS_vthread_start(jobject vthread) { - VTMS_mount_end(vthread); - JavaThread* thread = JavaThread::current(); - - assert(!thread->is_in_VTMS_transition(), "sanity check"); - - // If interp_only_mode has been enabled then we must eagerly create JvmtiThreadState - // objects for globally enabled virtual thread filtered events. Otherwise, - // it is an important optimization to create JvmtiThreadState objects lazily. - // This optimization is disabled when watchpoint capabilities are present. It is to - // work around a bug with virtual thread frames which can be not deoptimized in time. - if (JvmtiThreadState::seen_interp_only_mode() || - JvmtiExport::should_post_field_access() || - JvmtiExport::should_post_field_modification()){ - JvmtiEventController::thread_started(thread); - } - if (JvmtiExport::should_post_vthread_start()) { - JvmtiExport::post_vthread_start(vthread); - } - // post VirtualThreadMount event after VirtualThreadStart - if (JvmtiExport::should_post_vthread_mount()) { - JvmtiExport::post_vthread_mount(vthread); - } -} - -void -JvmtiVTMSTransitionDisabler::VTMS_vthread_end(jobject vthread) { - JavaThread* thread = JavaThread::current(); - - assert(!thread->is_in_VTMS_transition(), "sanity check"); - - // post VirtualThreadUnmount event before VirtualThreadEnd - if (JvmtiExport::should_post_vthread_unmount()) { - JvmtiExport::post_vthread_unmount(vthread); - } - if (JvmtiExport::should_post_vthread_end()) { - JvmtiExport::post_vthread_end(vthread); - } - VTMS_unmount_begin(vthread, /* last_unmount */ true); - if (thread->jvmti_thread_state() != nullptr) { - JvmtiExport::cleanup_thread(thread); - assert(thread->jvmti_thread_state() == nullptr, "should be null"); - assert(java_lang_Thread::jvmti_thread_state(JNIHandles::resolve(vthread)) == nullptr, "should be null"); - } - thread->rebind_to_jvmti_thread_state_of(thread->threadObj()); -} - -void -JvmtiVTMSTransitionDisabler::VTMS_vthread_mount(jobject vthread, bool hide) { - if (hide) { - VTMS_mount_begin(vthread); - } else { - VTMS_mount_end(vthread); - if (JvmtiExport::should_post_vthread_mount()) { - JvmtiExport::post_vthread_mount(vthread); - } - } -} - -void -JvmtiVTMSTransitionDisabler::VTMS_vthread_unmount(jobject vthread, bool hide) { - if (hide) { - if (JvmtiExport::should_post_vthread_unmount()) { - JvmtiExport::post_vthread_unmount(vthread); - } - VTMS_unmount_begin(vthread, /* last_unmount */ false); - } else { - VTMS_unmount_end(vthread); - } -} - -void -JvmtiVTMSTransitionDisabler::VTMS_mount_begin(jobject vthread) { - JavaThread* thread = JavaThread::current(); - assert(!thread->is_in_VTMS_transition(), "sanity check"); - start_VTMS_transition(vthread, /* is_mount */ true); -} - -void -JvmtiVTMSTransitionDisabler::VTMS_mount_end(jobject vthread) { - JavaThread* thread = JavaThread::current(); - oop vt = JNIHandles::resolve(vthread); - - thread->rebind_to_jvmti_thread_state_of(vt); - - assert(thread->is_in_VTMS_transition(), "sanity check"); - finish_VTMS_transition(vthread, /* is_mount */ true); -} - -void -JvmtiVTMSTransitionDisabler::VTMS_unmount_begin(jobject vthread, bool last_unmount) { - JavaThread* thread = JavaThread::current(); - - assert(!thread->is_in_VTMS_transition(), "sanity check"); - - start_VTMS_transition(vthread, /* is_mount */ false); - if (!last_unmount) { - thread->rebind_to_jvmti_thread_state_of(thread->threadObj()); - } -} - -void -JvmtiVTMSTransitionDisabler::VTMS_unmount_end(jobject vthread) { - JavaThread* thread = JavaThread::current(); - assert(thread->is_in_VTMS_transition(), "sanity check"); - finish_VTMS_transition(vthread, /* is_mount */ false); -} - - // // Virtual Threads Suspend/Resume management // diff --git a/src/hotspot/share/prims/jvmtiThreadState.hpp b/src/hotspot/share/prims/jvmtiThreadState.hpp index 17bdae4662e..43b568cf1fc 100644 --- a/src/hotspot/share/prims/jvmtiThreadState.hpp +++ b/src/hotspot/share/prims/jvmtiThreadState.hpp @@ -72,67 +72,6 @@ class JvmtiEnvThreadStateIterator : public StackObj { JvmtiEnvThreadState* next(JvmtiEnvThreadState* ets); }; -/////////////////////////////////////////////////////////////// -// -// class JvmtiVTMSTransitionDisabler -// -// Virtual Thread Mount State Transition (VTMS transition) mechanism -// -class JvmtiVTMSTransitionDisabler : public AnyObj { - private: - static volatile int _VTMS_transition_disable_for_one_count; // transitions for one virtual thread are disabled while it is positive - static volatile int _VTMS_transition_disable_for_all_count; // transitions for all virtual threads are disabled while it is positive - static volatile bool _SR_mode; // there is an active suspender or resumer - static volatile int _sync_protocol_enabled_count; // current number of JvmtiVTMSTransitionDisablers enabled sync protocol - static volatile bool _sync_protocol_enabled_permanently; // seen a suspender: JvmtiVTMSTransitionDisabler protocol is enabled permanently - - bool _is_SR; // is suspender or resumer - bool _is_virtual; // target thread is virtual - bool _is_self; // JvmtiVTMSTransitionDisabler is a no-op for current platform, carrier or virtual thread - jthread _thread; // virtual thread to disable transitions for, no-op if it is a platform thread - - DEBUG_ONLY(static void print_info();) - void VTMS_transition_disable_for_one(); - void VTMS_transition_disable_for_all(); - void VTMS_transition_enable_for_one(); - void VTMS_transition_enable_for_all(); - - public: - static bool _VTMS_notify_jvmti_events; // enable notifications from VirtualThread about VTMS events - static bool VTMS_notify_jvmti_events() { return _VTMS_notify_jvmti_events; } - static void set_VTMS_notify_jvmti_events(bool val) { _VTMS_notify_jvmti_events = val; } - - static void inc_sync_protocol_enabled_count() { AtomicAccess::inc(&_sync_protocol_enabled_count); } - static void dec_sync_protocol_enabled_count() { AtomicAccess::dec(&_sync_protocol_enabled_count); } - static int sync_protocol_enabled_count() { return AtomicAccess::load(&_sync_protocol_enabled_count); } - static bool sync_protocol_enabled_permanently() { return AtomicAccess::load(&_sync_protocol_enabled_permanently); } - - static bool sync_protocol_enabled() { return sync_protocol_enabled_permanently() || sync_protocol_enabled_count() > 0; } - - // parameter is_SR: suspender or resumer - JvmtiVTMSTransitionDisabler(bool is_SR = false); - JvmtiVTMSTransitionDisabler(jthread thread); - ~JvmtiVTMSTransitionDisabler(); - - // set VTMS transition bit value in JavaThread and java.lang.VirtualThread object - static void set_is_in_VTMS_transition(JavaThread* thread, jobject vthread, bool in_trans); - - static void start_VTMS_transition(jthread vthread, bool is_mount); - static void finish_VTMS_transition(jthread vthread, bool is_mount); - - static void VTMS_vthread_start(jobject vthread); - static void VTMS_vthread_end(jobject vthread); - - static void VTMS_vthread_mount(jobject vthread, bool hide); - static void VTMS_vthread_unmount(jobject vthread, bool hide); - - static void VTMS_mount_begin(jobject vthread); - static void VTMS_mount_end(jobject vthread); - - static void VTMS_unmount_begin(jobject vthread, bool last_unmount); - static void VTMS_unmount_end(jobject vthread); -}; - /////////////////////////////////////////////////////////////// // // class VirtualThreadList diff --git a/src/hotspot/share/runtime/continuation.cpp b/src/hotspot/share/runtime/continuation.cpp index 8f1cbe39640..935f304a751 100644 --- a/src/hotspot/share/runtime/continuation.cpp +++ b/src/hotspot/share/runtime/continuation.cpp @@ -35,6 +35,7 @@ #include "runtime/interfaceSupport.inline.hpp" #include "runtime/javaThread.inline.hpp" #include "runtime/jniHandles.inline.hpp" +#include "runtime/mountUnmountDisabler.hpp" #include "runtime/osThread.hpp" #include "runtime/vframe.inline.hpp" #include "runtime/vframe_hp.hpp" @@ -56,66 +57,50 @@ JVM_ENTRY(void, CONT_unpin(JNIEnv* env, jclass cls)) { } JVM_END -#if INCLUDE_JVMTI -class JvmtiUnmountBeginMark : public StackObj { +class UnmountBeginMark : public StackObj { Handle _vthread; JavaThread* _current; freeze_result _result; bool _failed; public: - JvmtiUnmountBeginMark(JavaThread* t) : + UnmountBeginMark(JavaThread* t) : _vthread(t, t->vthread()), _current(t), _result(freeze_pinned_native), _failed(false) { - assert(!_current->is_in_VTMS_transition(), "must be"); + assert(!_current->is_in_vthread_transition(), "must be"); - if (JvmtiVTMSTransitionDisabler::VTMS_notify_jvmti_events()) { - JvmtiVTMSTransitionDisabler::VTMS_vthread_unmount((jthread)_vthread.raw_value(), true); + MountUnmountDisabler::start_transition(_current, _vthread(), false /*is_mount*/, false /*is_thread_start*/); - // Don't preempt if there is a pending popframe or earlyret operation. This can - // be installed in start_VTMS_transition() so we need to check it here. - if (JvmtiExport::can_pop_frame() || JvmtiExport::can_force_early_return()) { - JvmtiThreadState* state = _current->jvmti_thread_state(); - if (_current->has_pending_popframe() || (state != nullptr && state->is_earlyret_pending())) { - _failed = true; - } - } - - // Don't preempt in case there is an async exception installed since - // we would incorrectly throw it during the unmount logic in the carrier. - if (_current->has_async_exception_condition()) { + // Don't preempt if there is a pending popframe or earlyret operation. This can + // be installed in in process_at_transition_start() so we need to check it here. + if (JvmtiExport::can_pop_frame() || JvmtiExport::can_force_early_return()) { + JvmtiThreadState* state = _current->jvmti_thread_state(); + if (_current->has_pending_popframe() || (state != nullptr && state->is_earlyret_pending())) { _failed = true; } - } else { - _current->set_is_in_VTMS_transition(true); - java_lang_Thread::set_is_in_VTMS_transition(_vthread(), true); + } + + // Don't preempt in case there is an async exception installed since + // we would incorrectly throw it during the unmount logic in the carrier. + if (_current->has_async_exception_condition()) { + _failed = true; } } - ~JvmtiUnmountBeginMark() { + ~UnmountBeginMark() { assert(!_current->is_suspended(), "must be"); - - assert(_current->is_in_VTMS_transition(), "must be"); - assert(java_lang_Thread::is_in_VTMS_transition(_vthread()), "must be"); - - // Read it again since for late binding agents the flag could have - // been set while blocked in the allocation path during freeze. - bool jvmti_present = JvmtiVTMSTransitionDisabler::VTMS_notify_jvmti_events(); + assert(_current->is_in_vthread_transition(), "must be"); if (_result != freeze_ok) { // Undo transition - if (jvmti_present) { - JvmtiVTMSTransitionDisabler::VTMS_vthread_mount((jthread)_vthread.raw_value(), false); - } else { - _current->set_is_in_VTMS_transition(false); - java_lang_Thread::set_is_in_VTMS_transition(_vthread(), false); - } + MountUnmountDisabler::end_transition(_current, _vthread(), true /*is_mount*/, false /*is_thread_start*/); } } void set_result(freeze_result res) { _result = res; } bool failed() { return _failed; } }; +#if INCLUDE_JVMTI static bool is_vthread_safe_to_preempt_for_jvmti(JavaThread* current) { - if (current->is_in_VTMS_transition()) { + if (current->is_in_vthread_transition()) { // We are at the end of a mount transition. return false; } @@ -150,11 +135,11 @@ freeze_result Continuation::try_preempt(JavaThread* current, oop continuation) { return freeze_pinned_native; } - JVMTI_ONLY(JvmtiUnmountBeginMark jubm(current);) - JVMTI_ONLY(if (jubm.failed()) return freeze_pinned_native;) + UnmountBeginMark ubm(current); + if (ubm.failed()) return freeze_pinned_native; freeze_result res = CAST_TO_FN_PTR(FreezeContFnT, freeze_preempt_entry())(current, current->last_Java_sp()); log_trace(continuations, preempt)("try_preempt: %d", res); - JVMTI_ONLY(jubm.set_result(res);) + ubm.set_result(res); if (current->has_pending_exception()) { assert(res == freeze_exception, "expecting an exception result from freeze"); diff --git a/src/hotspot/share/runtime/continuationFreezeThaw.cpp b/src/hotspot/share/runtime/continuationFreezeThaw.cpp index 2a31e5fb5b2..ccbe78817d6 100644 --- a/src/hotspot/share/runtime/continuationFreezeThaw.cpp +++ b/src/hotspot/share/runtime/continuationFreezeThaw.cpp @@ -58,6 +58,7 @@ #include "runtime/javaThread.inline.hpp" #include "runtime/jniHandles.inline.hpp" #include "runtime/keepStackGCProcessed.hpp" +#include "runtime/mountUnmountDisabler.hpp" #include "runtime/objectMonitor.inline.hpp" #include "runtime/orderAccess.hpp" #include "runtime/prefetch.inline.hpp" @@ -1690,7 +1691,7 @@ static void jvmti_mount_end(JavaThread* current, ContinuationWrapper& cont, fram AnchorMark am(current, top); // Set anchor so that the stack is walkable. JRT_BLOCK - JvmtiVTMSTransitionDisabler::VTMS_vthread_mount((jthread)vth.raw_value(), false); + MountUnmountDisabler::end_transition(current, vth(), true /*is_mount*/, false /*is_thread_start*/); if (current->pending_contended_entered_event()) { // No monitor JVMTI events for ObjectLocker case. @@ -2629,19 +2630,21 @@ intptr_t* ThawBase::handle_preempted_continuation(intptr_t* sp, Continuation::pr DEBUG_ONLY(verify_frame_kind(top, preempt_kind);) NOT_PRODUCT(int64_t tid = _thread->monitor_owner_id();) -#if INCLUDE_JVMTI // Finish the VTMS transition. - assert(_thread->is_in_VTMS_transition(), "must be"); + assert(_thread->is_in_vthread_transition(), "must be"); bool is_vthread = Continuation::continuation_scope(_cont.continuation()) == java_lang_VirtualThread::vthread_scope(); if (is_vthread) { - if (JvmtiVTMSTransitionDisabler::VTMS_notify_jvmti_events()) { +#if INCLUDE_JVMTI + if (MountUnmountDisabler::notify_jvmti_events()) { jvmti_mount_end(_thread, _cont, top, preempt_kind); - } else { - _thread->set_is_in_VTMS_transition(false); - java_lang_Thread::set_is_in_VTMS_transition(_thread->vthread(), false); + } else +#endif + { // Faster version of MountUnmountDisabler::end_transition() to avoid + // unnecessary extra instructions from jvmti_mount_end(). + java_lang_Thread::set_is_in_vthread_transition(_thread->vthread(), false); + _thread->set_is_in_vthread_transition(false); } } -#endif if (fast_case) { // If we thawed in the slow path the runtime stub/native wrapper frame already diff --git a/src/hotspot/share/runtime/handshake.cpp b/src/hotspot/share/runtime/handshake.cpp index f468f27e2c0..89b02717a7a 100644 --- a/src/hotspot/share/runtime/handshake.cpp +++ b/src/hotspot/share/runtime/handshake.cpp @@ -34,6 +34,7 @@ #include "runtime/handshake.hpp" #include "runtime/interfaceSupport.inline.hpp" #include "runtime/javaThread.inline.hpp" +#include "runtime/mountUnmountDisabler.hpp" #include "runtime/os.hpp" #include "runtime/osThread.hpp" #include "runtime/stackWatermarkSet.hpp" @@ -361,6 +362,27 @@ void Handshake::execute(HandshakeClosure* hs_cl) { VMThread::execute(&handshake); } +void Handshake::execute(HandshakeClosure* hs_cl, oop vthread) { + assert(java_lang_VirtualThread::is_instance(vthread), ""); + Handle vth(JavaThread::current(), vthread); + + MountUnmountDisabler md(vthread); + oop carrier_thread = java_lang_VirtualThread::carrier_thread(vth()); + if (carrier_thread != nullptr) { + JavaThread* target = java_lang_Thread::thread(carrier_thread); + assert(target != nullptr, ""); + // Technically there is no need for a ThreadsListHandle since the target + // will block if it tries to unmount the vthread, so it can never exit. + ThreadsListHandle tlh(JavaThread::current()); + assert(tlh.includes(target), ""); + execute(hs_cl, &tlh, target); + assert(target->threadObj() == java_lang_VirtualThread::carrier_thread(vth()), ""); + } else { + // unmounted vthread, execute closure with the current thread + hs_cl->do_thread(nullptr); + } +} + void Handshake::execute(HandshakeClosure* hs_cl, JavaThread* target) { // tlh == nullptr means we rely on a ThreadsListHandle somewhere // in the caller's context (and we sanity check for that). diff --git a/src/hotspot/share/runtime/handshake.hpp b/src/hotspot/share/runtime/handshake.hpp index 1304dca12b7..c764bbcfcd2 100644 --- a/src/hotspot/share/runtime/handshake.hpp +++ b/src/hotspot/share/runtime/handshake.hpp @@ -69,6 +69,7 @@ class Handshake : public AllStatic { // This version of execute() relies on a ThreadListHandle somewhere in // the caller's context to protect target (and we sanity check for that). static void execute(HandshakeClosure* hs_cl, JavaThread* target); + static void execute(HandshakeClosure* hs_cl, oop vthread); // This version of execute() is used when you have a ThreadListHandle in // hand and are using it to protect target. If tlh == nullptr, then we // sanity check for a ThreadListHandle somewhere in the caller's context diff --git a/src/hotspot/share/runtime/javaThread.cpp b/src/hotspot/share/runtime/javaThread.cpp index a81a687a9c0..1bf4841e193 100644 --- a/src/hotspot/share/runtime/javaThread.cpp +++ b/src/hotspot/share/runtime/javaThread.cpp @@ -448,16 +448,11 @@ JavaThread::JavaThread(MemTag mem_tag) : _do_not_unlock_if_synchronized(false), #if INCLUDE_JVMTI _carrier_thread_suspended(false), - _is_in_VTMS_transition(false), _is_disable_suspend(false), _is_in_java_upcall(false), _jvmti_events_disabled(0), - _VTMS_transition_mark(false), _on_monitor_waited_event(false), _contended_entered_monitor(nullptr), -#ifdef ASSERT - _is_VTMS_transition_disabler(false), -#endif #endif _jni_attach_state(_not_attaching_via_jni), _is_in_internal_oome_mark(false), @@ -503,6 +498,10 @@ JavaThread::JavaThread(MemTag mem_tag) : _handshake(this), _suspend_resume_manager(this, &_handshake._lock), + _is_in_vthread_transition(false), + DEBUG_ONLY(_is_vthread_transition_disabler(false) COMMA) + DEBUG_ONLY(_is_disabler_at_start(false) COMMA) + _popframe_preserved_args(nullptr), _popframe_preserved_args_size(0), @@ -1150,17 +1149,26 @@ void JavaThread::send_async_exception(JavaThread* target, oop java_throwable) { Handshake::execute(&iaeh, target); } -#if INCLUDE_JVMTI -void JavaThread::set_is_in_VTMS_transition(bool val) { - assert(is_in_VTMS_transition() != val, "already %s transition", val ? "inside" : "outside"); - _is_in_VTMS_transition = val; +bool JavaThread::is_in_vthread_transition() const { + DEBUG_ONLY(Thread* current = Thread::current();) + assert(is_handshake_safe_for(current) || SafepointSynchronize::is_at_safepoint() + || JavaThread::cast(current)->is_disabler_at_start(), "not safe"); + return AtomicAccess::load(&_is_in_vthread_transition); +} + +void JavaThread::set_is_in_vthread_transition(bool val) { + assert(is_in_vthread_transition() != val, "already %s transition", val ? "inside" : "outside"); + AtomicAccess::store(&_is_in_vthread_transition, val); } #ifdef ASSERT -void JavaThread::set_is_VTMS_transition_disabler(bool val) { - _is_VTMS_transition_disabler = val; +void JavaThread::set_is_vthread_transition_disabler(bool val) { + _is_vthread_transition_disabler = val; +} + +void JavaThread::set_is_disabler_at_start(bool val) { + _is_disabler_at_start = val; } -#endif #endif // External suspension mechanism. @@ -1170,11 +1178,8 @@ void JavaThread::set_is_VTMS_transition_disabler(bool val) { // - Target thread will not enter any new monitors. // bool JavaThread::java_suspend(bool register_vthread_SR) { -#if INCLUDE_JVMTI - // Suspending a JavaThread in VTMS transition or disabling VTMS transitions can cause deadlocks. - assert(!is_in_VTMS_transition(), "no suspend allowed in VTMS transition"); - assert(!is_VTMS_transition_disabler(), "no suspend allowed for VTMS transition disablers"); -#endif + // Suspending a vthread transition disabler can cause deadlocks. + assert(!is_vthread_transition_disabler(), "no suspend allowed for vthread transition disablers"); guarantee(Thread::is_JavaThread_protected(/* target */ this), "target JavaThread is not protected in calling context."); diff --git a/src/hotspot/share/runtime/javaThread.hpp b/src/hotspot/share/runtime/javaThread.hpp index ba2aa42132f..d4c12887e10 100644 --- a/src/hotspot/share/runtime/javaThread.hpp +++ b/src/hotspot/share/runtime/javaThread.hpp @@ -322,16 +322,11 @@ class JavaThread: public Thread { // never locked) when throwing an exception. Used by interpreter only. #if INCLUDE_JVMTI volatile bool _carrier_thread_suspended; // Carrier thread is externally suspended - bool _is_in_VTMS_transition; // thread is in virtual thread mount state transition bool _is_disable_suspend; // JVMTI suspend is temporarily disabled; used on current thread only bool _is_in_java_upcall; // JVMTI is doing a Java upcall, so JVMTI events must be hidden int _jvmti_events_disabled; // JVMTI events disabled manually - bool _VTMS_transition_mark; // used for sync between VTMS transitions and disablers bool _on_monitor_waited_event; // Avoid callee arg processing for enterSpecial when posting waited event ObjectMonitor* _contended_entered_monitor; // Monitor for pending monitor_contended_entered callback -#ifdef ASSERT - bool _is_VTMS_transition_disabler; // thread currently disabled VTMS transitions -#endif #endif // JNI attach states: @@ -737,6 +732,20 @@ public: // current thread, i.e. reverts optimizations based on escape analysis. void wait_for_object_deoptimization(); +private: + bool _is_in_vthread_transition; // thread is in virtual thread mount state transition + DEBUG_ONLY(bool _is_vthread_transition_disabler;) // thread currently disabled vthread transitions + DEBUG_ONLY(bool _is_disabler_at_start;) // thread at process of disabling vthread transitions +public: + bool is_in_vthread_transition() const; + void set_is_in_vthread_transition(bool val); +#ifdef ASSERT + bool is_vthread_transition_disabler() const { return _is_vthread_transition_disabler; } + void set_is_vthread_transition_disabler(bool val); + bool is_disabler_at_start() const { return _is_disabler_at_start; } + void set_is_disabler_at_start(bool val); +#endif + #if INCLUDE_JVMTI inline bool set_carrier_thread_suspended(); inline bool clear_carrier_thread_suspended(); @@ -745,9 +754,6 @@ public: return AtomicAccess::load(&_carrier_thread_suspended); } - bool is_in_VTMS_transition() const { return _is_in_VTMS_transition; } - void set_is_in_VTMS_transition(bool val); - bool is_disable_suspend() const { return _is_disable_suspend; } void toggle_is_disable_suspend() { _is_disable_suspend = !_is_disable_suspend; } @@ -757,15 +763,12 @@ public: void disable_jvmti_events() { _jvmti_events_disabled++; } void enable_jvmti_events() { _jvmti_events_disabled--; } - bool VTMS_transition_mark() const { return AtomicAccess::load(&_VTMS_transition_mark); } - void set_VTMS_transition_mark(bool val) { AtomicAccess::store(&_VTMS_transition_mark, val); } - // Temporarily skip posting JVMTI events for safety reasons when executions is in a critical section: - // - is in a VTMS transition (_is_in_VTMS_transition) + // - is in a vthread transition (_is_in_vthread_transition) // - is in an interruptLock or similar critical section (_is_disable_suspend) // - JVMTI is making a Java upcall (_is_in_java_upcall) bool should_hide_jvmti_events() const { - return _is_in_VTMS_transition || _is_disable_suspend || _is_in_java_upcall || _jvmti_events_disabled != 0; + return _is_in_vthread_transition || _is_disable_suspend || _is_in_java_upcall || _jvmti_events_disabled != 0; } bool on_monitor_waited_event() { return _on_monitor_waited_event; } @@ -773,10 +776,6 @@ public: bool pending_contended_entered_event() { return _contended_entered_monitor != nullptr; } ObjectMonitor* contended_entered_monitor() { return _contended_entered_monitor; } -#ifdef ASSERT - bool is_VTMS_transition_disabler() const { return _is_VTMS_transition_disabler; } - void set_is_VTMS_transition_disabler(bool val); -#endif #endif void set_contended_entered_monitor(ObjectMonitor* val) NOT_JVMTI_RETURN JVMTI_ONLY({ _contended_entered_monitor = val; }) @@ -931,9 +930,9 @@ public: static ByteSize preempt_alternate_return_offset() { return byte_offset_of(JavaThread, _preempt_alternate_return); } DEBUG_ONLY(static ByteSize interp_at_preemptable_vmcall_cnt_offset() { return byte_offset_of(JavaThread, _interp_at_preemptable_vmcall_cnt); }) static ByteSize unlocked_inflated_monitor_offset() { return byte_offset_of(JavaThread, _unlocked_inflated_monitor); } + static ByteSize is_in_vthread_transition_offset() { return byte_offset_of(JavaThread, _is_in_vthread_transition); } #if INCLUDE_JVMTI - static ByteSize is_in_VTMS_transition_offset() { return byte_offset_of(JavaThread, _is_in_VTMS_transition); } static ByteSize is_disable_suspend_offset() { return byte_offset_of(JavaThread, _is_disable_suspend); } #endif diff --git a/src/hotspot/share/runtime/mountUnmountDisabler.cpp b/src/hotspot/share/runtime/mountUnmountDisabler.cpp new file mode 100644 index 00000000000..5bf00323f10 --- /dev/null +++ b/src/hotspot/share/runtime/mountUnmountDisabler.cpp @@ -0,0 +1,450 @@ +/* + * Copyright (c) 2025, 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. + * + */ + +#include "classfile/javaClasses.inline.hpp" +#include "prims/jvmtiEventController.hpp" +#include "prims/jvmtiExport.hpp" +#include "prims/jvmtiThreadState.inline.hpp" +#include "runtime/handles.inline.hpp" +#include "runtime/javaThread.hpp" +#include "runtime/mountUnmountDisabler.hpp" +#include "runtime/threadSMR.hpp" + +volatile int MountUnmountDisabler::_global_vthread_transition_disable_count = 0; +volatile int MountUnmountDisabler::_active_disablers = 0; +bool MountUnmountDisabler::_exclusive_operation_ongoing = false; +bool MountUnmountDisabler::_notify_jvmti_events = false; + +#if INCLUDE_JVMTI +class JVMTIStartTransition : public StackObj { + JavaThread* _current; + Handle _vthread; + bool _is_mount; + bool _is_thread_end; + public: + JVMTIStartTransition(JavaThread* current, oop vthread, bool is_mount, bool is_thread_end) : + _current(current), _vthread(current, vthread), _is_mount(is_mount), _is_thread_end(is_thread_end) { + assert(DoJVMTIVirtualThreadTransitions || !JvmtiExport::can_support_virtual_threads(), "sanity check"); + if (DoJVMTIVirtualThreadTransitions && MountUnmountDisabler::notify_jvmti_events()) { + // post VirtualThreadUnmount event before VirtualThreadEnd + if (!_is_mount && JvmtiExport::should_post_vthread_unmount()) { + JvmtiExport::post_vthread_unmount((jthread)_vthread.raw_value()); + } + if (_is_thread_end && JvmtiExport::should_post_vthread_end()) { + JvmtiExport::post_vthread_end((jthread)_vthread.raw_value()); + } + } + } + ~JVMTIStartTransition() { + if (DoJVMTIVirtualThreadTransitions && MountUnmountDisabler::notify_jvmti_events()) { + if (_is_thread_end && _current->jvmti_thread_state() != nullptr) { + JvmtiExport::cleanup_thread(_current); + assert(_current->jvmti_thread_state() == nullptr, "should be null"); + assert(java_lang_Thread::jvmti_thread_state(_vthread()) == nullptr, "should be null"); + } + if (!_is_mount) { + _current->rebind_to_jvmti_thread_state_of(_current->threadObj()); + } + } + } +}; + +class JVMTIEndTransition : public StackObj { + JavaThread* _current; + Handle _vthread; + bool _is_mount; + bool _is_thread_start; + public: + JVMTIEndTransition(JavaThread* current, oop vthread, bool is_mount, bool is_thread_start) : + _current(current), _vthread(current, vthread), _is_mount(is_mount), _is_thread_start(is_thread_start) { + assert(DoJVMTIVirtualThreadTransitions || !JvmtiExport::can_support_virtual_threads(), "sanity check"); + if (DoJVMTIVirtualThreadTransitions && MountUnmountDisabler::notify_jvmti_events()) { + if (_is_mount) { + _current->rebind_to_jvmti_thread_state_of(_vthread()); + } + DEBUG_ONLY(bool is_virtual = java_lang_VirtualThread::is_instance(_current->jvmti_vthread())); + assert(_is_mount == is_virtual, "wrong identity"); + } + } + ~JVMTIEndTransition() { + if (DoJVMTIVirtualThreadTransitions && MountUnmountDisabler::notify_jvmti_events()) { + if (!_is_mount && _current->is_carrier_thread_suspended()) { + MonitorLocker ml(VThreadTransition_lock); + while (_current->is_carrier_thread_suspended()) { + ml.wait(200); + } + } + + if (_is_thread_start) { + // If interp_only_mode has been enabled then we must eagerly create JvmtiThreadState + // objects for globally enabled virtual thread filtered events. Otherwise, + // it is an important optimization to create JvmtiThreadState objects lazily. + // This optimization is disabled when watchpoint capabilities are present. It is to + // work around a bug with virtual thread frames which can be not deoptimized in time. + if (JvmtiThreadState::seen_interp_only_mode() || + JvmtiExport::should_post_field_access() || + JvmtiExport::should_post_field_modification()){ + JvmtiEventController::thread_started(_current); + } + if (JvmtiExport::should_post_vthread_start()) { + JvmtiExport::post_vthread_start((jthread)_vthread.raw_value()); + } + } + if (_is_mount && JvmtiExport::should_post_vthread_mount()) { + JvmtiExport::post_vthread_mount((jthread)_vthread.raw_value()); + } + } + } +}; +#endif // INCLUDE_JVMTI + +bool MountUnmountDisabler::is_start_transition_disabled(JavaThread* thread, oop vthread) { + // We need to read the per-vthread and global counters to check if transitions are disabled. + // In case of JVMTI present, the global counter will always be at least 1. This is to force + // the slow path and check for possible event posting. Here we need to check if transitions + // are actually disabled, so we compare the global counter against 1 or 0 accordingly. + // In case of JVMTI we also need to check for suspension. + int base_disable_count = notify_jvmti_events() ? 1 : 0; + return java_lang_Thread::vthread_transition_disable_count(vthread) > 0 + || global_vthread_transition_disable_count() > base_disable_count + JVMTI_ONLY(|| (JvmtiVTSuspender::is_vthread_suspended(java_lang_Thread::thread_id(vthread)) || thread->is_suspended())); +} + +void MountUnmountDisabler::start_transition(JavaThread* current, oop vthread, bool is_mount, bool is_thread_end) { + assert(!java_lang_Thread::is_in_vthread_transition(vthread), ""); + assert(!current->is_in_vthread_transition(), ""); + Handle vth = Handle(current, vthread); + JVMTI_ONLY(JVMTIStartTransition jst(current, vthread, is_mount, is_thread_end);) + + java_lang_Thread::set_is_in_vthread_transition(vth(), true); + current->set_is_in_vthread_transition(true); + + // Prevent loads of disable conditions from floating up. + OrderAccess::storeload(); + + while (is_start_transition_disabled(current, vth())) { + java_lang_Thread::set_is_in_vthread_transition(vth(), false); + current->set_is_in_vthread_transition(false); + { + // Block while transitions are disabled + MonitorLocker ml(VThreadTransition_lock); + while (is_start_transition_disabled(current, vth())) { + ml.wait(200); + } + } + + // Try to start transition again... + java_lang_Thread::set_is_in_vthread_transition(vth(), true); + current->set_is_in_vthread_transition(true); + OrderAccess::storeload(); + } + + // Start of the critical section. If this is a mount, we need an acquire barrier to + // synchronize with a possible disabler that executed an operation while this thread + // was unmounted. We make VirtualThread.mount guarantee such ordering and avoid barriers + // here. If this is an unmount, the handshake that the disabler executed against this + // thread already provided the needed synchronization. + // This pairs with the release barrier in xx_enable_for_one()/xx_enable_for_all(). +} + +void MountUnmountDisabler::end_transition(JavaThread* current, oop vthread, bool is_mount, bool is_thread_start) { + assert(java_lang_Thread::is_in_vthread_transition(vthread), ""); + assert(current->is_in_vthread_transition(), ""); + Handle vth = Handle(current, vthread); + JVMTI_ONLY(JVMTIEndTransition jst(current, vthread, is_mount, is_thread_start);) + + // End of the critical section. If this is an unmount, we need a release barrier before + // clearing the in_transition flags to make sure any memory operations executed in the + // transition are visible to a possible disabler that executes while this thread is unmounted. + // We make VirtualThread.unmount guarantee such ordering and avoid barriers here. If this is + // a mount, the only thing that needs to be published is the setting of carrierThread, since + // the handshake that the disabler will execute against it already provides the needed + // synchronization. This order is already guaranteed by the barriers in VirtualThread.mount. + // This pairs with the acquire barrier in xx_disable_for_one()/xx_disable_for_all(). + + java_lang_Thread::set_is_in_vthread_transition(vth(), false); + current->set_is_in_vthread_transition(false); + + // Unblock waiting transition disablers. + if (active_disablers() > 0) { + MonitorLocker ml(VThreadTransition_lock); + ml.notify_all(); + } +} + +// disable transitions for one virtual thread +// disable transitions for all threads if thread is nullptr or a platform thread +MountUnmountDisabler::MountUnmountDisabler(oop thread_oop) + : _is_exclusive(false), + _is_self(false) +{ + if (!Continuations::enabled()) { + return; // MountUnmountDisabler is no-op without virtual threads + } + if (Thread::current_or_null() == nullptr) { + return; // Detached thread, can be a call from Agent_OnLoad. + } + JavaThread* current = JavaThread::current(); + assert(!current->is_in_vthread_transition(), ""); + + bool is_virtual = java_lang_VirtualThread::is_instance(thread_oop); + if (thread_oop == nullptr || + (!is_virtual && thread_oop == current->threadObj()) || + (is_virtual && thread_oop == current->vthread())) { + _is_self = true; + return; // no need for current thread to disable and enable transitions for itself + } + + // Target can be virtual or platform thread. + // If target is a platform thread then we have to disable transitions for all threads. + // It is by several reasons: + // - carrier threads can mount virtual threads which may cause incorrect behavior + // - there is no mechanism to disable transitions for a specific carrier thread yet + if (is_virtual) { + _vthread = Handle(current, thread_oop); + disable_transition_for_one(); // disable transitions for one virtual thread + } else { + disable_transition_for_all(); // disable transitions for all virtual threads + } +} + +// disable transitions for all virtual threads +MountUnmountDisabler::MountUnmountDisabler(bool exclusive) + : _is_exclusive(exclusive), + _is_self(false) +{ + if (!Continuations::enabled()) { + return; // MountUnmountDisabler is no-op without virtual threads + } + if (Thread::current_or_null() == nullptr) { + return; // Detached thread, can be a call from Agent_OnLoad. + } + assert(!JavaThread::current()->is_in_vthread_transition(), ""); + disable_transition_for_all(); +} + +MountUnmountDisabler::~MountUnmountDisabler() { + if (!Continuations::enabled()) { + return; // MountUnmountDisabler is a no-op without virtual threads + } + if (Thread::current_or_null() == nullptr) { + return; // Detached thread, can be a call from Agent_OnLoad. + } + if (_is_self) { + return; // no need for current thread to disable and enable transitions for itself + } + if (_vthread() != nullptr) { + enable_transition_for_one(); // enable transitions for one virtual thread + } else { + enable_transition_for_all(); // enable transitions for all virtual threads + } +} + +// disable transitions for one virtual thread +void +MountUnmountDisabler::disable_transition_for_one() { + MonitorLocker ml(VThreadTransition_lock); + while (exclusive_operation_ongoing()) { + ml.wait(10); + } + + inc_active_disablers(); + java_lang_Thread::inc_vthread_transition_disable_count(_vthread()); + + // Prevent load of transition flag from floating up. + OrderAccess::storeload(); + + while (java_lang_Thread::is_in_vthread_transition(_vthread())) { + ml.wait(10); // wait while the virtual thread is in transition + } + + // Start of the critical section. If the target is unmounted, we need an acquire + // barrier to make sure memory operations executed in the last transition are visible. + // If the target is mounted, although the handshake that will be executed against it + // already provides the needed synchronization, we still need to prevent the load of + // carrierThread to float up. + // This pairs with the release barrier in end_transition(). + OrderAccess::acquire(); + DEBUG_ONLY(JavaThread::current()->set_is_vthread_transition_disabler(true);) +} + +// disable transitions for all virtual threads +void +MountUnmountDisabler::disable_transition_for_all() { + DEBUG_ONLY(JavaThread* thread = JavaThread::current();) + DEBUG_ONLY(thread->set_is_disabler_at_start(true);) + + MonitorLocker ml(VThreadTransition_lock); + while (exclusive_operation_ongoing()) { + ml.wait(10); + } + if (_is_exclusive) { + set_exclusive_operation_ongoing(true); + while (active_disablers() > 0) { + ml.wait(10); + } + } + inc_active_disablers(); + inc_global_vthread_transition_disable_count(); + + // Prevent loads of transition flag from floating up. Technically not + // required since JavaThreadIteratorWithHandle includes full fence. + OrderAccess::storeload(); + + // Block while some mount/unmount transitions are in progress. + // Debug version fails and prints diagnostic information. + for (JavaThreadIteratorWithHandle jtiwh; JavaThread *jt = jtiwh.next(); ) { + while (jt->is_in_vthread_transition()) { + ml.wait(10); + } + } + + // Start of the critical section. If some target is unmounted, we need an acquire + // barrier to make sure memory operations executed in the last transition are visible. + // If a target is mounted, although the handshake that will be executed against it + // already provides the needed synchronization, we still need to prevent the load of + // carrierThread to float up. + // This pairs with the release barrier in end_transition(). + OrderAccess::acquire(); + DEBUG_ONLY(thread->set_is_vthread_transition_disabler(true);) + DEBUG_ONLY(thread->set_is_disabler_at_start(false);) +} + +// enable transitions for one virtual thread +void +MountUnmountDisabler::enable_transition_for_one() { + assert(java_lang_VirtualThread::is_instance(_vthread()), ""); + + // End of the critical section. If the target was unmounted, we need a + // release barrier before decrementing _vthread_transition_disable_count to + // make sure any memory operations executed by the disabler are visible to + // the target once it mounts again. If the target was mounted, the handshake + // executed against it already provided the needed synchronization. + // This pairs with the equivalent acquire barrier in start_transition(). + OrderAccess::release(); + + MonitorLocker ml(VThreadTransition_lock); + dec_active_disablers(); + java_lang_Thread::dec_vthread_transition_disable_count(_vthread()); + if (java_lang_Thread::vthread_transition_disable_count(_vthread()) == 0) { + ml.notify_all(); + } + DEBUG_ONLY(JavaThread::current()->set_is_vthread_transition_disabler(false);) +} + +// enable transitions for all virtual threads +void +MountUnmountDisabler::enable_transition_for_all() { + JavaThread* thread = JavaThread::current(); + + // End of the critical section. If some target was unmounted, we need a + // release barrier before decrementing _global_vthread_transition_disable_count + // to make sure any memory operations executed by the disabler are visible to + // the target once it mounts again. If a target was mounted, the handshake + // executed against it already provided the needed synchronization. + // This pairs with the equivalent acquire barrier in start_transition(). + OrderAccess::release(); + + MonitorLocker ml(VThreadTransition_lock); + if (exclusive_operation_ongoing()) { + set_exclusive_operation_ongoing(false); + } + dec_active_disablers(); + dec_global_vthread_transition_disable_count(); + int base_disable_count = notify_jvmti_events() ? 1 : 0; + if (global_vthread_transition_disable_count() == base_disable_count || _is_exclusive) { + ml.notify_all(); + } + DEBUG_ONLY(thread->set_is_vthread_transition_disabler(false);) +} + +int MountUnmountDisabler::global_vthread_transition_disable_count() { + assert(_global_vthread_transition_disable_count >= 0, ""); + return AtomicAccess::load(&_global_vthread_transition_disable_count); +} + +void MountUnmountDisabler::inc_global_vthread_transition_disable_count() { + assert(VThreadTransition_lock->owned_by_self() || SafepointSynchronize::is_at_safepoint(), "Must be locked"); + assert(_global_vthread_transition_disable_count >= 0, ""); + AtomicAccess::store(&_global_vthread_transition_disable_count, _global_vthread_transition_disable_count + 1); +} + +void MountUnmountDisabler::dec_global_vthread_transition_disable_count() { + assert(VThreadTransition_lock->owned_by_self() || SafepointSynchronize::is_at_safepoint(), "Must be locked"); + assert(_global_vthread_transition_disable_count > 0, ""); + AtomicAccess::store(&_global_vthread_transition_disable_count, _global_vthread_transition_disable_count - 1); +} + +bool MountUnmountDisabler::exclusive_operation_ongoing() { + assert(VThreadTransition_lock->owned_by_self(), "Must be locked"); + return _exclusive_operation_ongoing; +} + +void MountUnmountDisabler::set_exclusive_operation_ongoing(bool val) { + assert(VThreadTransition_lock->owned_by_self(), "Must be locked"); + assert(_exclusive_operation_ongoing != val, ""); + _exclusive_operation_ongoing = val; +} + +int MountUnmountDisabler::active_disablers() { + assert(_active_disablers >= 0, ""); + return AtomicAccess::load(&_active_disablers); +} + +void MountUnmountDisabler::inc_active_disablers() { + assert(VThreadTransition_lock->owned_by_self(), "Must be locked"); + assert(_active_disablers >= 0, ""); + _active_disablers++; +} + +void MountUnmountDisabler::dec_active_disablers() { + assert(VThreadTransition_lock->owned_by_self(), "Must be locked"); + assert(_active_disablers > 0, ""); + _active_disablers--; +} + +bool MountUnmountDisabler::notify_jvmti_events() { + return _notify_jvmti_events; +} + +void MountUnmountDisabler::set_notify_jvmti_events(bool val, bool is_onload) { + if (val == _notify_jvmti_events || !DoJVMTIVirtualThreadTransitions) return; + + // Force slow path on start/end vthread transitions for JVMTI bookkeeping. + // 'val' is always true except with WhiteBox methods for testing purposes. + if (is_onload) { + // Skip existing increment methods since asserts will fail. + assert(val && _global_vthread_transition_disable_count == 0, ""); + AtomicAccess::inc(&_global_vthread_transition_disable_count); + } else { + assert(SafepointSynchronize::is_at_safepoint(), ""); + if (val) { + inc_global_vthread_transition_disable_count(); + } else { + dec_global_vthread_transition_disable_count(); + } + } + log_trace(continuations,tracking)("%s _notify_jvmti_events, _global_vthread_transition_disable_count=%d", val ? "enabling" : "disabling", _global_vthread_transition_disable_count); + _notify_jvmti_events = val; +} diff --git a/src/hotspot/share/runtime/mountUnmountDisabler.hpp b/src/hotspot/share/runtime/mountUnmountDisabler.hpp new file mode 100644 index 00000000000..2ebb09734a6 --- /dev/null +++ b/src/hotspot/share/runtime/mountUnmountDisabler.hpp @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2025, 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. + * + */ + +#ifndef SHARE_RUNTIME_MOUNTUNMOUNTDISABLER_HPP +#define SHARE_RUNTIME_MOUNTUNMOUNTDISABLER_HPP + +#include "memory/allocation.hpp" +#include "runtime/handles.hpp" + +class JavaThread; + +// This class adds support to disable virtual thread transitions (mount/unmount). +// This is needed to safely execute operations that access virtual thread state. +// Users should use the Handshake class when possible instead of using this directly. +class MountUnmountDisabler : public AnyObj { + // The global counter is used for operations that require disabling + // transitions for all virtual threads. Currently this is only used + // by some JVMTI operations. We also increment this counter when the + // first JVMTI agent attaches to always force the slowpath when starting + // a transition. This is needed because if JVMTI is present we need to + // check for possible event posting. + static volatile int _global_vthread_transition_disable_count; + static volatile int _active_disablers; + static bool _exclusive_operation_ongoing; + + bool _is_exclusive; // currently only for suspender or resumer + bool _is_virtual; // target thread is virtual + bool _is_self; // MountUnmountDisabler is a no-op for current platform, carrier or virtual thread + Handle _vthread; // virtual thread to disable transitions for, no-op if it is a platform thread + + //DEBUG_ONLY(static void print_info();) + void disable_transition_for_one(); + void disable_transition_for_all(); + void enable_transition_for_one(); + void enable_transition_for_all(); + + public: + MountUnmountDisabler(bool exlusive = false); + MountUnmountDisabler(oop thread_oop); + ~MountUnmountDisabler(); + + static int global_vthread_transition_disable_count(); + static void inc_global_vthread_transition_disable_count(); + static void dec_global_vthread_transition_disable_count(); + + static volatile int* global_vthread_transition_disable_count_address() { + return &_global_vthread_transition_disable_count; + } + + static bool exclusive_operation_ongoing(); + static void set_exclusive_operation_ongoing(bool val); + + static int active_disablers(); + static void inc_active_disablers(); + static void dec_active_disablers(); + + static void start_transition(JavaThread* thread, oop vthread, bool is_mount, bool is_thread_end); + static void end_transition(JavaThread* thread, oop vthread, bool is_mount, bool is_thread_start); + + static bool is_start_transition_disabled(JavaThread* thread, oop vthread); + + // enable notifications from VirtualThread about Mount/Unmount events + static bool _notify_jvmti_events; + static bool notify_jvmti_events(); + static void set_notify_jvmti_events(bool val, bool is_onload = false); + static bool* notify_jvmti_events_address() { + return &_notify_jvmti_events; + } +}; + +#endif // SHARE_RUNTIME_MOUNTUNMOUNTDISABLER_HPP diff --git a/src/hotspot/share/runtime/mutexLocker.cpp b/src/hotspot/share/runtime/mutexLocker.cpp index e4707a342a7..5d7e310fb11 100644 --- a/src/hotspot/share/runtime/mutexLocker.cpp +++ b/src/hotspot/share/runtime/mutexLocker.cpp @@ -49,7 +49,7 @@ Mutex* JfieldIdCreation_lock = nullptr; Monitor* JNICritical_lock = nullptr; Mutex* JvmtiThreadState_lock = nullptr; Monitor* EscapeBarrier_lock = nullptr; -Monitor* JvmtiVTMSTransition_lock = nullptr; +Monitor* VThreadTransition_lock = nullptr; Mutex* JvmtiVThreadSuspend_lock = nullptr; Monitor* Heap_lock = nullptr; #if INCLUDE_PARALLELGC @@ -265,7 +265,7 @@ void mutex_init() { MUTEX_DEFN(CompileStatistics_lock , PaddedMutex , safepoint); MUTEX_DEFN(DirectivesStack_lock , PaddedMutex , nosafepoint); - MUTEX_DEFN(JvmtiVTMSTransition_lock , PaddedMonitor, safepoint); // used for Virtual Thread Mount State transition management + MUTEX_DEFN(VThreadTransition_lock , PaddedMonitor, safepoint); MUTEX_DEFN(JvmtiVThreadSuspend_lock , PaddedMutex, nosafepoint-1); MUTEX_DEFN(EscapeBarrier_lock , PaddedMonitor, nosafepoint); // Used to synchronize object reallocation/relocking triggered by JVMTI MUTEX_DEFN(Management_lock , PaddedMutex , safepoint); // used for JVM management @@ -361,8 +361,8 @@ void mutex_init() { // JVMCIRuntime_lock must be acquired before JVMCI_lock to avoid deadlock MUTEX_DEFL(JVMCI_lock , PaddedMonitor, JVMCIRuntime_lock); #endif - MUTEX_DEFL(JvmtiThreadState_lock , PaddedMutex , JvmtiVTMSTransition_lock); // Used by JvmtiThreadState/JvmtiEventController - MUTEX_DEFL(SharedDecoder_lock , PaddedMutex , NmtVirtualMemory_lock); // Must be lower than NmtVirtualMemory_lock due to MemTracker::print_containing_region + MUTEX_DEFL(JvmtiThreadState_lock , PaddedMutex , VThreadTransition_lock); // Used by JvmtiThreadState/JvmtiEventController + MUTEX_DEFL(SharedDecoder_lock , PaddedMutex , NmtVirtualMemory_lock); // Must be lower than NmtVirtualMemory_lock due to MemTracker::print_containing_region // Allocate RecursiveMutex MultiArray_lock = new RecursiveMutex(); diff --git a/src/hotspot/share/runtime/mutexLocker.hpp b/src/hotspot/share/runtime/mutexLocker.hpp index 74fe4650b7c..f6c0a967718 100644 --- a/src/hotspot/share/runtime/mutexLocker.hpp +++ b/src/hotspot/share/runtime/mutexLocker.hpp @@ -47,7 +47,7 @@ extern Mutex* JfieldIdCreation_lock; // a lock on creating JNI stati extern Monitor* JNICritical_lock; // a lock used while synchronizing with threads entering/leaving JNI critical regions extern Mutex* JvmtiThreadState_lock; // a lock on modification of JVMTI thread data extern Monitor* EscapeBarrier_lock; // a lock to sync reallocating and relocking objects because of JVMTI access -extern Monitor* JvmtiVTMSTransition_lock; // a lock for Virtual Thread Mount State transition (VTMS transition) management +extern Monitor* VThreadTransition_lock; // a lock used when disabling virtual thread transitions extern Mutex* JvmtiVThreadSuspend_lock; // a lock for virtual threads suspension extern Monitor* Heap_lock; // a lock on the heap #if INCLUDE_PARALLELGC diff --git a/src/hotspot/share/runtime/sharedRuntime.cpp b/src/hotspot/share/runtime/sharedRuntime.cpp index 3a7c60cf83e..7e3bf763d08 100644 --- a/src/hotspot/share/runtime/sharedRuntime.cpp +++ b/src/hotspot/share/runtime/sharedRuntime.cpp @@ -737,34 +737,6 @@ void SharedRuntime::throw_and_post_jvmti_exception(JavaThread* current, Symbol* throw_and_post_jvmti_exception(current, h_exception); } -#if INCLUDE_JVMTI -JRT_ENTRY(void, SharedRuntime::notify_jvmti_vthread_start(oopDesc* vt, jboolean hide, JavaThread* current)) - assert(hide == JNI_FALSE, "must be VTMS transition finish"); - jobject vthread = JNIHandles::make_local(const_cast(vt)); - JvmtiVTMSTransitionDisabler::VTMS_vthread_start(vthread); - JNIHandles::destroy_local(vthread); -JRT_END - -JRT_ENTRY(void, SharedRuntime::notify_jvmti_vthread_end(oopDesc* vt, jboolean hide, JavaThread* current)) - assert(hide == JNI_TRUE, "must be VTMS transition start"); - jobject vthread = JNIHandles::make_local(const_cast(vt)); - JvmtiVTMSTransitionDisabler::VTMS_vthread_end(vthread); - JNIHandles::destroy_local(vthread); -JRT_END - -JRT_ENTRY(void, SharedRuntime::notify_jvmti_vthread_mount(oopDesc* vt, jboolean hide, JavaThread* current)) - jobject vthread = JNIHandles::make_local(const_cast(vt)); - JvmtiVTMSTransitionDisabler::VTMS_vthread_mount(vthread, hide); - JNIHandles::destroy_local(vthread); -JRT_END - -JRT_ENTRY(void, SharedRuntime::notify_jvmti_vthread_unmount(oopDesc* vt, jboolean hide, JavaThread* current)) - jobject vthread = JNIHandles::make_local(const_cast(vt)); - JvmtiVTMSTransitionDisabler::VTMS_vthread_unmount(vthread, hide); - JNIHandles::destroy_local(vthread); -JRT_END -#endif // INCLUDE_JVMTI - // The interpreter code to call this tracing function is only // called/generated when UL is on for redefine, class and has the right level // and tags. Since obsolete methods are never compiled, we don't have diff --git a/src/hotspot/share/runtime/sharedRuntime.hpp b/src/hotspot/share/runtime/sharedRuntime.hpp index a696ce5a71b..140207e5d63 100644 --- a/src/hotspot/share/runtime/sharedRuntime.hpp +++ b/src/hotspot/share/runtime/sharedRuntime.hpp @@ -317,14 +317,6 @@ class SharedRuntime: AllStatic { static void throw_and_post_jvmti_exception(JavaThread* current, Handle h_exception); static void throw_and_post_jvmti_exception(JavaThread* current, Symbol* name, const char *message = nullptr); -#if INCLUDE_JVMTI - // Functions for JVMTI notifications - static void notify_jvmti_vthread_start(oopDesc* vt, jboolean hide, JavaThread* current); - static void notify_jvmti_vthread_end(oopDesc* vt, jboolean hide, JavaThread* current); - static void notify_jvmti_vthread_mount(oopDesc* vt, jboolean hide, JavaThread* current); - static void notify_jvmti_vthread_unmount(oopDesc* vt, jboolean hide, JavaThread* current); -#endif - // RedefineClasses() tracing support for obsolete method entry static int rc_trace_method_entry(JavaThread* thread, Method* m); diff --git a/src/hotspot/share/runtime/stubDeclarations.hpp b/src/hotspot/share/runtime/stubDeclarations.hpp index b051c6d0e18..f9080364dc4 100644 --- a/src/hotspot/share/runtime/stubDeclarations.hpp +++ b/src/hotspot/share/runtime/stubDeclarations.hpp @@ -199,23 +199,10 @@ // declaration order. #ifdef COMPILER2 -// do_jvmti_stub(name) -#if INCLUDE_JVMTI -#define C2_JVMTI_STUBS_DO(do_jvmti_stub) \ - do_jvmti_stub(notify_jvmti_vthread_start) \ - do_jvmti_stub(notify_jvmti_vthread_end) \ - do_jvmti_stub(notify_jvmti_vthread_mount) \ - do_jvmti_stub(notify_jvmti_vthread_unmount) \ - -#else -#define C2_JVMTI_STUBS_DO(do_jvmti_stub) -#endif // INCLUDE_JVMTI - // client macro to operate on c2 stubs // // do_blob(name, type) // do_stub(name, fancy_jump, pass_tls, return_pc) -// do_jvmti_stub(name) // // do_blob is used for stubs that are generated via direct invocation // of the assembler to write into a blob of the appropriate type @@ -225,10 +212,8 @@ // in the IR graph employ a special type of jump (0, 1 or 2) or // provide access to TLS and the return pc. // -// do_jvmti_stub generates a JVMTI stub as an IR intrinsic which -// employs jump 0, and requires no special access -#define C2_STUBS_DO(do_blob, do_stub, do_jvmti_stub) \ +#define C2_STUBS_DO(do_blob, do_stub) \ do_blob(uncommon_trap, UncommonTrapBlob) \ do_blob(exception, ExceptionBlob) \ do_stub(new_instance, 0, true, false) \ @@ -239,16 +224,19 @@ do_stub(multianewarray4, 0, true, false) \ do_stub(multianewarray5, 0, true, false) \ do_stub(multianewarrayN, 0, true, false) \ - C2_JVMTI_STUBS_DO(do_jvmti_stub) \ do_stub(complete_monitor_locking, 0, false, false) \ do_stub(monitor_notify, 0, false, false) \ do_stub(monitor_notifyAll, 0, false, false) \ do_stub(rethrow, 2, true, true) \ do_stub(slow_arraycopy, 0, false, false) \ do_stub(register_finalizer, 0, false, false) \ + do_stub(vthread_end_first_transition, 0, false, false) \ + do_stub(vthread_start_final_transition, 0, false, false) \ + do_stub(vthread_start_transition, 0, false, false) \ + do_stub(vthread_end_transition, 0, false, false) \ #else -#define C2_STUBS_DO(do_blob, do_stub, do_jvmti_stub) +#define C2_STUBS_DO(do_blob, do_stub) #endif // Stubgen stub declarations @@ -1190,9 +1178,6 @@ // ignore do_stub(name, fancy_jump, pass_tls, return_pc) declarations #define DO_STUB_EMPTY4(name, fancy_jump, pass_tls, return_pc) -// ignore do_jvmti_stub(name) declarations -#define DO_JVMTI_STUB_EMPTY1(stub_name) - // ignore do_stub(blob_name, stub_name) declarations #define DO_STUB_EMPTY2(blob_name, stub_name) diff --git a/src/hotspot/share/runtime/stubInfo.cpp b/src/hotspot/share/runtime/stubInfo.cpp index bca6ff344ea..47a31fe7967 100644 --- a/src/hotspot/share/runtime/stubInfo.cpp +++ b/src/hotspot/share/runtime/stubInfo.cpp @@ -509,14 +509,6 @@ void StubInfo::process_stubgen_entry(StubGroup& group_cursor, StubId:: JOIN3(c2, name, id), \ EntryId:: JOIN3(c2, name, id)); \ -#define PROCESS_C2_JVMTI_STUB(name) \ - process_c2_blob(_group_cursor, _blob_cursor, \ - _stub_cursor, _entry_cursor, \ - "C2 Runtime " # name "_blob", \ - BlobId:: JOIN3(c2, name, id), \ - StubId:: JOIN3(c2, name, id), \ - EntryId:: JOIN3(c2, name, id)); \ - #define PROCESS_STUBGEN_BLOB(blob) \ process_stubgen_blob(_group_cursor, _blob_cursor, \ _stub_cursor, _entry_cursor, \ @@ -610,7 +602,7 @@ void StubInfo::populate_stub_tables() { group_details(_group_cursor)._max = BlobId::NO_BLOBID; group_details(_group_cursor)._entry_base = EntryId::NO_ENTRYID; group_details(_group_cursor)._entry_max = EntryId::NO_ENTRYID; - C2_STUBS_DO(PROCESS_C2_BLOB, PROCESS_C2_STUB, PROCESS_C2_JVMTI_STUB); + C2_STUBS_DO(PROCESS_C2_BLOB, PROCESS_C2_STUB); _group_cursor = StubGroup::STUBGEN; group_details(_group_cursor)._name = "StubGen Stubs"; @@ -637,7 +629,6 @@ void StubInfo::populate_stub_tables() { #undef PROCESS_C1_BLOB #undef PROCESS_C2_BLOB #undef PROCESS_C2_STUB -#undef PROCESS_C2_JVMTI_STUB #undef PROCESS_STUBGEN_BLOB #undef PROCESS_STUBGEN_STUB #undef PROCESS_STUBGEN_ENTRY diff --git a/src/hotspot/share/runtime/stubInfo.hpp b/src/hotspot/share/runtime/stubInfo.hpp index eaea07f7e6c..9ed6e0cb9f9 100644 --- a/src/hotspot/share/runtime/stubInfo.hpp +++ b/src/hotspot/share/runtime/stubInfo.hpp @@ -164,7 +164,6 @@ enum class StubGroup : int { #define SHARED_DECLARE_TAG(name, type) JOIN3(shared, name, id) , #define C1_DECLARE_TAG(name) JOIN3(c1, name, id) , -#define C2_DECLARE_TAG1(name) JOIN3(c2, name, id) , #define C2_DECLARE_TAG2(name, _1) JOIN3(c2, name, id) , #define C2_DECLARE_TAG4(name, _1, _2, _3) JOIN3(c2, name, id) , #define STUBGEN_DECLARE_TAG(name) JOIN3(stubgen, name, id) , @@ -177,8 +176,7 @@ enum class BlobId : int { C1_STUBS_DO(C1_DECLARE_TAG) // declare an enum tag for each opto runtime blob or stub C2_STUBS_DO(C2_DECLARE_TAG2, - C2_DECLARE_TAG4, - C2_DECLARE_TAG1) + C2_DECLARE_TAG4) // declare an enum tag for each stubgen blob STUBGEN_BLOBS_DO(STUBGEN_DECLARE_TAG) NUM_BLOBIDS @@ -214,7 +212,6 @@ enum class BlobId : int { #define SHARED_DECLARE_TAG(name, type) JOIN3(shared, name, id) , #define C1_DECLARE_TAG(name) JOIN3(c1, name, id) , -#define C2_DECLARE_TAG1(name) JOIN3(c2, name, id) , #define C2_DECLARE_TAG2(name, _1) JOIN3(c2, name, id) , #define C2_DECLARE_TAG4(name, _1, _2, _3) JOIN3(c2, name, id) , #define STUBGEN_DECLARE_TAG(blob, name) JOIN3(stubgen, name, id) , @@ -227,8 +224,7 @@ enum class StubId : int { C1_STUBS_DO(C1_DECLARE_TAG) // declare an enum tag for each opto runtime blob or stub C2_STUBS_DO(C2_DECLARE_TAG2, - C2_DECLARE_TAG4, - C2_DECLARE_TAG1) + C2_DECLARE_TAG4) // declare an enum tag for each stubgen runtime stub STUBGEN_STUBS_DO(STUBGEN_DECLARE_TAG) NUM_STUBIDS @@ -307,7 +303,7 @@ enum class StubId : int { type ::ENTRY_COUNT - 1, \ // macros to declare a tag for a C1 generated blob or a C2 generated -// blob, stub or JVMTI stub all of which have a single unique entry +// blob, stub all of which have a single unique entry #define C1_DECLARE_TAG(name) \ JOIN3(c1, name, id), \ @@ -318,9 +314,6 @@ enum class StubId : int { #define C2_DECLARE_STUB_TAG(name, fancy_jump, pass_tls, return_pc) \ JOIN3(c2, name, id), \ -#define C2_DECLARE_JVMTI_STUB_TAG(name) \ - JOIN3(c2, name, id), \ - // macros to declare a tag for a StubGen normal entry or initialized // entry @@ -366,8 +359,7 @@ enum class EntryId : int { C1_STUBS_DO(C1_DECLARE_TAG) // declare an enum tag for each opto runtime blob or stub C2_STUBS_DO(C2_DECLARE_BLOB_TAG, - C2_DECLARE_STUB_TAG, - C2_DECLARE_JVMTI_STUB_TAG) + C2_DECLARE_STUB_TAG) // declare an enum tag for each stubgen entry or, in the case of an // array of entries for the first and last entries. STUBGEN_ALL_ENTRIES_DO(STUBGEN_DECLARE_TAG, @@ -382,7 +374,6 @@ enum class EntryId : int { #undef C1_DECLARE_TAG #undef C2_DECLARE_BLOB_TAG #undef C2_DECLARE_STUB_TAG -#undef C2_DECLARE_JVMTI_STUB_TAG #undef STUBGEN_DECLARE_TAG #undef STUBGEN_DECLARE_INIT_TAG #undef STUBGEN_DECLARE_ARRAY_TAG @@ -402,7 +393,7 @@ enum class EntryId : int { 0 C1_STUBS_DO(COUNT1) #define C2_STUB_COUNT_INITIALIZER \ - 0 C2_STUBS_DO(COUNT2, COUNT4, COUNT1) + 0 C2_STUBS_DO(COUNT2, COUNT4) #define STUBGEN_BLOB_COUNT_INITIALIZER \ 0 STUBGEN_BLOBS_DO(COUNT1) diff --git a/src/hotspot/share/runtime/suspendResumeManager.cpp b/src/hotspot/share/runtime/suspendResumeManager.cpp index 1b9606cf633..067579b6386 100644 --- a/src/hotspot/share/runtime/suspendResumeManager.cpp +++ b/src/hotspot/share/runtime/suspendResumeManager.cpp @@ -93,11 +93,12 @@ void SuspendResumeManager::set_suspended_current_thread(int64_t vthread_id, bool } bool SuspendResumeManager::suspend(bool register_vthread_SR) { - JVMTI_ONLY(assert(!_target->is_in_VTMS_transition(), "no suspend allowed in VTMS transition");) JavaThread* self = JavaThread::current(); if (_target == self) { // If target is the current thread we can bypass the handshake machinery // and just suspend directly. + // Self-suspending while in transition can cause deadlocks. + assert(!self->is_in_vthread_transition(), "no self-suspend allowed in transition"); // The vthread() oop must only be accessed before state is set to _thread_blocked. int64_t id = java_lang_Thread::thread_id(_target->vthread()); ThreadBlockInVM tbivm(self); diff --git a/src/hotspot/share/services/threadService.cpp b/src/hotspot/share/services/threadService.cpp index 48f4eb16cf1..8772195df0b 100644 --- a/src/hotspot/share/services/threadService.cpp +++ b/src/hotspot/share/services/threadService.cpp @@ -1179,12 +1179,13 @@ public: GrowableArray* _bcis; JavaThreadStatus _thread_status; OopHandle _thread_name; + OopHandle _carrier_thread; GrowableArray* _locks; Blocker _blocker; - GetThreadSnapshotHandshakeClosure(Handle thread_h, JavaThread* java_thread): + GetThreadSnapshotHandshakeClosure(Handle thread_h): HandshakeClosure("GetThreadSnapshotHandshakeClosure"), - _thread_h(thread_h), _java_thread(java_thread), + _thread_h(thread_h), _java_thread(nullptr), _frame_count(0), _methods(nullptr), _bcis(nullptr), _thread_status(), _thread_name(nullptr), _locks(nullptr), _blocker() { @@ -1275,14 +1276,15 @@ private: public: void do_thread(Thread* th) override { Thread* current = Thread::current(); + _java_thread = th != nullptr ? JavaThread::cast(th) : nullptr; bool is_virtual = java_lang_VirtualThread::is_instance(_thread_h()); if (_java_thread != nullptr) { if (is_virtual) { // mounted vthread, use carrier thread state - oop carrier_thread = java_lang_VirtualThread::carrier_thread(_thread_h()); - assert(carrier_thread != nullptr, "should only get here for a mounted vthread"); - _thread_status = java_lang_Thread::get_thread_status(carrier_thread); + _carrier_thread = OopHandle(oop_storage(), java_lang_VirtualThread::carrier_thread(_thread_h())); + assert(_carrier_thread.resolve() == _java_thread->threadObj(), ""); + _thread_status = java_lang_Thread::get_thread_status(_carrier_thread.resolve()); } else { _thread_status = java_lang_Thread::get_thread_status(_thread_h()); } @@ -1459,67 +1461,21 @@ oop ThreadSnapshotFactory::get_thread_snapshot(jobject jthread, TRAPS) { oop thread_oop; bool has_javathread = tlh.cv_internal_thread_to_JavaThread(jthread, &java_thread, &thread_oop); assert((has_javathread && thread_oop != nullptr) || !has_javathread, "Missing Thread oop"); - Handle thread_h(THREAD, thread_oop); - bool is_virtual = java_lang_VirtualThread::is_instance(thread_h()); // Deals with null + bool is_virtual = java_lang_VirtualThread::is_instance(thread_oop); // Deals with null if (!has_javathread && !is_virtual) { return nullptr; // thread terminated so not of interest } - // wrapper to auto delete JvmtiVTMSTransitionDisabler - class TransitionDisabler { - JvmtiVTMSTransitionDisabler* _transition_disabler; - public: - TransitionDisabler(): _transition_disabler(nullptr) {} - ~TransitionDisabler() { - reset(); - } - void init(jobject jthread) { - _transition_disabler = new (mtInternal) JvmtiVTMSTransitionDisabler(jthread); - } - void reset() { - if (_transition_disabler != nullptr) { - delete _transition_disabler; - _transition_disabler = nullptr; - } - } - } transition_disabler; - - Handle carrier_thread; - if (is_virtual) { - // 1st need to disable mount/unmount transitions - transition_disabler.init(jthread); - - carrier_thread = Handle(THREAD, java_lang_VirtualThread::carrier_thread(thread_h())); - if (carrier_thread != nullptr) { - // Note: The java_thread associated with this carrier_thread may not be - // protected by the ThreadsListHandle above. There could have been an - // unmount and remount after the ThreadsListHandle above was created - // and before the JvmtiVTMSTransitionDisabler was created. However, as - // we have disabled transitions, if we are mounted on it, then it cannot - // terminate and so is safe to handshake with. - java_thread = java_lang_Thread::thread(carrier_thread()); - } else { - // We may have previously found a carrier but the virtual thread has unmounted - // after that, so clear that previous reference. - java_thread = nullptr; - } - } else { - java_thread = java_lang_Thread::thread(thread_h()); - } - // Handshake with target - GetThreadSnapshotHandshakeClosure cl(thread_h, java_thread); - if (java_thread == nullptr) { - // unmounted vthread, execute on the current thread - cl.do_thread(nullptr); + Handle thread_h(THREAD, thread_oop); + GetThreadSnapshotHandshakeClosure cl(thread_h); + if (java_lang_VirtualThread::is_instance(thread_oop)) { + Handshake::execute(&cl, thread_oop); } else { Handshake::execute(&cl, &tlh, java_thread); } - // all info is collected, can enable transitions. - transition_disabler.reset(); - // StackTrace InstanceKlass* ste_klass = vmClasses::StackTraceElement_klass(); assert(ste_klass != nullptr, "must be loaded"); @@ -1569,7 +1525,7 @@ oop ThreadSnapshotFactory::get_thread_snapshot(jobject jthread, TRAPS) { Handle snapshot = jdk_internal_vm_ThreadSnapshot::allocate(InstanceKlass::cast(snapshot_klass), CHECK_NULL); jdk_internal_vm_ThreadSnapshot::set_name(snapshot(), cl._thread_name.resolve()); jdk_internal_vm_ThreadSnapshot::set_thread_status(snapshot(), (int)cl._thread_status); - jdk_internal_vm_ThreadSnapshot::set_carrier_thread(snapshot(), carrier_thread()); + jdk_internal_vm_ThreadSnapshot::set_carrier_thread(snapshot(), cl._carrier_thread.resolve()); jdk_internal_vm_ThreadSnapshot::set_stack_trace(snapshot(), trace()); jdk_internal_vm_ThreadSnapshot::set_locks(snapshot(), locks()); if (!cl._blocker.is_empty()) { diff --git a/src/java.base/share/classes/java/lang/VirtualThread.java b/src/java.base/share/classes/java/lang/VirtualThread.java index 51543f835c1..514bf07e665 100644 --- a/src/java.base/share/classes/java/lang/VirtualThread.java +++ b/src/java.base/share/classes/java/lang/VirtualThread.java @@ -246,11 +246,11 @@ final class VirtualThread extends BaseVirtualThread { @Hidden @JvmtiHideEvents public void run() { - vthread.notifyJvmtiStart(); // notify JVMTI + vthread.endFirstTransition(); try { vthread.run(task); } finally { - vthread.notifyJvmtiEnd(); // notify JVMTI + vthread.startFinalTransition(); } } }; @@ -491,8 +491,9 @@ final class VirtualThread extends BaseVirtualThread { @ChangesCurrentThread @ReservedStackAccess private void mount() { - // notify JVMTI before mount - notifyJvmtiMount(/*hide*/true); + startTransition(/*is_mount*/true); + // We assume following volatile accesses provide equivalent + // of acquire ordering, otherwise we need U.loadFence() here. // sets the carrier thread Thread carrier = Thread.currentCarrierThread(); @@ -533,8 +534,9 @@ final class VirtualThread extends BaseVirtualThread { } carrier.clearInterrupt(); - // notify JVMTI after unmount - notifyJvmtiUnmount(/*hide*/false); + // We assume previous volatile accesses provide equivalent + // of release ordering, otherwise we need U.storeFence() here. + endTransition(/*is_mount*/false); } /** @@ -543,11 +545,11 @@ final class VirtualThread extends BaseVirtualThread { */ @Hidden private boolean yieldContinuation() { - notifyJvmtiUnmount(/*hide*/true); + startTransition(/*is_mount*/false); try { return Continuation.yield(VTHREAD_SCOPE); } finally { - notifyJvmtiMount(/*hide*/false); + endTransition(/*is_mount*/true); } } @@ -1401,23 +1403,34 @@ final class VirtualThread extends BaseVirtualThread { this.carrierThread = carrier; } - // -- JVM TI support -- + // The following four methods notify the VM when a "transition" starts and ends. + // A "mount transition" embodies the steps to transfer control from a platform + // thread to a virtual thread, changing the thread identity, and starting or + // resuming the virtual thread's continuation on the carrier. + // An "unmount transition" embodies the steps to transfer control from a virtual + // thread to its carrier, suspending the virtual thread's continuation, and + // restoring the thread identity to the platform thread. + // The notifications to the VM are necessary in order to coordinate with functions + // (JVMTI mostly) that disable transitions for one or all virtual threads. Starting + // a transition may block if transitions are disabled. Ending a transition may + // notify a thread that is waiting to disable transitions. The notifications are + // also used to post JVMTI events for virtual thread start and end. @IntrinsicCandidate @JvmtiMountTransition - private native void notifyJvmtiStart(); + private native void endFirstTransition(); @IntrinsicCandidate @JvmtiMountTransition - private native void notifyJvmtiEnd(); + private native void startFinalTransition(); @IntrinsicCandidate @JvmtiMountTransition - private native void notifyJvmtiMount(boolean hide); + private native void startTransition(boolean is_mount); @IntrinsicCandidate @JvmtiMountTransition - private native void notifyJvmtiUnmount(boolean hide); + private native void endTransition(boolean is_mount); @IntrinsicCandidate private static native void notifyJvmtiDisableSuspend(boolean enter); diff --git a/src/java.base/share/native/libjava/VirtualThread.c b/src/java.base/share/native/libjava/VirtualThread.c index 3cacf89e752..5936031f926 100644 --- a/src/java.base/share/native/libjava/VirtualThread.c +++ b/src/java.base/share/native/libjava/VirtualThread.c @@ -32,10 +32,10 @@ #define VIRTUAL_THREAD "Ljava/lang/VirtualThread;" static JNINativeMethod methods[] = { - { "notifyJvmtiStart", "()V", (void *)&JVM_VirtualThreadStart }, - { "notifyJvmtiEnd", "()V", (void *)&JVM_VirtualThreadEnd }, - { "notifyJvmtiMount", "(Z)V", (void *)&JVM_VirtualThreadMount }, - { "notifyJvmtiUnmount", "(Z)V", (void *)&JVM_VirtualThreadUnmount }, + { "endFirstTransition", "()V", (void *)&JVM_VirtualThreadEndFirstTransition }, + { "startFinalTransition", "()V", (void *)&JVM_VirtualThreadStartFinalTransition }, + { "startTransition", "(Z)V", (void *)&JVM_VirtualThreadStartTransition }, + { "endTransition", "(Z)V", (void *)&JVM_VirtualThreadEndTransition }, { "notifyJvmtiDisableSuspend", "(Z)V", (void *)&JVM_VirtualThreadDisableSuspend }, { "postPinnedEvent", "(" STR ")V", (void *)&JVM_VirtualThreadPinnedEvent }, { "takeVirtualThreadListToUnblock", "()" VIRTUAL_THREAD, (void *)&JVM_TakeVirtualThreadListToUnblock}, diff --git a/test/jdk/com/sun/management/HotSpotDiagnosticMXBean/DumpThreadsWhenParking.java b/test/jdk/com/sun/management/HotSpotDiagnosticMXBean/DumpThreadsWhenParking.java new file mode 100644 index 00000000000..bd7dc014460 --- /dev/null +++ b/test/jdk/com/sun/management/HotSpotDiagnosticMXBean/DumpThreadsWhenParking.java @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2025, 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 id=transitions + * @bug 8364343 + * @summary HotSpotDiagnosticMXBean.dumpThreads while virtual threads are parking and unparking + * @requires vm.continuations + * @modules jdk.management + * @library /test/lib + * @run main/othervm/timeout=200 DumpThreadsWhenParking 1000 1 100 + */ + +/* + * @test id=concurrent + * @summary HotSpotDiagnosticMXBean.dumpThreads from concurrent threads while virtual threads + * are parking and unparking + * @requires vm.continuations + * @modules jdk.management + * @library /test/lib + * @run main/othervm/timeout=200 DumpThreadsWhenParking 100 4 100 + */ + +/* + * @test id=concurrent_gcstress + * @summary HotSpotDiagnosticMXBean.dumpThreads from concurrent threads while virtual threads + * are parking and unparking + * @requires vm.debug == true & vm.continuations + * @modules jdk.management + * @library /test/lib + * @run main/othervm/timeout=200 -XX:+UnlockDiagnosticVMOptions -XX:+FullGCALot -XX:FullGCALotInterval=10000 DumpThreadsWhenParking 100 4 100 + */ + +import java.lang.management.ManagementFactory; +import java.nio.file.Files; +import java.nio.file.Path; +import java.time.Instant; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.Phaser; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.locks.LockSupport; +import java.util.stream.IntStream; +import com.sun.management.HotSpotDiagnosticMXBean; +import jdk.test.lib.thread.VThreadRunner; +import jdk.test.lib.threaddump.ThreadDump; + +public class DumpThreadsWhenParking { + + public static void main(String... args) throws Throwable { + int vthreadCount = Integer.parseInt(args[0]); + int concurrentDumpers = Integer.parseInt(args[1]); + int iterations = Integer.parseInt(args[2]); + + // need >=2 carriers to make progress + VThreadRunner.ensureParallelism(2); + + try (var executor = Executors.newVirtualThreadPerTaskExecutor(); + var pool = Executors.newCachedThreadPool()) { + + // start virtual threads that park and unpark + var done = new AtomicBoolean(); + var phaser = new Phaser(vthreadCount + 1); + for (int i = 0; i < vthreadCount; i++) { + executor.submit(() -> { + phaser.arriveAndAwaitAdvance(); + while (!done.get()) { + LockSupport.parkNanos(1); + } + }); + } + // wait for all virtual threads to start so all have a non-empty stack + System.out.format("Waiting for %d virtual threads to start ...%n", vthreadCount); + phaser.arriveAndAwaitAdvance(); + System.out.format("%d virtual threads started.%n", vthreadCount); + + // Bash on HotSpotDiagnosticMXBean.dumpThreads from >= 1 threads + try { + String containerName = Objects.toIdentityString(executor); + for (int i = 1; i <= iterations; i++) { + System.out.format("%s %d of %d ...%n", Instant.now(), i, iterations); + List> futures = IntStream.of(0, concurrentDumpers) + .mapToObj(_ -> pool.submit(() -> dumpThreads(containerName, vthreadCount))) + .toList(); + for (Future future : futures) { + future.get(); + } + } + } finally { + done.set(true); + } + } + } + + /** + * Invoke HotSpotDiagnosticMXBean.dumpThreads to generate a thread dump to a file in + * JSON format. Parse the thread dump to ensure it contains a thread grouping with + * the expected number of virtual threads. + */ + static Void dumpThreads(String containerName, int expectedVThreadCount) throws Exception { + long tid = Thread.currentThread().threadId(); + Path file = Path.of("threads-" + tid + ".json").toAbsolutePath(); + Files.deleteIfExists(file); + ManagementFactory.getPlatformMXBean(HotSpotDiagnosticMXBean.class) + .dumpThreads(file.toString(), HotSpotDiagnosticMXBean.ThreadDumpFormat.JSON); + + // read and parse the dump + String jsonText = Files.readString(file); + ThreadDump threadDump = ThreadDump.parse(jsonText); + var container = threadDump.findThreadContainer(containerName).orElse(null); + if (container == null) { + fail(containerName + " not found in thread dump"); + } + + // check expected virtual thread count + long threadCount = container.threads().count(); + if (threadCount != expectedVThreadCount) { + fail(threadCount + " virtual threads found, expected " + expectedVThreadCount); + } + + // check each thread is a virtual thread with stack frames + container.threads().forEach(t -> { + if (!t.isVirtual()) { + fail("#" + t.tid() + "(" + t.name() + ") is not a virtual thread"); + } + long stackFrameCount = t.stack().count(); + if (stackFrameCount == 0) { + fail("#" + t.tid() + " has empty stack"); + } + }); + return null; + } + + private static void fail(String message) { + throw new RuntimeException(message); + } +} diff --git a/test/jdk/com/sun/management/HotSpotDiagnosticMXBean/DumpThreadsWithEliminatedLock.java b/test/jdk/com/sun/management/HotSpotDiagnosticMXBean/DumpThreadsWithEliminatedLock.java index 4cbd0de460c..787d53ae045 100644 --- a/test/jdk/com/sun/management/HotSpotDiagnosticMXBean/DumpThreadsWithEliminatedLock.java +++ b/test/jdk/com/sun/management/HotSpotDiagnosticMXBean/DumpThreadsWithEliminatedLock.java @@ -43,6 +43,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.time.Instant; import java.util.List; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.ThreadFactory; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; @@ -73,9 +74,11 @@ public class DumpThreadsWithEliminatedLock { // A thread that spins creating and adding to a StringBuffer. StringBuffer is // synchronized, assume object will be scalar replaced and the lock eliminated. + var started = new CountDownLatch(1); var done = new AtomicBoolean(); var ref = new AtomicReference(); Thread thread = factory.newThread(() -> { + started.countDown(); while (!done.get()) { StringBuffer sb = new StringBuffer(); sb.append(System.currentTimeMillis()); @@ -85,6 +88,7 @@ public class DumpThreadsWithEliminatedLock { }); try { thread.start(); + started.await(); if (plain) { testPlainFormat(); } else { From 5ea2b6402114d34465b2ad9e476ab8e36ddeea06 Mon Sep 17 00:00:00 2001 From: Alexander Zvegintsev Date: Wed, 3 Dec 2025 20:03:33 +0000 Subject: [PATCH 150/706] 8372977: unnecessary gthread-2.0 loading Reviewed-by: prr, kizune --- .../native/libawt_xawt/awt/gtk3_interface.c | 21 ------------------- .../native/libawt_xawt/awt/gtk_interface.h | 6 ------ 2 files changed, 27 deletions(-) diff --git a/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.c b/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.c index e5b2dfa6db9..03dba969e8d 100644 --- a/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.c +++ b/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.c @@ -42,7 +42,6 @@ #include "debug_assert.h" static void *gtk3_libhandle = NULL; -static void *gthread_libhandle = NULL; static void transform_detail_string (const gchar *detail, GtkStyleContext *context); @@ -79,15 +78,6 @@ static void* dl_symbol(const char* name) return result; } -static void* dl_symbol_gthread(const char* name) -{ - void* result = dlsym(gthread_libhandle, name); - if (!result) - longjmp(j, NO_SYMBOL_EXCEPTION); - - return result; -} - gboolean gtk3_check(const char* lib_name, gboolean load) { if (gtk3_libhandle != NULL) { @@ -264,13 +254,6 @@ GtkApi* gtk3_load(JNIEnv *env, const char* lib_name) return FALSE; } - gthread_libhandle = dlopen(GTHREAD_LIB_VERSIONED, RTLD_LAZY | RTLD_LOCAL); - if (gthread_libhandle == NULL) { - gthread_libhandle = dlopen(GTHREAD_LIB, RTLD_LAZY | RTLD_LOCAL); - if (gthread_libhandle == NULL) - return FALSE; - } - if (setjmp(j) == 0) { fp_gtk_check_version = dl_symbol("gtk_check_version"); @@ -634,9 +617,6 @@ GtkApi* gtk3_load(JNIEnv *env, const char* lib_name) dlclose(gtk3_libhandle); gtk3_libhandle = NULL; - dlclose(gthread_libhandle); - gthread_libhandle = NULL; - return NULL; } @@ -735,7 +715,6 @@ static int gtk3_unload() dlerror(); dlclose(gtk3_libhandle); - dlclose(gthread_libhandle); if ((gtk3_error = dlerror()) != NULL) { return FALSE; diff --git a/src/java.desktop/unix/native/libawt_xawt/awt/gtk_interface.h b/src/java.desktop/unix/native/libawt_xawt/awt/gtk_interface.h index 11ec245ce8b..39be6a735d7 100644 --- a/src/java.desktop/unix/native/libawt_xawt/awt/gtk_interface.h +++ b/src/java.desktop/unix/native/libawt_xawt/awt/gtk_interface.h @@ -38,9 +38,6 @@ #define TRUE (!FALSE) #endif -#define GTHREAD_LIB_VERSIONED VERSIONED_JNI_LIB_NAME("gthread-2.0", "0") -#define GTHREAD_LIB JNI_LIB_NAME("gthread-2.0") - #define _G_TYPE_CIC(ip, gt, ct) ((ct*) ip) #define G_TYPE_CHECK_INSTANCE_CAST(instance, g_type, c_type) \ (_G_TYPE_CIC ((instance), (g_type), c_type)) @@ -850,9 +847,6 @@ typedef struct GtkApi { gboolean gtk_load(JNIEnv *env, GtkVersion version, gboolean verbose); gboolean gtk_check_version(GtkVersion version); -typedef struct _GThreadFunctions GThreadFunctions; -static gboolean (*fp_g_thread_get_initialized)(void); -static void (*fp_g_thread_init)(GThreadFunctions *vtable); static void (*fp_gdk_threads_init)(void); static void (*fp_gdk_threads_enter)(void); static void (*fp_gdk_threads_leave)(void); From 70e2bc876abe35b3d447f8004245bdbf2fead59f Mon Sep 17 00:00:00 2001 From: Volodymyr Paprotski Date: Wed, 3 Dec 2025 21:32:29 +0000 Subject: [PATCH 151/706] 8372816: New test sun/security/provider/acvp/ML_DSA_Intrinsic_Test.java succeeds in case of error Reviewed-by: azeller, mdoerr --- .../provider/acvp/ML_DSA_Intrinsic_Test.java | 33 +++++++------------ 1 file changed, 11 insertions(+), 22 deletions(-) diff --git a/test/jdk/sun/security/provider/acvp/ML_DSA_Intrinsic_Test.java b/test/jdk/sun/security/provider/acvp/ML_DSA_Intrinsic_Test.java index ea04b3c7eec..7f057603323 100644 --- a/test/jdk/sun/security/provider/acvp/ML_DSA_Intrinsic_Test.java +++ b/test/jdk/sun/security/provider/acvp/ML_DSA_Intrinsic_Test.java @@ -28,13 +28,6 @@ import java.lang.invoke.MethodHandles; import java.lang.reflect.Method; import java.util.HexFormat; -/* - * @test - * @library /test/lib - * @key randomness - * @modules java.base/sun.security.provider:+open - * @run main/othervm ML_DSA_Intrinsic_Test -XX:+UnlockDiagnosticVMOptions -XX:-UseDilithiumIntrinsics - */ /* * @test * @requires os.simpleArch == "x64" @@ -55,7 +48,7 @@ import java.util.HexFormat; // -XX:+UnlockDiagnosticVMOptions -XX:+UseDilithiumIntrinsics test/jdk/sun/security/provider/acvp/ML_DSA_Intrinsic_Test.java public class ML_DSA_Intrinsic_Test { - public static void main(String[] args) throws Exception { + public static void main(String[] args) throws Exception, Throwable { MethodHandles.Lookup lookup = MethodHandles.lookup(); Class kClazz = sun.security.provider.ML_DSA.class; @@ -114,27 +107,23 @@ public class ML_DSA_Intrinsic_Test { long seed = rnd.nextLong(); rnd.setSeed(seed); //Note: it might be useful to increase this number during development of new intrinsics - final int repeat = 10000000; + final int repeat = 10000; int[] coeffs1 = new int[ML_DSA_N]; int[] coeffs2 = new int[ML_DSA_N]; int[] prod1 = new int[ML_DSA_N]; int[] prod2 = new int[ML_DSA_N]; int[] prod3 = new int[ML_DSA_N]; int[] prod4 = new int[ML_DSA_N]; - try { - for (int i = 0; i < repeat; i++) { - // Hint: if test fails, you can hardcode the seed to make the test more reproducible: - // rnd.setSeed(seed); - testMult(prod1, prod2, coeffs1, coeffs2, mult, multJava, rnd, seed, i); - testMultConst(prod1, prod2, multConst, multConstJava, rnd, seed, i); - testDecompose(prod1, prod2, prod3, prod4, coeffs1, coeffs2, decompose, decomposeJava, rnd, seed, i); - testAlmostNtt(coeffs1, coeffs2, almostNtt, almostNttJava, rnd, seed, i); - testInverseNtt(coeffs1, coeffs2, inverseNtt, inverseNttJava, rnd, seed, i); - } - System.out.println("Fuzz Success"); - } catch (Throwable e) { - System.out.println("Fuzz Failed: " + e); + for (int i = 0; i < repeat; i++) { + // Hint: if test fails, you can hardcode the seed to make the test more reproducible: + // rnd.setSeed(seed); + testMult(prod1, prod2, coeffs1, coeffs2, mult, multJava, rnd, seed, i); + testMultConst(prod1, prod2, multConst, multConstJava, rnd, seed, i); + testDecompose(prod1, prod2, prod3, prod4, coeffs1, coeffs2, decompose, decomposeJava, rnd, seed, i); + testAlmostNtt(coeffs1, coeffs2, almostNtt, almostNttJava, rnd, seed, i); + testInverseNtt(coeffs1, coeffs2, inverseNtt, inverseNttJava, rnd, seed, i); } + System.out.println("Fuzz Success"); } private static final int ML_DSA_N = 256; From 9b386014a01b2bff47856bf9a8e113317db1f081 Mon Sep 17 00:00:00 2001 From: Evgeny Nikitin Date: Wed, 3 Dec 2025 21:58:17 +0000 Subject: [PATCH 152/706] 8373049: Update JCStress test suite Reviewed-by: epavlova, lmesnik --- test/hotspot/jtreg/applications/jcstress/JcstressRunner.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/hotspot/jtreg/applications/jcstress/JcstressRunner.java b/test/hotspot/jtreg/applications/jcstress/JcstressRunner.java index a0c9488dfe3..eb785b06330 100644 --- a/test/hotspot/jtreg/applications/jcstress/JcstressRunner.java +++ b/test/hotspot/jtreg/applications/jcstress/JcstressRunner.java @@ -45,7 +45,7 @@ import java.util.List; revision = JcstressRunner.VERSION, extension = "jar", unpack = false) public class JcstressRunner { - public static final String VERSION = "0.17-SNAPSHOT-20241217"; + public static final String VERSION = "0.17-SNAPSHOT-20250619"; public static final String MAIN_CLASS = "org.openjdk.jcstress.Main"; public static final String TIME_BUDGET_PROPERTY = "jcstress.time_budget"; From 1294d55b194704dce92c5132d6779e6f4d4850e6 Mon Sep 17 00:00:00 2001 From: Serguei Spitsyn Date: Wed, 3 Dec 2025 22:42:47 +0000 Subject: [PATCH 153/706] 8372769: Test runtime/handshake/HandshakeDirectTest.java failed - JVMTI ERROR 13 Reviewed-by: lmesnik, pchilanomate, cjplummer, amenkov --- .../jtreg/runtime/handshake/HandshakeDirectTest.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/test/hotspot/jtreg/runtime/handshake/HandshakeDirectTest.java b/test/hotspot/jtreg/runtime/handshake/HandshakeDirectTest.java index af43c6059d5..600ef6089a6 100644 --- a/test/hotspot/jtreg/runtime/handshake/HandshakeDirectTest.java +++ b/test/hotspot/jtreg/runtime/handshake/HandshakeDirectTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, 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,7 +48,7 @@ public class HandshakeDirectTest implements Runnable { static Object[] locks = new Object[WORKING_THREADS]; static AtomicInteger handshakeCount = new AtomicInteger(0); - static void suspendThread(Thread t) { + static boolean suspendThread(Thread t) { try { JVMTIUtils.suspendThread(t); } catch (JVMTIUtils.JvmtiException e) { @@ -56,7 +56,9 @@ public class HandshakeDirectTest implements Runnable { && e.getCode() != JVMTIUtils.JVMTI_ERROR_WRONG_PHASE) { throw e; } + return false; // failed to suspend } + return true; // suspended } static void resumeThread(Thread t) { @@ -115,7 +117,10 @@ public class HandshakeDirectTest implements Runnable { public void run() { while (true) { int i = ThreadLocalRandom.current().nextInt(0, WORKING_THREADS - 1); - suspendThread(workingThreads[i]); + boolean suspended = suspendThread(workingThreads[i]); + if (!suspended) { + continue; // skip resumeThread call if thread was not suspended + } try { Thread.sleep(1); // sleep for 1 ms } catch(InterruptedException ie) { From db2a5420a2e3d0f5f0f066eace37a8fd4f075802 Mon Sep 17 00:00:00 2001 From: Xiaolong Peng Date: Wed, 3 Dec 2025 22:43:17 +0000 Subject: [PATCH 154/706] 8372861: Genshen: Override parallel_region_stride of ShenandoahResetBitmapClosure to a reasonable value for better parallelism Reviewed-by: kdnilsen, shade, wkemper --- src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp | 3 +++ src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp | 2 +- src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp | 1 + .../share/gc/shenandoah/shenandoahHeapRegionClosures.hpp | 8 ++++++++ 4 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp index ea421365614..123bd792126 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp @@ -76,6 +76,9 @@ public: } } + // Bitmap reset task is heavy-weight and benefits from much smaller tasks than the default. + size_t parallel_region_stride() override { return 8; } + bool is_thread_safe() override { return true; } }; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp index 5c4d10ca8a5..6d569e9b4ce 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp @@ -1962,7 +1962,7 @@ void ShenandoahHeap::parallel_heap_region_iterate(ShenandoahHeapRegionClosure* b assert(blk->is_thread_safe(), "Only thread-safe closures here"); const uint active_workers = workers()->active_workers(); const size_t n_regions = num_regions(); - size_t stride = ShenandoahParallelRegionStride; + size_t stride = blk->parallel_region_stride(); if (stride == 0 && active_workers > 1) { // Automatically derive the stride to balance the work between threads // evenly. Do not try to split work if below the reasonable threshold. diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp index cd388ee7cf3..65e3803627c 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp @@ -113,6 +113,7 @@ public: class ShenandoahHeapRegionClosure : public StackObj { public: virtual void heap_region_do(ShenandoahHeapRegion* r) = 0; + virtual size_t parallel_region_stride() { return ShenandoahParallelRegionStride; } virtual bool is_thread_safe() { return false; } }; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegionClosures.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegionClosures.hpp index 0daf268628c..3f3b57c9bb2 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegionClosures.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegionClosures.hpp @@ -44,6 +44,10 @@ public: } } + size_t parallel_region_stride() override { + return _closure->parallel_region_stride(); + } + bool is_thread_safe() override { return _closure->is_thread_safe(); } @@ -64,6 +68,10 @@ public: } } + size_t parallel_region_stride() override { + return _closure->parallel_region_stride(); + } + bool is_thread_safe() override { return _closure->is_thread_safe(); } From 8f8fda7c80b57e8a36827cc260f0be0e5d61f6a6 Mon Sep 17 00:00:00 2001 From: Xiaolong Peng Date: Wed, 3 Dec 2025 22:46:18 +0000 Subject: [PATCH 155/706] 8373048: Genshen: Remove dead code from Shenandoah Reviewed-by: wkemper --- .../share/gc/shenandoah/shenandoahFreeSet.cpp | 115 +----------------- .../gc/shenandoah/shenandoahGeneration.cpp | 2 - .../shenandoah/shenandoahGenerationalHeap.cpp | 13 -- .../shenandoah/shenandoahGenerationalHeap.hpp | 12 -- .../shenandoahHeapRegion.inline.hpp | 2 +- .../shenandoah/shenandoahRegulatorThread.hpp | 1 - .../shenandoah/shenandoahScanRemembered.hpp | 2 - 7 files changed, 2 insertions(+), 145 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp index ab7985b3d34..6a6cad68fd9 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp @@ -175,7 +175,6 @@ ShenandoahRegionPartitions::ShenandoahRegionPartitions(size_t max_regions, Shena void ShenandoahFreeSet::account_for_pip_regions(size_t mutator_regions, size_t mutator_bytes, size_t collector_regions, size_t collector_bytes) { shenandoah_assert_heaplocked(); - size_t region_size_bytes = ShenandoahHeapRegion::region_size_bytes(); // We have removed all of these regions from their respective partition. Each pip region is "in" the NotFree partition. // We want to account for all pip pad memory as if it had been consumed from within the Mutator partition. @@ -1605,18 +1604,13 @@ HeapWord* ShenandoahFreeSet::try_allocate_in(ShenandoahHeapRegion* r, Shenandoah } } - size_t ac = alloc_capacity(r); ShenandoahFreeSetPartitionId orig_partition; - ShenandoahGeneration* request_generation = nullptr; if (req.is_mutator_alloc()) { - request_generation = _heap->mode()->is_generational()? _heap->young_generation(): _heap->global_generation(); orig_partition = ShenandoahFreeSetPartitionId::Mutator; } else if (req.is_old()) { - request_generation = _heap->old_generation(); orig_partition = ShenandoahFreeSetPartitionId::OldCollector; } else { // Not old collector alloc, so this is a young collector gclab or shared allocation - request_generation = _heap->mode()->is_generational()? _heap->young_generation(): _heap->global_generation(); orig_partition = ShenandoahFreeSetPartitionId::Collector; } if (alloc_capacity(r) < PLAB::min_size() * HeapWordSize) { @@ -1688,7 +1682,6 @@ HeapWord* ShenandoahFreeSet::allocate_contiguous(ShenandoahAllocRequest& req, bo idx_t num = ShenandoahHeapRegion::required_regions(words_size * HeapWordSize); assert(req.is_young(), "Humongous regions always allocated in YOUNG"); - ShenandoahGeneration* generation = _heap->generation_for(req.affiliation()); // Check if there are enough regions left to satisfy allocation. if (num > (idx_t) _partitions.count(ShenandoahFreeSetPartitionId::Mutator)) { @@ -1833,107 +1826,7 @@ HeapWord* ShenandoahFreeSet::allocate_contiguous(ShenandoahAllocRequest& req, bo } class ShenandoahRecycleTrashedRegionClosure final : public ShenandoahHeapRegionClosure { -private: - static const ssize_t SentinelUsed = -1; - static const ssize_t SentinelIndex = -1; - static const size_t MaxSavedRegions = 128; - - ShenandoahRegionPartitions* _partitions; - volatile size_t _recycled_region_count; - ssize_t _region_indices[MaxSavedRegions]; - ssize_t _region_used[MaxSavedRegions]; - - void get_lock_and_flush_buffer(size_t region_count, size_t overflow_region_used, size_t overflow_region_index) { - ShenandoahHeap* heap = ShenandoahHeap::heap(); - ShenandoahHeapLocker locker(heap->lock()); - size_t recycled_regions = AtomicAccess::load(&_recycled_region_count); - size_t region_tallies[int(ShenandoahRegionPartitions::NumPartitions)]; - size_t used_byte_tallies[int(ShenandoahRegionPartitions::NumPartitions)]; - for (int p = 0; p < int(ShenandoahRegionPartitions::NumPartitions); p++) { - region_tallies[p] = 0; - used_byte_tallies[p] = 0; - } - ShenandoahFreeSetPartitionId p = _partitions->membership(overflow_region_index); - used_byte_tallies[int(p)] += overflow_region_used; - if (region_count <= recycled_regions) { - // _recycled_region_count has not been decremented after I incremented it to obtain region_count, so I will - // try to flush the buffer. - - // Multiple worker threads may attempt to flush this buffer. The first thread to acquire the lock does the work. - // _recycled_region_count is only decreased while holding the heap lock. - if (region_count > recycled_regions) { - region_count = recycled_regions; - } - for (size_t i = 0; i < region_count; i++) { - ssize_t used; - // wait for other threads to finish updating their entries within the region buffer before processing entry - do { - used = _region_used[i]; - } while (used == SentinelUsed); - ssize_t index; - do { - index = _region_indices[i]; - } while (index == SentinelIndex); - - ShenandoahFreeSetPartitionId p = _partitions->membership(index); - assert(p != ShenandoahFreeSetPartitionId::NotFree, "Trashed regions should be in a free partition"); - used_byte_tallies[int(p)] += used; - region_tallies[int(p)]++; - } - if (region_count > 0) { - for (size_t i = 0; i < MaxSavedRegions; i++) { - _region_indices[i] = SentinelIndex; - _region_used[i] = SentinelUsed; - } - } - - // The almost last thing we do before releasing the lock is to set the _recycled_region_count to 0. What happens next? - // - // 1. Any worker thread that attempted to buffer a new region while we were flushing the buffer will have seen - // that _recycled_region_count > MaxSavedRegions. All such worker threads will first wait for the lock, then - // discover that the _recycled_region_count is zero, then, while holding the lock, they will process the - // region so it doesn't have to be placed into the buffer. This handles the large majority of cases. - // - // 2. However, there's a race that can happen, which will result in someewhat different behavior. Suppose - // this thread resets _recycled_region_count to 0. Then some other worker thread increments _recycled_region_count - // in order to stores its region into the buffer and suppose this happens before all of the other worker threads - // which are waiting to acquire the heap lock have finished their efforts to flush the buffer. If this happens, - // then the workers who are waiting to acquire the heap lock and flush the buffer will find that _recycled_region_count - // has decreased from the value it held when they last tried to increment its value. In this case, these worker - // threads will process their overflow region while holding the lock, but they will not attempt to process regions - // newly placed into the buffer. Otherwise, confusion could result. - // - // Assumption: all worker threads who are attempting to acquire lock and flush buffer will finish their efforts before - // the buffer once again overflows. - // How could we avoid depending on this assumption? - // 1. Let MaxSavedRegions be as large as number of regions, or at least as large as the collection set. - // 2. Keep a count of how many times the buffer has been flushed per instantation of the - // ShenandoahRecycleTrashedRegionClosure object, and only consult/update this value while holding the heap lock. - // Need to think about how this helps resolve the race. - _recycled_region_count = 0; - } else { - // Some other thread has already processed the buffer, resetting _recycled_region_count to zero. Its current value - // may be greater than zero because other workers may have accumulated entries into the buffer. But it is "extremely" - // unlikely that it will overflow again before all waiting workers have had a chance to clear their state. While I've - // got the heap lock, I'll go ahead and update the global state for my overflow region. I'll let other heap regions - // accumulate in the buffer to be processed when the buffer is once again full. - region_count = 0; - } - for (size_t p = 0; p < int(ShenandoahRegionPartitions::NumPartitions); p++) { - _partitions->decrease_used(ShenandoahFreeSetPartitionId(p), used_byte_tallies[p]); - } - } - public: - ShenandoahRecycleTrashedRegionClosure(ShenandoahRegionPartitions* p): ShenandoahHeapRegionClosure() { - _partitions = p; - _recycled_region_count = 0; - for (size_t i = 0; i < MaxSavedRegions; i++) { - _region_indices[i] = SentinelIndex; - _region_used[i] = SentinelUsed; - } - } - void heap_region_do(ShenandoahHeapRegion* r) { r->try_recycle(); } @@ -1950,14 +1843,12 @@ void ShenandoahFreeSet::recycle_trash() { ShenandoahHeap* heap = ShenandoahHeap::heap(); heap->assert_gc_workers(heap->workers()->active_workers()); - ShenandoahRecycleTrashedRegionClosure closure(&_partitions); + ShenandoahRecycleTrashedRegionClosure closure; heap->parallel_heap_region_iterate(&closure); } bool ShenandoahFreeSet::transfer_one_region_from_mutator_to_old_collector(size_t idx, size_t alloc_capacity) { ShenandoahGenerationalHeap* gen_heap = ShenandoahGenerationalHeap::heap(); - ShenandoahYoungGeneration* young_gen = gen_heap->young_generation(); - ShenandoahOldGeneration* old_gen = gen_heap->old_generation(); size_t region_size_bytes = ShenandoahHeapRegion::region_size_bytes(); assert(alloc_capacity == region_size_bytes, "Region must be empty"); if (young_unaffiliated_regions() > 0) { @@ -1985,7 +1876,6 @@ bool ShenandoahFreeSet::flip_to_old_gc(ShenandoahHeapRegion* r) { assert(_partitions.partition_id_matches(idx, ShenandoahFreeSetPartitionId::Mutator), "Should be in mutator view"); assert(can_allocate_from(r), "Should not be allocated"); - ShenandoahGenerationalHeap* gen_heap = ShenandoahGenerationalHeap::heap(); const size_t region_alloc_capacity = alloc_capacity(r); if (transfer_one_region_from_mutator_to_old_collector(idx, region_alloc_capacity)) { @@ -2133,7 +2023,6 @@ void ShenandoahFreeSet::find_regions_with_alloc_capacity(size_t &young_trashed_r size_t total_mutator_regions = 0; size_t total_old_collector_regions = 0; - bool is_generational = _heap->mode()->is_generational(); size_t num_regions = _heap->num_regions(); for (size_t idx = 0; idx < num_regions; idx++) { ShenandoahHeapRegion* region = _heap->get_region(idx); @@ -2222,7 +2111,6 @@ void ShenandoahFreeSet::find_regions_with_alloc_capacity(size_t &young_trashed_r } } else { assert(_partitions.membership(idx) == ShenandoahFreeSetPartitionId::NotFree, "Region should have been retired"); - size_t ac = alloc_capacity(region); size_t humongous_waste_bytes = 0; if (region->is_humongous_start()) { oop obj = cast_to_oop(region->bottom()); @@ -3120,7 +3008,6 @@ void ShenandoahFreeSet::log_status() { size_t total_used = 0; size_t total_free = 0; size_t total_free_ext = 0; - size_t total_trashed_free = 0; for (idx_t idx = _partitions.leftmost(ShenandoahFreeSetPartitionId::Mutator); idx <= _partitions.rightmost(ShenandoahFreeSetPartitionId::Mutator); idx++) { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp index 123bd792126..55d6033b3bc 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp @@ -527,7 +527,6 @@ size_t ShenandoahGeneration::select_aged_regions(const size_t old_promotion_rese assert_no_in_place_promotions(); auto const heap = ShenandoahGenerationalHeap::heap(); - ShenandoahYoungGeneration* young_gen = heap->young_generation(); ShenandoahFreeSet* free_set = heap->free_set(); bool* const candidate_regions_for_promotion_by_copy = heap->collection_set()->preselected_regions(); ShenandoahMarkingContext* const ctx = heap->marking_context(); @@ -565,7 +564,6 @@ size_t ShenandoahGeneration::select_aged_regions(const size_t old_promotion_rese size_t pip_mutator_bytes = 0; size_t pip_collector_bytes = 0; - size_t min_remnant_size = PLAB::min_size() * HeapWordSize; for (idx_t i = 0; i < num_regions; i++) { ShenandoahHeapRegion* const r = heap->get_region(i); if (r->is_empty() || !r->has_live() || !r->is_young() || !r->is_regular()) { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp index 134ae371bce..f887cc9064e 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp @@ -688,19 +688,6 @@ void ShenandoahGenerationalHeap::reset_generation_reserves() { old_generation()->set_promoted_reserve(0); } -void ShenandoahGenerationalHeap::TransferResult::print_on(const char* when, outputStream* ss) const { - auto heap = ShenandoahGenerationalHeap::heap(); - ShenandoahYoungGeneration* const young_gen = heap->young_generation(); - ShenandoahOldGeneration* const old_gen = heap->old_generation(); - const size_t young_available = young_gen->available(); - const size_t old_available = old_gen->available(); - ss->print_cr("After %s, %s %zu regions to %s to prepare for next gc, old available: " - PROPERFMT ", young_available: " PROPERFMT, - when, - success? "successfully transferred": "failed to transfer", region_count, region_destination, - PROPERFMTARGS(old_available), PROPERFMTARGS(young_available)); -} - void ShenandoahGenerationalHeap::coalesce_and_fill_old_regions(bool concurrent) { class ShenandoahGlobalCoalesceAndFill : public WorkerTask { private: diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.hpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.hpp index 704c8538397..736026916f7 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.hpp @@ -132,24 +132,12 @@ public: bool requires_barriers(stackChunkOop obj) const override; - // Used for logging the result of a region transfer outside the heap lock - struct TransferResult { - bool success; - size_t region_count; - const char* region_destination; - - void print_on(const char* when, outputStream* ss) const; - }; - // Zeros out the evacuation and promotion reserves void reset_generation_reserves(); // Computes the optimal size for the old generation, represented as a surplus or deficit of old regions void compute_old_generation_balance(size_t old_xfer_limit, size_t old_cset_regions); - // Transfers surplus old regions to young, or takes regions from young to satisfy old region deficit - TransferResult balance_generations(); - // Balances generations, coalesces and fills old regions if necessary void complete_degenerated_cycle(); void complete_concurrent_cycle(); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.inline.hpp index 636f65e2553..4feeed815da 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.inline.hpp @@ -157,7 +157,7 @@ inline void ShenandoahHeapRegion::increase_live_data_gc_words(size_t s) { } inline void ShenandoahHeapRegion::internal_increase_live_data(size_t s) { - size_t new_live_data = AtomicAccess::add(&_live_data, s, memory_order_relaxed); + AtomicAccess::add(&_live_data, s, memory_order_relaxed); } inline void ShenandoahHeapRegion::clear_live_data() { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahRegulatorThread.hpp b/src/hotspot/share/gc/shenandoah/shenandoahRegulatorThread.hpp index c23690b15d6..2519025b6fb 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahRegulatorThread.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahRegulatorThread.hpp @@ -62,7 +62,6 @@ class ShenandoahRegulatorThread: public ConcurrentGCThread { bool start_old_cycle() const; bool start_young_cycle() const; bool start_global_cycle() const; - bool resume_old_cycle(); // The generational mode can only unload classes in a global cycle. The regulator // thread itself will trigger a global cycle if metaspace is out of memory. diff --git a/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.hpp b/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.hpp index 9a0d28d2cb7..c758873a040 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.hpp @@ -233,8 +233,6 @@ public: inline bool is_write_card_dirty(size_t card_index) const; inline void mark_card_as_dirty(size_t card_index); inline void mark_range_as_dirty(size_t card_index, size_t num_cards); - inline void mark_card_as_clean(size_t card_index); - inline void mark_range_as_clean(size_t card_index, size_t num_cards); inline bool is_card_dirty(HeapWord* p) const; inline bool is_write_card_dirty(HeapWord* p) const; inline void mark_card_as_dirty(HeapWord* p); From 4856344668042fcbc4d15966519d27fb0a4f509f Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Thu, 4 Dec 2025 00:21:53 +0000 Subject: [PATCH 156/706] 8371046: Segfault in compiler/whitebox/StressNMethodRelocation.java with -XX:+UseZGC Reviewed-by: kvn, eastigeevich --- src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp | 2 +- src/hotspot/share/asm/codeBuffer.cpp | 2 +- src/hotspot/share/asm/codeBuffer.hpp | 2 +- src/hotspot/share/code/nmethod.cpp | 57 ++++++++++++------- src/hotspot/share/code/nmethod.hpp | 3 + src/hotspot/share/jvmci/vmStructs_jvmci.cpp | 1 + src/hotspot/share/prims/whitebox.cpp | 2 +- 7 files changed, 43 insertions(+), 26 deletions(-) diff --git a/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp b/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp index 94694b58d2f..dbec2d76d4f 100644 --- a/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp @@ -85,7 +85,7 @@ void Relocation::pd_set_call_destination(address x) { } else { MacroAssembler::pd_patch_instruction(addr(), x); } - assert(pd_call_destination(addr()) == x, "fail in reloc"); + guarantee(pd_call_destination(addr()) == x, "fail in reloc"); } void trampoline_stub_Relocation::pd_fix_owner_after_move() { diff --git a/src/hotspot/share/asm/codeBuffer.cpp b/src/hotspot/share/asm/codeBuffer.cpp index 2c6b7d7e96e..7871134e923 100644 --- a/src/hotspot/share/asm/codeBuffer.cpp +++ b/src/hotspot/share/asm/codeBuffer.cpp @@ -90,7 +90,7 @@ typedef CodeBuffer::csize_t csize_t; // file-local definition // External buffer, in a predefined CodeBlob. // Important: The code_start must be taken exactly, and not realigned. -CodeBuffer::CodeBuffer(CodeBlob* blob) DEBUG_ONLY(: Scrubber(this, sizeof(*this))) { +CodeBuffer::CodeBuffer(const CodeBlob* blob) DEBUG_ONLY(: Scrubber(this, sizeof(*this))) { // Provide code buffer with meaningful name initialize_misc(blob->name()); initialize(blob->content_begin(), blob->content_size()); diff --git a/src/hotspot/share/asm/codeBuffer.hpp b/src/hotspot/share/asm/codeBuffer.hpp index 430d4949467..38e151273da 100644 --- a/src/hotspot/share/asm/codeBuffer.hpp +++ b/src/hotspot/share/asm/codeBuffer.hpp @@ -672,7 +672,7 @@ class CodeBuffer: public StackObj DEBUG_ONLY(COMMA private Scrubber) { } // (2) CodeBuffer referring to pre-allocated CodeBlob. - CodeBuffer(CodeBlob* blob); + CodeBuffer(const CodeBlob* blob); // (3) code buffer allocating codeBlob memory for code & relocation // info but with lazy initialization. The name must be something diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index c2f8b46f00e..edfca5c98ee 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1498,6 +1498,40 @@ nmethod::nmethod(const nmethod &nm) : CodeBlob(nm._name, nm._kind, nm._size, nm. // - OOP table memcpy(consts_begin(), nm.consts_begin(), nm.data_end() - nm.consts_begin()); + // Fix relocation + RelocIterator iter(this); + CodeBuffer src(&nm); + CodeBuffer dst(this); + while (iter.next()) { +#ifdef USE_TRAMPOLINE_STUB_FIX_OWNER + // After an nmethod is moved, some direct call sites may end up out of range. + // CallRelocation::fix_relocation_after_move() assumes the target is always + // reachable and does not check branch range. Calling it without range checks + // could cause us to write an offset too large for the instruction. + // + // If a call site has a trampoline, we skip the normal call relocation. The + // associated trampoline_stub_Relocation will handle the call and the + // trampoline, including range checks and updating the branch as needed. + // + // If no trampoline exists, we can assume the call target is always + // reachable and therefore within direct branch range, so calling + // CallRelocation::fix_relocation_after_move() is safe. + if (iter.reloc()->is_call()) { + address trampoline = trampoline_stub_Relocation::get_trampoline_for(iter.reloc()->addr(), this); + if (trampoline != nullptr) { + continue; + } + } +#endif + + iter.reloc()->fix_relocation_after_move(&src, &dst); + } + + { + MutexLocker ml(NMethodState_lock, Mutex::_no_safepoint_check_flag); + clear_inline_caches(); + } + post_init(); } @@ -1521,25 +1555,6 @@ nmethod* nmethod::relocate(CodeBlobType code_blob_type) { return nullptr; } - // Fix relocation - RelocIterator iter(nm_copy); - CodeBuffer src(this); - CodeBuffer dst(nm_copy); - while (iter.next()) { -#ifdef USE_TRAMPOLINE_STUB_FIX_OWNER - // Direct calls may no longer be in range and the use of a trampoline may now be required. - // Instead, allow trampoline relocations to update their owners and perform the necessary checks. - if (iter.reloc()->is_call()) { - address trampoline = trampoline_stub_Relocation::get_trampoline_for(iter.reloc()->addr(), nm_copy); - if (trampoline != nullptr) { - continue; - } - } -#endif - - iter.reloc()->fix_relocation_after_move(&src, &dst); - } - // To make dependency checking during class loading fast, record // the nmethod dependencies in the classes it is dependent on. // This allows the dependency checking code to simply walk the @@ -1569,8 +1584,6 @@ nmethod* nmethod::relocate(CodeBlobType code_blob_type) { if (!is_marked_for_deoptimization() && is_in_use()) { assert(method() != nullptr && method()->code() == this, "should be if is in use"); - nm_copy->clear_inline_caches(); - // Attempt to start using the copy if (nm_copy->make_in_use()) { ICache::invalidate_range(nm_copy->code_begin(), nm_copy->code_size()); @@ -1578,7 +1591,7 @@ nmethod* nmethod::relocate(CodeBlobType code_blob_type) { methodHandle mh(Thread::current(), nm_copy->method()); nm_copy->method()->set_code(mh, nm_copy); - make_not_used(); + make_not_entrant(InvalidationReason::RELOCATED); nm_copy->post_compiled_method_load_event(); diff --git a/src/hotspot/share/code/nmethod.hpp b/src/hotspot/share/code/nmethod.hpp index 0fa9d7fda9e..2391bc6d830 100644 --- a/src/hotspot/share/code/nmethod.hpp +++ b/src/hotspot/share/code/nmethod.hpp @@ -499,6 +499,7 @@ public: UNCOMMON_TRAP, WHITEBOX_DEOPTIMIZATION, ZOMBIE, + RELOCATED, INVALIDATION_REASONS_COUNT }; @@ -543,6 +544,8 @@ public: return "whitebox deoptimization"; case InvalidationReason::ZOMBIE: return "zombie"; + case InvalidationReason::RELOCATED: + return "relocated"; default: { assert(false, "Unhandled reason"); return "Unknown"; diff --git a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp index 7f009eba5f1..77e98db9156 100644 --- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp +++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp @@ -586,6 +586,7 @@ declare_constant(nmethod::InvalidationReason::UNCOMMON_TRAP) \ declare_constant(nmethod::InvalidationReason::WHITEBOX_DEOPTIMIZATION) \ declare_constant(nmethod::InvalidationReason::ZOMBIE) \ + declare_constant(nmethod::InvalidationReason::RELOCATED) \ \ declare_constant(CodeInstaller::VERIFIED_ENTRY) \ declare_constant(CodeInstaller::UNVERIFIED_ENTRY) \ diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index 5514f7d3260..bbd7b4bf795 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -1678,7 +1678,7 @@ WB_ENTRY(void, WB_RelocateNMethodFromAddr(JNIEnv* env, jobject o, jlong addr, ji CodeBlob* blob = CodeCache::find_blob(address); if (blob != nullptr && blob->is_nmethod()) { nmethod* code = blob->as_nmethod(); - if (code->is_in_use()) { + if (code->is_in_use() && !code->is_unloading()) { CompiledICLocker ic_locker(code); code->relocate(static_cast(blob_type)); } From 04c0f8d359a3f450ac2070c6d41834145d9c75f7 Mon Sep 17 00:00:00 2001 From: Jaikiran Pai Date: Thu, 4 Dec 2025 01:36:54 +0000 Subject: [PATCH 157/706] 8372857: Improve debuggability of java/rmi/server/RemoteServer/AddrInUse.java test Reviewed-by: msheppar, smarks, syan --- .../rmi/server/RemoteServer/AddrInUse.java | 96 +++++++------------ 1 file changed, 37 insertions(+), 59 deletions(-) diff --git a/test/jdk/java/rmi/server/RemoteServer/AddrInUse.java b/test/jdk/java/rmi/server/RemoteServer/AddrInUse.java index 34e343b6193..86ac5b0313b 100644 --- a/test/jdk/java/rmi/server/RemoteServer/AddrInUse.java +++ b/test/jdk/java/rmi/server/RemoteServer/AddrInUse.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, 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,7 +24,6 @@ /* @test * @bug 4111507 * @summary retryServerSocket should not retry on BindException - * @author Ann Wollrath * * @run main/othervm AddrInUse */ @@ -33,75 +32,54 @@ import java.net.ServerSocket; import java.rmi.registry.LocateRegistry; import java.rmi.server.ExportException; -public class AddrInUse implements Runnable { +public class AddrInUse { - private static int port = -1; - private static final long TIMEOUT = 10000; - - private boolean exportSucceeded = false; - private Throwable exportException = null; - - public void run() { - - /* - * Attempt to create (i.e. export) a registry on the port that - * has already been bound, and record the result. - */ - try { - LocateRegistry.createRegistry(port); - synchronized (this) { - exportSucceeded = true; - notifyAll(); - } - } catch (Throwable t) { - synchronized (this) { - exportException = t; - notifyAll(); - } - } - } + private static volatile Throwable registryExportFailure = null; public static void main(String[] args) throws Exception { - System.err.println("\nRegression test for bug 4111507\n"); - /* * Bind a server socket to a port. */ - ServerSocket server = new ServerSocket(0); - port = server.getLocalPort(); - System.err.println("Created a ServerSocket on port " + port + "..."); - - /* - * Start a thread that creates a registry on the same port, - * and analyze the result. - */ - System.err.println("create a registry on the same port..."); - System.err.println("(should cause an ExportException)"); - AddrInUse obj = new AddrInUse(); - synchronized (obj) { - (new Thread(obj, "AddrInUse")).start(); + try (ServerSocket server = new ServerSocket(0)) { + int port = server.getLocalPort(); + System.err.println("Created a ServerSocket on port " + port + "..."); /* - * Don't wait forever (original bug is that the export - * hangs). + * Start a thread that creates a registry on the same port, + * and analyze the result. */ - obj.wait(TIMEOUT); + System.err.println("create a registry on the same port..."); + System.err.println("(should cause an ExportException)"); - if (obj.exportSucceeded) { - throw new RuntimeException( - "TEST FAILED: export on already-bound port succeeded"); - } else if (obj.exportException != null) { - obj.exportException.printStackTrace(); - if (obj.exportException instanceof ExportException) { - System.err.println("TEST PASSED"); - } else { - throw new RuntimeException( - "TEST FAILED: unexpected exception occurred", - obj.exportException); + Thread exportRegistryThread = new Thread(() -> { + /* + * Attempt to create (i.e. export) a registry on the port that + * has already been bound, and record the result. + */ + try { + LocateRegistry.createRegistry(port); + } catch (Throwable t) { + registryExportFailure = t; } - } else { - throw new RuntimeException("TEST FAILED: export timed out"); + }, "ExportRegistry-Thread"); + + exportRegistryThread.start(); + + /* + * Wait for the LocateRegistry.createRegistry() call to complete or + * if it blocks forever (due to the original bug), then let jtreg fail + * the test with a timeout + */ + exportRegistryThread.join(); + if (registryExportFailure == null) { + throw new RuntimeException( + "TEST FAILED: export on already-bound port succeeded"); } + if (!(registryExportFailure instanceof ExportException)) { + throw new RuntimeException( + "TEST FAILED: unexpected exception occurred", registryExportFailure); + } + System.err.println("TEST PASSED, received expected exception: " + registryExportFailure); } } } From db2cd1a4e0ee7b72339e7ee3c0286dc04fc5adbf Mon Sep 17 00:00:00 2001 From: Alexander Zvegintsev Date: Thu, 4 Dec 2025 02:15:54 +0000 Subject: [PATCH 158/706] 8372756: Mouse additional buttons and horizontal scrolling are broken on XWayland GNOME >= 47 after JDK-8351907 Reviewed-by: prr --- .../unix/classes/sun/awt/X11/XToolkit.java | 25 +++++++------------ 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java b/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java index eab0817af23..78cd4a7e57d 100644 --- a/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java +++ b/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java @@ -138,8 +138,6 @@ import sun.awt.X11GraphicsDevice; import sun.awt.X11GraphicsEnvironment; import sun.awt.XSettings; import sun.awt.datatransfer.DataTransferer; -import sun.awt.screencast.ScreencastHelper; -import sun.awt.screencast.XdgDesktopPortal; import sun.awt.util.PerformanceLogger; import sun.awt.util.ThreadGroupUtils; import sun.font.FontConfigManager; @@ -1523,21 +1521,16 @@ public final class XToolkit extends UNIXToolkit implements Runnable { awtLock(); try { if (numberOfButtons == 0) { - if (XdgDesktopPortal.isRemoteDesktop() - && ScreencastHelper.isAvailable()) { + numberOfButtons = getNumberOfButtonsImpl(); + numberOfButtons = (numberOfButtons > MAX_BUTTONS_SUPPORTED) ? MAX_BUTTONS_SUPPORTED : numberOfButtons; + //4th and 5th buttons are for wheel and shouldn't be reported as buttons. + //If we have more than 3 physical buttons and a wheel, we report N-2 buttons. + //If we have 3 physical buttons and a wheel, we report 3 buttons. + //If we have 1,2,3 physical buttons, we report it as is i.e. 1,2 or 3 respectively. + if (numberOfButtons >= 5) { + numberOfButtons -= 2; + } else if (numberOfButtons == 4 || numberOfButtons == 5) { numberOfButtons = 3; - } else { - numberOfButtons = getNumberOfButtonsImpl(); - numberOfButtons = (numberOfButtons > MAX_BUTTONS_SUPPORTED) ? MAX_BUTTONS_SUPPORTED : numberOfButtons; - //4th and 5th buttons are for wheel and shouldn't be reported as buttons. - //If we have more than 3 physical buttons and a wheel, we report N-2 buttons. - //If we have 3 physical buttons and a wheel, we report 3 buttons. - //If we have 1,2,3 physical buttons, we report it as is i.e. 1,2 or 3 respectively. - if (numberOfButtons >= 5) { - numberOfButtons -= 2; - } else if (numberOfButtons == 4 || numberOfButtons == 5) { - numberOfButtons = 3; - } } } //Assume don't have to re-query the number again and again. From 019df4d89c8a0fe2b27c6ec074499445ae45bc3f Mon Sep 17 00:00:00 2001 From: Dmitry Drobotov Date: Thu, 4 Dec 2025 03:22:42 +0000 Subject: [PATCH 159/706] 8372757: MacOS, Accessibility: Crash in [MenuAccessibility accessibilityChildren] after JDK-8341311 Reviewed-by: azvegint, psadhukhan --- .../macosx/native/libawt_lwawt/awt/a11y/MenuAccessibility.m | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/MenuAccessibility.m b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/MenuAccessibility.m index 90a147aa5a2..14b7ee8c6b5 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/MenuAccessibility.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/MenuAccessibility.m @@ -68,6 +68,11 @@ static jclass sjc_CAccessibility = NULL; sjm_getCurrentAccessiblePopupMenu, fAccessible, fComponent); + CHECK_EXCEPTION(); + if (axComponent == nil) { + return nil; + } + CommonComponentAccessibility *currentElement = [CommonComponentAccessibility createWithAccessible:axComponent withEnv:env withView:self->fView isCurrent:YES]; From dbf0742bf205ec57477373ebd43016383f7e7791 Mon Sep 17 00:00:00 2001 From: Ashutosh Mehra Date: Thu, 4 Dec 2025 05:03:07 +0000 Subject: [PATCH 160/706] 8373046: Method::get_c2i_unverified_entry() and get_c2i_no_clinit_check_entry() are missing check for abstract method Reviewed-by: kvn, vlivanov --- src/hotspot/share/oops/method.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/hotspot/share/oops/method.cpp b/src/hotspot/share/oops/method.cpp index cb1c8ea37e8..1a2e5f0bee4 100644 --- a/src/hotspot/share/oops/method.cpp +++ b/src/hotspot/share/oops/method.cpp @@ -168,11 +168,17 @@ address Method::get_c2i_entry() { } address Method::get_c2i_unverified_entry() { + if (is_abstract()) { + return SharedRuntime::get_handle_wrong_method_abstract_stub(); + } assert(adapter() != nullptr, "must have"); return adapter()->get_c2i_unverified_entry(); } address Method::get_c2i_no_clinit_check_entry() { + if (is_abstract()) { + return nullptr; + } assert(VM_Version::supports_fast_class_init_checks(), ""); assert(adapter() != nullptr, "must have"); return adapter()->get_c2i_no_clinit_check_entry(); From 828498c54b3b1089af9e076cb45f3cf3bea58e2f Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Thu, 4 Dec 2025 07:34:43 +0000 Subject: [PATCH 161/706] 8371978: tools/jar/ReproducibleJar.java fails on XFS Reviewed-by: jpai --- test/jdk/tools/jar/ReproducibleJar.java | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/test/jdk/tools/jar/ReproducibleJar.java b/test/jdk/tools/jar/ReproducibleJar.java index ed5e2ed2ae3..5f59d1cbe41 100644 --- a/test/jdk/tools/jar/ReproducibleJar.java +++ b/test/jdk/tools/jar/ReproducibleJar.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, 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 @@ -66,7 +66,9 @@ public class ReproducibleJar { private static final TimeZone TZ = TimeZone.getDefault(); private static final boolean DST = TZ.inDaylightTime(new Date()); private static final String UNIX_2038_ROLLOVER_TIME = "2038-01-19T03:14:07Z"; + private static final String UNIX_EPOCH_TIME = "1970-01-01T00:00:00Z"; private static final Instant UNIX_2038_ROLLOVER = Instant.parse(UNIX_2038_ROLLOVER_TIME); + private static final Instant UNIX_EPOCH = Instant.parse(UNIX_EPOCH_TIME); private static final File DIR_OUTER = new File("outer"); private static final File DIR_INNER = new File(DIR_OUTER, "inner"); private static final File FILE_INNER = new File(DIR_INNER, "foo.txt"); @@ -231,12 +233,15 @@ public class ReproducibleJar { if (Math.abs(now - original) > PRECISION) { // If original time is after UNIX 2038 32bit rollover - // and the now time is exactly the rollover time, then assume + // and the now time is exactly the rollover time or UNIX epoch time, then assume // running on a file system that only supports to 2038 (e.g.XFS) and pass test - if (FileTime.fromMillis(original).toInstant().isAfter(UNIX_2038_ROLLOVER) && - FileTime.fromMillis(now).toInstant().equals(UNIX_2038_ROLLOVER)) { - System.out.println("Checking file time after Unix 2038 rollover," + - " and extracted file time is " + UNIX_2038_ROLLOVER_TIME + ", " + + Instant originalInstant = FileTime.fromMillis(original).toInstant(); + Instant nowInstant = FileTime.fromMillis(now).toInstant(); + if (originalInstant.isAfter(UNIX_2038_ROLLOVER) && + (nowInstant.equals(UNIX_2038_ROLLOVER) || + nowInstant.equals(UNIX_EPOCH))) { + System.out.println("Checking file time after Unix 2038 rollover," + + " and extracted file time is " + nowInstant + ", " + " Assuming restricted file system, pass file time check."); } else { throw new AssertionError("checkFileTime failed," + From 63a10e0099111d69b167abf99d1a00084c4d6c1e Mon Sep 17 00:00:00 2001 From: Erik Gahlin Date: Thu, 4 Dec 2025 08:01:17 +0000 Subject: [PATCH 162/706] 8373024: JFR: CPU throttle rate can't handle incorrect values Reviewed-by: mgronlun --- .../share/classes/jdk/jfr/internal/PlatformEventType.java | 3 ++- .../classes/jdk/jfr/internal/settings/CPUThrottleSetting.java | 2 +- src/jdk.jfr/share/classes/jdk/jfr/internal/util/Rate.java | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformEventType.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformEventType.java index eaba86e6327..1180ebd6ea2 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformEventType.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformEventType.java @@ -34,6 +34,7 @@ import jdk.jfr.internal.periodic.PeriodicEvents; import jdk.jfr.internal.util.ImplicitFields; import jdk.jfr.internal.util.TimespanRate; import jdk.jfr.internal.util.Utils; +import jdk.jfr.internal.settings.CPUThrottleSetting; import jdk.jfr.internal.settings.Throttler; import jdk.jfr.internal.tracing.Modification; @@ -60,7 +61,7 @@ public final class PlatformEventType extends Type { private boolean stackTraceEnabled = true; private long thresholdTicks = 0; private long period = 0; - private TimespanRate cpuRate; + private TimespanRate cpuRate = TimespanRate.of(CPUThrottleSetting.DEFAULT_VALUE); private boolean hasHook; private boolean beginChunk; diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/CPUThrottleSetting.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/CPUThrottleSetting.java index 944827f6d6f..7ea0ace21bb 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/CPUThrottleSetting.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/CPUThrottleSetting.java @@ -65,7 +65,7 @@ public final class CPUThrottleSetting extends SettingControl { } } } - return Objects.requireNonNullElse(highestRate.toString(), DEFAULT_VALUE); + return highestRate == null ? DEFAULT_VALUE : highestRate.toString(); } @Override diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/util/Rate.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/util/Rate.java index 2632cd63848..0a7b14965cb 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/util/Rate.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/util/Rate.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, 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 @@ public record Rate(long amount, TimespanUnit unit) { String value = splitted[0].strip(); String unit = splitted[1].strip(); TimespanUnit tu = TimespanUnit.fromText(unit); - if (unit == null) { + if (tu == null) { return null; } try { From 771253e285c48329a9b45dfaaa852b64e74b31d4 Mon Sep 17 00:00:00 2001 From: Frederic Thevenet Date: Thu, 4 Dec 2025 08:23:33 +0000 Subject: [PATCH 163/706] 8372802: PrintFlagsFinal should also print locked flags Reviewed-by: dholmes, stuefe, lmesnik --- src/hotspot/share/runtime/flags/jvmFlag.cpp | 2 +- .../runtime/CommandLine/PrintAllFlags.java | 69 +++++++++++++++++++ 2 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 test/hotspot/jtreg/runtime/CommandLine/PrintAllFlags.java diff --git a/src/hotspot/share/runtime/flags/jvmFlag.cpp b/src/hotspot/share/runtime/flags/jvmFlag.cpp index 51517fa49db..405b47e1813 100644 --- a/src/hotspot/share/runtime/flags/jvmFlag.cpp +++ b/src/hotspot/share/runtime/flags/jvmFlag.cpp @@ -711,7 +711,7 @@ void JVMFlag::printFlags(outputStream* out, bool withComments, bool printRanges, for (size_t i = 0; i < length; i++) { const bool skip = (skipDefaults && flagTable[i].is_default()); const bool visited = iteratorMarkers.at(i); - if (!visited && flagTable[i].is_unlocked() && !skip) { + if (!visited && !skip) { if ((bestFlag == nullptr) || (strcmp(bestFlag->name(), flagTable[i].name()) > 0)) { bestFlag = &flagTable[i]; bestFlagIndex = i; diff --git a/test/hotspot/jtreg/runtime/CommandLine/PrintAllFlags.java b/test/hotspot/jtreg/runtime/CommandLine/PrintAllFlags.java new file mode 100644 index 00000000000..13b0dd70d4e --- /dev/null +++ b/test/hotspot/jtreg/runtime/CommandLine/PrintAllFlags.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2025, IBM Corporation. + * 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 8372802 + * @summary Test that +PrintFlagsFinal print the same options when +UnlockExperimentalVMOptions and + * +UnlockDiagnosticVMOptions are set than when they aren't. + * @requires vm.flagless + * @library /test/lib + * @run driver PrintAllFlags + */ + +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.process.OutputAnalyzer; + +import java.io.IOException; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +public class PrintAllFlags { + private static final Pattern optPattern = Pattern.compile("\\s*\\w+\\s\\w+\\s+="); + + public static void main(String args[]) throws Exception { + var flagsFinal = runAndMakeVMOptionSet("-XX:+PrintFlagsFinal", "-version"); + var flagsFinalUnlocked = runAndMakeVMOptionSet( + "-XX:+UnlockExperimentalVMOptions", "-XX:+UnlockDiagnosticVMOptions", "-XX:+PrintFlagsFinal", "-version"); + if (!flagsFinal.equals(flagsFinalUnlocked)) { + throw new RuntimeException("+PrintFlagsFinal should produce the same output" + + " whether or not UnlockExperimentalVMOptions and UnlockDiagnosticVMOptions are set"); + } + } + + private static Set runAndMakeVMOptionSet(String... args) throws IOException { + var output = new OutputAnalyzer(ProcessTools.createLimitedTestJavaProcessBuilder(args).start()); + Set optNameSet = output.asLines().stream() + .map(optPattern::matcher) + .filter(Matcher::find) + .map(Matcher::group) + .collect(Collectors.toSet()); + if (optNameSet.isEmpty()) { + throw new RuntimeException("Sanity test failed: no match for option pattern in process output"); + } + return optNameSet; + } + +} From bb867ed23e2d6394d7e7dab55cf2122889fdf3ac Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Thu, 4 Dec 2025 08:32:00 +0000 Subject: [PATCH 164/706] 8372938: Fix reference to DeferredStatic in HotSpot Style Guide Reviewed-by: stefank, jsjolen --- doc/hotspot-style.html | 4 ++-- doc/hotspot-style.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/hotspot-style.html b/doc/hotspot-style.html index a2ffb57e5a3..362245cd00a 100644 --- a/doc/hotspot-style.html +++ b/doc/hotspot-style.html @@ -1037,8 +1037,8 @@ running destructors at exit can lead to problems.

    Some of the approaches used in HotSpot to avoid dynamic initialization include:

      -
    • Use the Deferred<T> class template. Add a call -to its initialization function at an appropriate place during VM +

    • Use the DeferredStatic<T> class template. Add +a call to its initialization function at an appropriate place during VM initialization. The underlying object is never destroyed.

    • For objects of class type, use a variable whose value is a pointer to the class, initialized to nullptr. Provide an diff --git a/doc/hotspot-style.md b/doc/hotspot-style.md index c8f0f72b814..26549e3ca02 100644 --- a/doc/hotspot-style.md +++ b/doc/hotspot-style.md @@ -954,7 +954,7 @@ destructors at exit can lead to problems. Some of the approaches used in HotSpot to avoid dynamic initialization include: -* Use the `Deferred` class template. Add a call to its initialization +* Use the `DeferredStatic` class template. Add a call to its initialization function at an appropriate place during VM initialization. The underlying object is never destroyed. From 317daa3c004fbb1738e0af6acfbaf50c403c8230 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Thu, 4 Dec 2025 08:36:00 +0000 Subject: [PATCH 165/706] 8372643: Warning message on macos when building the JDK - (arm64) /tmp/lto.o unable to open object file: No such file or directory Reviewed-by: erikj --- make/common/native/Flags.gmk | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/make/common/native/Flags.gmk b/make/common/native/Flags.gmk index 843701cb4db..efb4c08e74c 100644 --- a/make/common/native/Flags.gmk +++ b/make/common/native/Flags.gmk @@ -229,6 +229,11 @@ define SetupLinkerFlags # TOOLCHAIN_TYPE plus OPENJDK_TARGET_OS ifeq ($$($1_LINK_TIME_OPTIMIZATION), true) $1_EXTRA_LDFLAGS += $(LDFLAGS_LTO) + # Instruct the ld64 linker not to delete the temporary object file + # generated during Link Time Optimization + ifeq ($(call isTargetOs, macosx), true) + $1_EXTRA_LDFLAGS += -Wl,-object_path_lto,$$($1_OBJECT_DIR)/$$($1_NAME)_lto_helper.o + endif endif $1_EXTRA_LDFLAGS += $$($1_LDFLAGS_$(OPENJDK_TARGET_OS_TYPE)) $$($1_LDFLAGS_$(OPENJDK_TARGET_OS)) \ From 14000a25e6efcbe55171d4cc8c68170a8cf0406f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20Sikstr=C3=B6m?= Date: Thu, 4 Dec 2025 09:37:56 +0000 Subject: [PATCH 166/706] 8373080: Parallel: gc/arguments/TestMinInitialErgonomics.java should not be run with Large Pages Reviewed-by: ayang, aboldtch --- test/hotspot/jtreg/gc/arguments/TestMinInitialErgonomics.java | 1 + 1 file changed, 1 insertion(+) diff --git a/test/hotspot/jtreg/gc/arguments/TestMinInitialErgonomics.java b/test/hotspot/jtreg/gc/arguments/TestMinInitialErgonomics.java index 6912499e53f..38eb07139bd 100644 --- a/test/hotspot/jtreg/gc/arguments/TestMinInitialErgonomics.java +++ b/test/hotspot/jtreg/gc/arguments/TestMinInitialErgonomics.java @@ -28,6 +28,7 @@ package gc.arguments; * @bug 8006088 * @requires vm.gc.Parallel * @requires vm.compMode != "Xcomp" + * @requires !vm.opt.final.UseLargePages * @summary Test Parallel GC ergonomics decisions related to minimum and initial heap size. * @library /test/lib * @library / From 16699a394d4d6c2b8a21e7de3c3d344c5a3309b4 Mon Sep 17 00:00:00 2001 From: Volkan Yazici Date: Thu, 4 Dec 2025 09:40:31 +0000 Subject: [PATCH 167/706] 8208693: HttpClient: Extend the request timeout's scope to cover the response body Reviewed-by: jpai, dfuchs --- .../classes/java/net/http/HttpClient.java | 12 + .../classes/java/net/http/HttpRequest.java | 20 +- .../classes/java/net/http/WebSocket.java | 12 +- .../jdk/internal/net/http/ExchangeImpl.java | 12 + .../jdk/internal/net/http/Http1Exchange.java | 24 +- .../internal/net/http/Http3ExchangeImpl.java | 20 +- .../jdk/internal/net/http/HttpClientImpl.java | 7 + .../jdk/internal/net/http/MultiExchange.java | 17 +- .../classes/jdk/internal/net/http/Stream.java | 25 +- .../common/HttpBodySubscriberWrapper.java | 19 +- .../httpclient/TimeoutResponseBodyTest.java | 285 ++++++++++++ .../httpclient/TimeoutResponseHeaderTest.java | 138 ++++++ .../TimeoutResponseTestSupport.java | 415 ++++++++++++++++++ .../net/http/HttpClientTimerAccess.java | 59 +++ .../httpclient/websocket/WebSocketTest.java | 48 +- 15 files changed, 1088 insertions(+), 25 deletions(-) create mode 100644 test/jdk/java/net/httpclient/TimeoutResponseBodyTest.java create mode 100644 test/jdk/java/net/httpclient/TimeoutResponseHeaderTest.java create mode 100644 test/jdk/java/net/httpclient/TimeoutResponseTestSupport.java create mode 100644 test/jdk/java/net/httpclient/access/java.net.http/jdk/internal/net/http/HttpClientTimerAccess.java diff --git a/src/java.net.http/share/classes/java/net/http/HttpClient.java b/src/java.net.http/share/classes/java/net/http/HttpClient.java index a7a2171857d..9ecb048342b 100644 --- a/src/java.net.http/share/classes/java/net/http/HttpClient.java +++ b/src/java.net.http/share/classes/java/net/http/HttpClient.java @@ -312,10 +312,22 @@ public abstract class HttpClient implements AutoCloseable { * need to be established, for example if a connection can be reused * from a previous request, then this timeout duration has no effect. * + * @implSpec + * A connection timeout applies to the entire connection phase, from the + * moment a connection is requested until it is established. + * Implementations are recommended to ensure that the connection timeout + * covers any SSL/TLS handshakes. + * + * @implNote + * The built-in JDK implementation of the connection timeout covers any + * SSL/TLS handshakes. + * * @param duration the duration to allow the underlying connection to be * established * @return this builder * @throws IllegalArgumentException if the duration is non-positive + * @see HttpRequest.Builder#timeout(Duration) Configuring timeout for + * request execution */ public Builder connectTimeout(Duration duration); diff --git a/src/java.net.http/share/classes/java/net/http/HttpRequest.java b/src/java.net.http/share/classes/java/net/http/HttpRequest.java index c56328ba4b4..741573e06b3 100644 --- a/src/java.net.http/share/classes/java/net/http/HttpRequest.java +++ b/src/java.net.http/share/classes/java/net/http/HttpRequest.java @@ -258,12 +258,28 @@ public abstract class HttpRequest { * {@link HttpClient#sendAsync(java.net.http.HttpRequest, * java.net.http.HttpResponse.BodyHandler) HttpClient::sendAsync} * completes exceptionally with an {@code HttpTimeoutException}. The effect - * of not setting a timeout is the same as setting an infinite Duration, - * i.e. block forever. + * of not setting a timeout is the same as setting an infinite + * {@code Duration}, i.e., block forever. + * + * @implSpec + * A timeout applies to the duration measured from the instant the + * request execution starts to, at least, the instant an + * {@link HttpResponse} is constructed. The elapsed time includes + * obtaining a connection for transport and retrieving the response + * headers. + * + * @implNote + * The JDK built-in implementation applies timeout over the duration + * measured from the instant the request execution starts to the + * instant the response body is consumed, if present. This is + * implemented by stopping the timer after the response body subscriber + * completion. * * @param duration the timeout duration * @return this builder * @throws IllegalArgumentException if the duration is non-positive + * @see HttpClient.Builder#connectTimeout(Duration) Configuring + * timeout for connection establishment */ public abstract Builder timeout(Duration duration); diff --git a/src/java.net.http/share/classes/java/net/http/WebSocket.java b/src/java.net.http/share/classes/java/net/http/WebSocket.java index 313847cf449..84fc8472eef 100644 --- a/src/java.net.http/share/classes/java/net/http/WebSocket.java +++ b/src/java.net.http/share/classes/java/net/http/WebSocket.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, 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 @@ -144,6 +144,16 @@ public interface WebSocket { * {@link HttpTimeoutException}. If this method is not invoked then the * infinite timeout is assumed. * + * @implSpec + * A connection timeout applies to the entire connection phase, from the + * moment a connection is requested until it is established. + * Implementations are recommended to ensure that the connection timeout + * covers any WebSocket and SSL/TLS handshakes. + * + * @implNote + * The built-in JDK implementation of the connection timeout covers any + * WebSocket and SSL/TLS handshakes. + * * @param timeout * the timeout, non-{@linkplain Duration#isNegative() negative}, * non-{@linkplain Duration#ZERO ZERO} diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/ExchangeImpl.java b/src/java.net.http/share/classes/jdk/internal/net/http/ExchangeImpl.java index 74600e78557..c1ed01ff07a 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/ExchangeImpl.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/ExchangeImpl.java @@ -581,6 +581,18 @@ abstract class ExchangeImpl { // Needed for HTTP/2 to subscribe a dummy subscriber and close the stream } + /** + * {@return {@code true}, if it is allowed to cancel the request timer on + * response body subscriber termination; {@code false}, otherwise} + * + * @param webSocket indicates if the associated request is a WebSocket handshake + * @param statusCode the status code of the associated response + */ + static boolean cancelTimerOnResponseBodySubscriberTermination( + boolean webSocket, int statusCode) { + return webSocket || statusCode < 100 || statusCode >= 200; + } + /* The following methods have separate HTTP/1.1 and HTTP/2 implementations */ abstract CompletableFuture> sendHeadersAsync(); diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/Http1Exchange.java b/src/java.net.http/share/classes/jdk/internal/net/http/Http1Exchange.java index 02ce63b6314..72a47eca42c 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/Http1Exchange.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/Http1Exchange.java @@ -206,8 +206,15 @@ class Http1Exchange extends ExchangeImpl { */ static final class Http1ResponseBodySubscriber extends HttpBodySubscriberWrapper { final Http1Exchange exchange; - Http1ResponseBodySubscriber(BodySubscriber userSubscriber, Http1Exchange exchange) { + + private final boolean cancelTimerOnTermination; + + Http1ResponseBodySubscriber( + BodySubscriber userSubscriber, + boolean cancelTimerOnTermination, + Http1Exchange exchange) { super(userSubscriber); + this.cancelTimerOnTermination = cancelTimerOnTermination; this.exchange = exchange; } @@ -220,6 +227,14 @@ class Http1Exchange extends ExchangeImpl { protected void unregister() { exchange.unregisterResponseSubscriber(this); } + + @Override + protected void onTermination() { + if (cancelTimerOnTermination) { + exchange.exchange.multi.cancelTimer(); + } + } + } @Override @@ -459,9 +474,10 @@ class Http1Exchange extends ExchangeImpl { @Override Http1ResponseBodySubscriber createResponseSubscriber(BodyHandler handler, ResponseInfo response) { BodySubscriber subscriber = handler.apply(response); - Http1ResponseBodySubscriber bs = - new Http1ResponseBodySubscriber(subscriber, this); - return bs; + var cancelTimerOnTermination = + cancelTimerOnResponseBodySubscriberTermination( + exchange.request().isWebSocket(), response.statusCode()); + return new Http1ResponseBodySubscriber<>(subscriber, cancelTimerOnTermination, this); } @Override diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/Http3ExchangeImpl.java b/src/java.net.http/share/classes/jdk/internal/net/http/Http3ExchangeImpl.java index 41a4a84958a..81475a47c4a 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/Http3ExchangeImpl.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/Http3ExchangeImpl.java @@ -554,8 +554,12 @@ final class Http3ExchangeImpl extends Http3Stream { } final class Http3StreamResponseSubscriber extends HttpBodySubscriberWrapper { - Http3StreamResponseSubscriber(BodySubscriber subscriber) { + + private final boolean cancelTimerOnTermination; + + Http3StreamResponseSubscriber(BodySubscriber subscriber, boolean cancelTimerOnTermination) { super(subscriber); + this.cancelTimerOnTermination = cancelTimerOnTermination; } @Override @@ -568,6 +572,13 @@ final class Http3ExchangeImpl extends Http3Stream { registerResponseSubscriber(this); } + @Override + protected void onTermination() { + if (cancelTimerOnTermination) { + exchange.multi.cancelTimer(); + } + } + @Override protected void logComplete(Throwable error) { if (error == null) { @@ -590,9 +601,10 @@ final class Http3ExchangeImpl extends Http3Stream { Http3StreamResponseSubscriber createResponseSubscriber(BodyHandler handler, ResponseInfo response) { if (debug.on()) debug.log("Creating body subscriber"); - Http3StreamResponseSubscriber subscriber = - new Http3StreamResponseSubscriber<>(handler.apply(response)); - return subscriber; + var cancelTimerOnTermination = + cancelTimerOnResponseBodySubscriberTermination( + exchange.request().isWebSocket(), response.statusCode()); + return new Http3StreamResponseSubscriber<>(handler.apply(response), cancelTimerOnTermination); } @Override diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/HttpClientImpl.java b/src/java.net.http/share/classes/jdk/internal/net/http/HttpClientImpl.java index d02930f4f31..ff130e90358 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/HttpClientImpl.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/HttpClientImpl.java @@ -1880,6 +1880,13 @@ final class HttpClientImpl extends HttpClient implements Trackable { } } + // Visible for tests + List timers() { + synchronized (this) { + return new ArrayList<>(timeouts); + } + } + /** * Purges ( handles ) timer events that have passed their deadline, and * returns the amount of time, in milliseconds, until the next earliest diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/MultiExchange.java b/src/java.net.http/share/classes/jdk/internal/net/http/MultiExchange.java index ec621f7f955..60eb55ec0ad 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/MultiExchange.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/MultiExchange.java @@ -25,7 +25,6 @@ package jdk.internal.net.http; -import java.io.IOError; import java.io.IOException; import java.lang.ref.WeakReference; import java.net.ConnectException; @@ -254,7 +253,7 @@ class MultiExchange implements Cancelable { .map(ConnectTimeoutTracker::getRemaining); } - private void cancelTimer() { + void cancelTimer() { if (responseTimerEvent != null) { client.cancelTimer(responseTimerEvent); responseTimerEvent = null; @@ -404,6 +403,8 @@ class MultiExchange implements Cancelable { processAltSvcHeader(r, client(), currentreq); Exchange exch = getExchange(); if (bodyNotPermitted(r)) { + // No response body consumption is expected, we can cancel the timer right away + cancelTimer(); if (bodyIsPresent(r)) { IOException ioe = new IOException( "unexpected content length header with 204 response"); @@ -467,6 +468,8 @@ class MultiExchange implements Cancelable { private CompletableFuture responseAsyncImpl(final boolean applyReqFilters) { if (currentreq.timeout().isPresent()) { + // Retried/Forwarded requests should reset the timer, if present + cancelTimer(); responseTimerEvent = ResponseTimerEvent.of(this); client.registerTimer(responseTimerEvent); } @@ -502,7 +505,6 @@ class MultiExchange implements Cancelable { } return completedFuture(response); } else { - cancelTimer(); setNewResponse(currentreq, response, null, exch); if (currentreq.isWebSocket()) { // need to close the connection and open a new one. @@ -520,11 +522,18 @@ class MultiExchange implements Cancelable { } }) .handle((response, ex) -> { // 5. handle errors and cancel any timer set - cancelTimer(); if (ex == null) { assert response != null; return completedFuture(response); } + + // Cancel the timer. Note that we only do so if the + // response has completed exceptionally. That is, we don't + // cancel the timer if there are no exceptions, since the + // response body might still get consumed, and it is + // still subject to the response timer. + cancelTimer(); + // all exceptions thrown are handled here final RetryContext retryCtx = checkRetryEligible(ex, exch); assert retryCtx != null : "retry context is null"; diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/Stream.java b/src/java.net.http/share/classes/jdk/internal/net/http/Stream.java index 9a7ccd8f3a1..bf9170f8f51 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/Stream.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/Stream.java @@ -390,9 +390,10 @@ class Stream extends ExchangeImpl { @Override Http2StreamResponseSubscriber createResponseSubscriber(BodyHandler handler, ResponseInfo response) { - Http2StreamResponseSubscriber subscriber = - new Http2StreamResponseSubscriber<>(handler.apply(response)); - return subscriber; + var cancelTimerOnTermination = + cancelTimerOnResponseBodySubscriberTermination( + exchange.request().isWebSocket(), response.statusCode()); + return new Http2StreamResponseSubscriber<>(handler.apply(response), cancelTimerOnTermination); } // The Http2StreamResponseSubscriber is registered with the HttpClient @@ -1694,6 +1695,11 @@ class Stream extends ExchangeImpl { .whenComplete((v, t) -> pushGroup.pushError(t)); } + @Override + Http2StreamResponseSubscriber createResponseSubscriber(BodyHandler handler, ResponseInfo response) { + return new Http2StreamResponseSubscriber(handler.apply(response), false); + } + @Override void completeResponse(Response r) { Log.logResponse(r::toString); @@ -1924,8 +1930,12 @@ class Stream extends ExchangeImpl { } final class Http2StreamResponseSubscriber extends HttpBodySubscriberWrapper { - Http2StreamResponseSubscriber(BodySubscriber subscriber) { + + private final boolean cancelTimerOnTermination; + + Http2StreamResponseSubscriber(BodySubscriber subscriber, boolean cancelTimerOnTermination) { super(subscriber); + this.cancelTimerOnTermination = cancelTimerOnTermination; } @Override @@ -1938,6 +1948,13 @@ class Stream extends ExchangeImpl { unregisterResponseSubscriber(this); } + @Override + protected void onTermination() { + if (cancelTimerOnTermination) { + exchange.multi.cancelTimer(); + } + } + } private static final VarHandle DEREGISTERED; diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/common/HttpBodySubscriberWrapper.java b/src/java.net.http/share/classes/jdk/internal/net/http/common/HttpBodySubscriberWrapper.java index 1c483ce99f4..f1c1f6f2d2a 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/common/HttpBodySubscriberWrapper.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/common/HttpBodySubscriberWrapper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, 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.util.Objects; import java.util.concurrent.CompletionStage; import java.util.concurrent.Flow; import java.util.concurrent.Flow.Subscription; -import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.locks.ReentrantLock; @@ -51,7 +50,6 @@ public class HttpBodySubscriberWrapper implements TrustedSubscriber { public static final Comparator> COMPARE_BY_ID = Comparator.comparing(HttpBodySubscriberWrapper::id); - public static final Flow.Subscription NOP = new Flow.Subscription() { @Override public void request(long n) { } @@ -75,7 +73,18 @@ public class HttpBodySubscriberWrapper implements TrustedSubscriber { this.userSubscriber = userSubscriber; } - private class SubscriptionWrapper implements Subscription { + /** + * A callback to be invoked before termination, whether due to the + * completion or failure of the subscriber, or cancellation of the + * subscription. To be precise, this method is called before + * {@link #onComplete()}, {@link #onError(Throwable) onError()}, or + * {@link #onCancel()}. + */ + protected void onTermination() { + // Do nothing + } + + private final class SubscriptionWrapper implements Subscription { final Subscription subscription; SubscriptionWrapper(Subscription s) { this.subscription = Objects.requireNonNull(s); @@ -92,6 +101,7 @@ public class HttpBodySubscriberWrapper implements TrustedSubscriber { subscription.cancel(); } finally { if (markCancelled()) { + onTermination(); onCancel(); } } @@ -284,6 +294,7 @@ public class HttpBodySubscriberWrapper implements TrustedSubscriber { */ public final void complete(Throwable t) { if (markCompleted()) { + onTermination(); logComplete(t); tryUnregister(); t = withError = Utils.getCompletionCause(t); diff --git a/test/jdk/java/net/httpclient/TimeoutResponseBodyTest.java b/test/jdk/java/net/httpclient/TimeoutResponseBodyTest.java new file mode 100644 index 00000000000..093885a6ba0 --- /dev/null +++ b/test/jdk/java/net/httpclient/TimeoutResponseBodyTest.java @@ -0,0 +1,285 @@ +/* + * Copyright (c) 2025, 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 jdk.internal.net.http.common.Logger; +import jdk.internal.net.http.common.Utils; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import java.io.InputStream; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; + +import static jdk.internal.net.http.HttpClientTimerAccess.assertNoResponseTimerEventRegistrations; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTimeoutPreemptively; +import static org.junit.jupiter.api.Assertions.fail; + +/* + * @test id=retriesDisabled + * @bug 8208693 + * @summary Verifies `HttpRequest::timeout` is effective for *response body* + * timeouts when all retry mechanisms are disabled. + * + * @library /test/lib + * /test/jdk/java/net/httpclient/lib + * access + * @build TimeoutResponseTestSupport + * java.net.http/jdk.internal.net.http.HttpClientTimerAccess + * jdk.httpclient.test.lib.common.HttpServerAdapters + * jdk.test.lib.net.SimpleSSLContext + * + * @run junit/othervm + * -Djdk.httpclient.auth.retrylimit=0 + * -Djdk.httpclient.disableRetryConnect + * -Djdk.httpclient.redirects.retrylimit=0 + * -Dtest.requestTimeoutMillis=1000 + * TimeoutResponseBodyTest + */ + +/* + * @test id=retriesEnabledForResponseFailure + * @bug 8208693 + * @summary Verifies `HttpRequest::timeout` is effective for *response body* + * timeouts, where some initial responses are intentionally configured + * to fail to trigger retries. + * + * @library /test/lib + * /test/jdk/java/net/httpclient/lib + * access + * @build TimeoutResponseTestSupport + * java.net.http/jdk.internal.net.http.HttpClientTimerAccess + * jdk.httpclient.test.lib.common.HttpServerAdapters + * jdk.test.lib.net.SimpleSSLContext + * + * @run junit/othervm + * -Djdk.httpclient.auth.retrylimit=0 + * -Djdk.httpclient.disableRetryConnect + * -Djdk.httpclient.redirects.retrylimit=3 + * -Dtest.requestTimeoutMillis=1000 + * -Dtest.responseFailureWaitDurationMillis=600 + * TimeoutResponseBodyTest + */ + +/** + * Verifies {@link HttpRequest#timeout() HttpRequest.timeout()} is effective + * for response body timeouts. + * + * @implNote + * + * Using a response body subscriber (i.e., {@link InputStream}) of type that + * allows gradual consumption of the response body after successfully building + * an {@link HttpResponse} instance to ensure timeouts are propagated even + * after the {@code HttpResponse} construction. + *

      + * Each test is provided a pristine ephemeral client to avoid any unexpected + * effects due to pooling. + */ +class TimeoutResponseBodyTest extends TimeoutResponseTestSupport { + + private static final Logger LOGGER = Utils.getDebugLogger( + TimeoutResponseBodyTest.class.getSimpleName()::toString, Utils.DEBUG); + + /** + * Tests timeouts using + * {@link HttpClient#send(HttpRequest, HttpResponse.BodyHandler) HttpClient::send} + * against a server blocking without delivering the response body. + */ + @ParameterizedTest + @MethodSource("serverRequestPairs") + void testSendOnMissingBody(ServerRequestPair pair) throws Exception { + + ServerRequestPair.SERVER_HANDLER_BEHAVIOUR = + ServerRequestPair.ServerHandlerBehaviour.BLOCK_BEFORE_BODY_DELIVERY; + + try (var client = pair.createClientWithEstablishedConnection()) { + assertTimeoutPreemptively(REQUEST_TIMEOUT.multipliedBy(2), () -> { + LOGGER.log("Sending the request"); + var response = client.send(pair.request(), HttpResponse.BodyHandlers.ofInputStream()); + LOGGER.log("Consuming the obtained response"); + verifyResponseBodyDoesNotArrive(response); + }); + LOGGER.log("Verifying the registered response timer events"); + assertNoResponseTimerEventRegistrations(client); + } + + } + + /** + * Tests timeouts using + * {@link HttpClient#sendAsync(HttpRequest, HttpResponse.BodyHandler) HttpClient::sendAsync} + * against a server blocking without delivering the response body. + */ + @ParameterizedTest + @MethodSource("serverRequestPairs") + void testSendAsyncOnMissingBody(ServerRequestPair pair) throws Exception { + + ServerRequestPair.SERVER_HANDLER_BEHAVIOUR = + ServerRequestPair.ServerHandlerBehaviour.BLOCK_BEFORE_BODY_DELIVERY; + + try (var client = pair.createClientWithEstablishedConnection()) { + assertTimeoutPreemptively(REQUEST_TIMEOUT.multipliedBy(2), () -> { + LOGGER.log("Sending the request asynchronously"); + var responseFuture = client.sendAsync(pair.request(), HttpResponse.BodyHandlers.ofInputStream()); + LOGGER.log("Obtaining the response"); + var response = responseFuture.get(); + LOGGER.log("Consuming the obtained response"); + verifyResponseBodyDoesNotArrive(response); + }); + LOGGER.log("Verifying the registered response timer events"); + assertNoResponseTimerEventRegistrations(client); + } + + } + + private static void verifyResponseBodyDoesNotArrive(HttpResponse response) { + assertEquals(200, response.statusCode()); + assertThrowsHttpTimeoutException(() -> { + try (var responseBodyStream = response.body()) { + var readByte = responseBodyStream.read(); + fail("Unexpected read byte: " + readByte); + } + }); + } + + /** + * Tests timeouts using + * {@link HttpClient#send(HttpRequest, HttpResponse.BodyHandler) HttpClient::send} + * against a server delivering the response body very slowly. + */ + @ParameterizedTest + @MethodSource("serverRequestPairs") + void testSendOnSlowBody(ServerRequestPair pair) throws Exception { + + ServerRequestPair.SERVER_HANDLER_BEHAVIOUR = + ServerRequestPair.ServerHandlerBehaviour.DELIVER_BODY_SLOWLY; + + try (var client = pair.createClientWithEstablishedConnection()) { + assertTimeoutPreemptively(REQUEST_TIMEOUT.multipliedBy(2), () -> { + LOGGER.log("Sending the request"); + var response = client.send(pair.request(), HttpResponse.BodyHandlers.ofInputStream()); + LOGGER.log("Consuming the obtained response"); + verifyResponseBodyArrivesSlow(response); + }); + LOGGER.log("Verifying the registered response timer events"); + assertNoResponseTimerEventRegistrations(client); + } + + } + + /** + * Tests timeouts using + * {@link HttpClient#sendAsync(HttpRequest, HttpResponse.BodyHandler) HttpClient::sendAsync} + * against a server delivering the response body very slowly. + */ + @ParameterizedTest + @MethodSource("serverRequestPairs") + void testSendAsyncOnSlowBody(ServerRequestPair pair) throws Exception { + + ServerRequestPair.SERVER_HANDLER_BEHAVIOUR = + ServerRequestPair.ServerHandlerBehaviour.DELIVER_BODY_SLOWLY; + + try (var client = pair.createClientWithEstablishedConnection()) { + assertTimeoutPreemptively(REQUEST_TIMEOUT.multipliedBy(2), () -> { + LOGGER.log("Sending the request asynchronously"); + var responseFuture = client.sendAsync(pair.request(), HttpResponse.BodyHandlers.ofInputStream()); + LOGGER.log("Obtaining the response"); + var response = responseFuture.get(); + LOGGER.log("Consuming the obtained response"); + verifyResponseBodyArrivesSlow(response); + }); + LOGGER.log("Verifying the registered response timer events"); + assertNoResponseTimerEventRegistrations(client); + } + + } + + private static void verifyResponseBodyArrivesSlow(HttpResponse response) { + assertEquals(200, response.statusCode()); + assertThrowsHttpTimeoutException(() -> { + try (var responseBodyStream = response.body()) { + int i = 0; + int l = ServerRequestPair.CONTENT_LENGTH; + for (; i < l; i++) { + LOGGER.log("Reading byte %s/%s", i, l); + var readByte = responseBodyStream.read(); + if (readByte < 0) { + break; + } + assertEquals(i, readByte); + } + fail("Should not have reached here! (i=%s)".formatted(i)); + } + }); + } + + /** + * Tests timeouts using + * {@link HttpClient#send(HttpRequest, HttpResponse.BodyHandler) HttpClient::send} + * against a server delivering 204, i.e., no content, which is handled + * through a specialized path served by {@code MultiExchange::handleNoBody}. + */ + @ParameterizedTest + @MethodSource("serverRequestPairs") + void testSendOnNoBody(ServerRequestPair pair) throws Exception { + + ServerRequestPair.SERVER_HANDLER_BEHAVIOUR = + ServerRequestPair.ServerHandlerBehaviour.DELIVER_NO_BODY; + + try (var client = pair.createClientWithEstablishedConnection()) { + assertTimeoutPreemptively(REQUEST_TIMEOUT.multipliedBy(2), () -> { + LOGGER.log("Sending the request"); + client.send(pair.request(), HttpResponse.BodyHandlers.discarding()); + }); + LOGGER.log("Verifying the registered response timer events"); + assertNoResponseTimerEventRegistrations(client); + } + + } + + /** + * Tests timeouts using + * {@link HttpClient#sendAsync(HttpRequest, HttpResponse.BodyHandler) HttpClient::sendAsync} + * against a server delivering 204, i.e., no content, which is handled + * through a specialized path served by {@code MultiExchange::handleNoBody}. + */ + @ParameterizedTest + @MethodSource("serverRequestPairs") + void testSendAsyncOnNoBody(ServerRequestPair pair) throws Exception { + + ServerRequestPair.SERVER_HANDLER_BEHAVIOUR = + ServerRequestPair.ServerHandlerBehaviour.DELIVER_NO_BODY; + + try (var client = pair.createClientWithEstablishedConnection()) { + assertTimeoutPreemptively(REQUEST_TIMEOUT.multipliedBy(2), () -> { + LOGGER.log("Sending the request asynchronously"); + client.sendAsync(pair.request(), HttpResponse.BodyHandlers.discarding()).get(); + }); + LOGGER.log("Verifying the registered response timer events"); + assertNoResponseTimerEventRegistrations(client); + } + + } + +} diff --git a/test/jdk/java/net/httpclient/TimeoutResponseHeaderTest.java b/test/jdk/java/net/httpclient/TimeoutResponseHeaderTest.java new file mode 100644 index 00000000000..ab562f8eab8 --- /dev/null +++ b/test/jdk/java/net/httpclient/TimeoutResponseHeaderTest.java @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2025, 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 jdk.internal.net.http.common.Logger; +import jdk.internal.net.http.common.Utils; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; + +import static jdk.internal.net.http.HttpClientTimerAccess.assertNoResponseTimerEventRegistrations; +import static org.junit.jupiter.api.Assertions.assertTimeoutPreemptively; + +/* + * @test id=retriesDisabled + * @bug 8208693 + * @summary Verifies `HttpRequest::timeout` is effective for *response header* + * timeouts when all retry mechanisms are disabled. + * + * @library /test/jdk/java/net/httpclient/lib + * /test/lib + * access + * @build TimeoutResponseTestSupport + * java.net.http/jdk.internal.net.http.HttpClientTimerAccess + * jdk.httpclient.test.lib.common.HttpServerAdapters + * jdk.test.lib.net.SimpleSSLContext + * + * @run junit/othervm + * -Djdk.httpclient.auth.retrylimit=0 + * -Djdk.httpclient.disableRetryConnect + * -Djdk.httpclient.redirects.retrylimit=0 + * -Dtest.requestTimeoutMillis=1000 + * TimeoutResponseHeaderTest + */ + +/* + * @test id=retriesEnabledForResponseFailure + * @bug 8208693 + * @summary Verifies `HttpRequest::timeout` is effective for *response header* + * timeouts, where some initial responses are intentionally configured + * to fail to trigger retries. + * + * @library /test/jdk/java/net/httpclient/lib + * /test/lib + * access + * @build TimeoutResponseTestSupport + * java.net.http/jdk.internal.net.http.HttpClientTimerAccess + * jdk.httpclient.test.lib.common.HttpServerAdapters + * jdk.test.lib.net.SimpleSSLContext + * + * @run junit/othervm + * -Djdk.httpclient.auth.retrylimit=0 + * -Djdk.httpclient.disableRetryConnect + * -Djdk.httpclient.redirects.retrylimit=3 + * -Dtest.requestTimeoutMillis=1000 + * -Dtest.responseFailureWaitDurationMillis=600 + * TimeoutResponseHeaderTest + */ + +/** + * Verifies {@link HttpRequest#timeout() HttpRequest.timeout()} is effective + * for response header timeouts. + */ +class TimeoutResponseHeaderTest extends TimeoutResponseTestSupport { + + private static final Logger LOGGER = Utils.getDebugLogger( + TimeoutResponseHeaderTest.class.getSimpleName()::toString, Utils.DEBUG); + + static { + ServerRequestPair.SERVER_HANDLER_BEHAVIOUR = + ServerRequestPair.ServerHandlerBehaviour.BLOCK_BEFORE_HEADER_DELIVERY; + } + + /** + * Tests timeouts using + * {@link HttpClient#send(HttpRequest, HttpResponse.BodyHandler) HttpClient::send} + * against a server blocking without delivering any response headers. + */ + @ParameterizedTest + @MethodSource("serverRequestPairs") + void testSend(ServerRequestPair pair) throws Exception { + try (var client = pair.createClientWithEstablishedConnection()) { + assertTimeoutPreemptively( + REQUEST_TIMEOUT.multipliedBy(2), + () -> assertThrowsHttpTimeoutException(() -> { + LOGGER.log("Sending the request"); + client.send(pair.request(), HttpResponse.BodyHandlers.discarding()); + })); + LOGGER.log("Verifying the registered response timer events"); + assertNoResponseTimerEventRegistrations(client); + } + } + + /** + * Tests timeouts using + * {@link HttpClient#sendAsync(HttpRequest, HttpResponse.BodyHandler) HttpClient::sendAsync} + * against a server blocking without delivering any response headers. + */ + @ParameterizedTest + @MethodSource("serverRequestPairs") + void testSendAsync(ServerRequestPair pair) throws Exception { + try (var client = pair.createClientWithEstablishedConnection()) { + assertTimeoutPreemptively(REQUEST_TIMEOUT.multipliedBy(2), () -> { + LOGGER.log("Sending the request asynchronously"); + var responseFuture = client.sendAsync(pair.request(), HttpResponse.BodyHandlers.discarding()); + assertThrowsHttpTimeoutException(() -> { + LOGGER.log("Obtaining the response"); + responseFuture.get(); + }); + }); + LOGGER.log("Verifying the registered response timer events"); + assertNoResponseTimerEventRegistrations(client); + } + } + +} diff --git a/test/jdk/java/net/httpclient/TimeoutResponseTestSupport.java b/test/jdk/java/net/httpclient/TimeoutResponseTestSupport.java new file mode 100644 index 00000000000..4da63a2dff9 --- /dev/null +++ b/test/jdk/java/net/httpclient/TimeoutResponseTestSupport.java @@ -0,0 +1,415 @@ +/* + * Copyright (c) 2025, 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 jdk.httpclient.test.lib.common.HttpServerAdapters.HttpTestExchange; +import jdk.httpclient.test.lib.common.HttpServerAdapters.HttpTestHandler; +import jdk.httpclient.test.lib.common.HttpServerAdapters.HttpTestServer; +import jdk.internal.net.http.common.Logger; +import jdk.internal.net.http.common.Utils; +import jdk.internal.net.http.frame.ErrorFrame; +import jdk.internal.net.http.http3.Http3Error; +import jdk.test.lib.net.SimpleSSLContext; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.function.Executable; + +import javax.net.ssl.SSLContext; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpClient.Version; +import java.net.http.HttpOption; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.net.http.HttpTimeoutException; +import java.time.Duration; +import java.util.Map; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Stream; + +import static java.net.http.HttpClient.Builder.NO_PROXY; +import static java.net.http.HttpOption.Http3DiscoveryMode.HTTP_3_URI_ONLY; +import static jdk.httpclient.test.lib.common.HttpServerAdapters.createClientBuilderFor; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * Utilities for {@code TimeoutResponse*Test}s. + * + * @see TimeoutResponseBodyTest Server response body timeout tests + * @see TimeoutResponseHeaderTest Server response header timeout tests + * @see TimeoutBasic Server connection timeout tests + */ +public class TimeoutResponseTestSupport { + + private static final String CLASS_NAME = TimeoutResponseTestSupport.class.getSimpleName(); + + private static final Logger LOGGER = Utils.getDebugLogger(CLASS_NAME::toString, Utils.DEBUG); + + private static final SSLContext SSL_CONTEXT = createSslContext(); + + protected static final Duration REQUEST_TIMEOUT = + Duration.ofMillis(Long.parseLong(System.getProperty("test.requestTimeoutMillis"))); + + static { + assertTrue( + REQUEST_TIMEOUT.isPositive(), + "was expecting `test.requestTimeoutMillis > 0`, found: " + REQUEST_TIMEOUT); + } + + protected static final int RETRY_LIMIT = + Integer.parseInt(System.getProperty("jdk.httpclient.redirects.retrylimit", "0")); + + private static final long RESPONSE_FAILURE_WAIT_DURATION_MILLIS = + Long.parseLong(System.getProperty("test.responseFailureWaitDurationMillis", "0")); + + static { + if (RETRY_LIMIT > 0) { + + // Verify that response failure wait duration is provided + if (RESPONSE_FAILURE_WAIT_DURATION_MILLIS <= 0) { + var message = String.format( + "`jdk.httpclient.redirects.retrylimit` (%s) is greater than zero. " + + "`test.responseFailureWaitDurationMillis` (%s) must be greater than zero too.", + RETRY_LIMIT, RESPONSE_FAILURE_WAIT_DURATION_MILLIS); + throw new AssertionError(message); + } + + // Verify that the total response failure waits exceed the request timeout + var totalResponseFailureWaitDuration = Duration + .ofMillis(RESPONSE_FAILURE_WAIT_DURATION_MILLIS) + .multipliedBy(RETRY_LIMIT); + if (totalResponseFailureWaitDuration.compareTo(REQUEST_TIMEOUT) <= 0) { + var message = ("`test.responseFailureWaitDurationMillis * jdk.httpclient.redirects.retrylimit` (%s * %s = %s) " + + "must be greater than `test.requestTimeoutMillis` (%s)") + .formatted( + RESPONSE_FAILURE_WAIT_DURATION_MILLIS, + RETRY_LIMIT, + totalResponseFailureWaitDuration, + REQUEST_TIMEOUT); + throw new AssertionError(message); + } + + } + } + + protected static final ServerRequestPair + HTTP1 = ServerRequestPair.of(Version.HTTP_1_1, false), + HTTPS1 = ServerRequestPair.of(Version.HTTP_1_1, true), + HTTP2 = ServerRequestPair.of(Version.HTTP_2, false), + HTTPS2 = ServerRequestPair.of(Version.HTTP_2, true), + HTTP3 = ServerRequestPair.of(Version.HTTP_3, true); + + private static SSLContext createSslContext() { + try { + return new SimpleSSLContext().get(); + } catch (IOException exception) { + throw new UncheckedIOException(exception); + } + } + + protected record ServerRequestPair(HttpTestServer server, HttpRequest request, boolean secure) { + + private static final ExecutorService EXECUTOR = Executors.newVirtualThreadPerTaskExecutor(); + + private static final CountDownLatch SHUT_DOWN_LATCH = new CountDownLatch(1); + + private static final AtomicInteger SERVER_COUNTER = new AtomicInteger(); + + /** + * An arbitrary content length to cause the client wait for it. + * It just needs to be greater than zero, and big enough to trigger a timeout when delivered slowly. + */ + public static final int CONTENT_LENGTH = 1234; + + public enum ServerHandlerBehaviour { + BLOCK_BEFORE_HEADER_DELIVERY, + BLOCK_BEFORE_BODY_DELIVERY, + DELIVER_BODY_SLOWLY, + DELIVER_NO_BODY + } + + public static volatile ServerHandlerBehaviour SERVER_HANDLER_BEHAVIOUR; + + public static volatile int SERVER_HANDLER_PENDING_FAILURE_COUNT = 0; + + private static ServerRequestPair of(Version version, boolean secure) { + + // Create the server and the request URI + var sslContext = secure ? SSL_CONTEXT : null; + var serverId = "" + SERVER_COUNTER.getAndIncrement(); + var server = createServer(version, sslContext); + server.getVersion(); + var handlerPath = "/%s/".formatted(CLASS_NAME); + var requestUriScheme = secure ? "https" : "http"; + var requestUri = URI.create("%s://%s%s-".formatted(requestUriScheme, server.serverAuthority(), handlerPath)); + + // Register the request handler + server.addHandler(createServerHandler(serverId), handlerPath); + + // Create the request + var request = createRequestBuilder(requestUri, version).timeout(REQUEST_TIMEOUT).build(); + + // Create the pair + var pair = new ServerRequestPair(server, request, secure); + pair.server.start(); + LOGGER.log("Server[%s] is started at `%s`", serverId, server.serverAuthority()); + return pair; + + } + + private static HttpTestServer createServer(Version version, SSLContext sslContext) { + try { + return switch (version) { + case HTTP_1_1, HTTP_2 -> HttpTestServer.create(version, sslContext, EXECUTOR); + case HTTP_3 -> HttpTestServer.create(HTTP_3_URI_ONLY, sslContext, EXECUTOR); + }; + } catch (IOException exception) { + throw new UncheckedIOException(exception); + } + } + + private static HttpTestHandler createServerHandler(String serverId) { + return (exchange) -> { + var connectionKey = exchange.getConnectionKey(); + LOGGER.log( + "Server[%s] has received request %s", + serverId, Map.of("connectionKey", connectionKey)); + try (exchange) { + + // Short-circuit on `HEAD` requests. + // They are used for admitting established connections to the pool. + if ("HEAD".equals(exchange.getRequestMethod())) { + LOGGER.log( + "Server[%s] is responding to the `HEAD` request %s", + serverId, Map.of("connectionKey", connectionKey)); + exchange.sendResponseHeaders(200, 0); + return; + } + + // Short-circuit if instructed to fail + synchronized (ServerRequestPair.class) { + if (SERVER_HANDLER_PENDING_FAILURE_COUNT > 0) { + LOGGER.log( + "Server[%s] is prematurely failing as instructed %s", + serverId, + Map.of( + "connectionKey", connectionKey, + "SERVER_HANDLER_PENDING_FAILURE_COUNT", SERVER_HANDLER_PENDING_FAILURE_COUNT)); + // Closing the exchange will trigger an `END_STREAM` without a headers frame. + // This is a protocol violation, hence we must reset the stream first. + // We are doing so using by rejecting the stream, which is known to make the client retry. + if (Version.HTTP_2.equals(exchange.getExchangeVersion())) { + exchange.resetStream(ErrorFrame.REFUSED_STREAM); + } else if (Version.HTTP_3.equals(exchange.getExchangeVersion())) { + exchange.resetStream(Http3Error.H3_REQUEST_REJECTED.code()); + } + SERVER_HANDLER_PENDING_FAILURE_COUNT--; + return; + } + } + + switch (SERVER_HANDLER_BEHAVIOUR) { + + case BLOCK_BEFORE_HEADER_DELIVERY -> sleepIndefinitely(serverId, connectionKey); + + case BLOCK_BEFORE_BODY_DELIVERY -> { + sendResponseHeaders(serverId, exchange, connectionKey); + sleepIndefinitely(serverId, connectionKey); + } + + case DELIVER_BODY_SLOWLY -> { + sendResponseHeaders(serverId, exchange, connectionKey); + sendResponseBodySlowly(serverId, exchange, connectionKey); + } + + case DELIVER_NO_BODY -> sendResponseHeaders(serverId, exchange, connectionKey, 204, 0); + + } + + } catch (Exception exception) { + var message = String.format( + "Server[%s] has failed! %s", + serverId, Map.of("connectionKey", connectionKey)); + LOGGER.log(System.Logger.Level.ERROR, message, exception); + if (exception instanceof InterruptedException) { + // Restore the interrupt + Thread.currentThread().interrupt(); + } + throw new RuntimeException(message, exception); + } + }; + } + + private static void sleepIndefinitely(String serverId, String connectionKey) throws InterruptedException { + LOGGER.log("Server[%s] is sleeping %s", serverId, Map.of("connectionKey", connectionKey)); + SHUT_DOWN_LATCH.await(); + } + + private static void sendResponseHeaders(String serverId, HttpTestExchange exchange, String connectionKey) + throws IOException { + sendResponseHeaders(serverId, exchange, connectionKey, 200, CONTENT_LENGTH); + } + + private static void sendResponseHeaders( + String serverId, + HttpTestExchange exchange, + String connectionKey, + int statusCode, + long contentLength) + throws IOException { + LOGGER.log("Server[%s] is sending headers %s", serverId, Map.of("connectionKey", connectionKey)); + exchange.sendResponseHeaders(statusCode, contentLength); + // Force the headers to be flushed + exchange.getResponseBody().flush(); + } + + private static void sendResponseBodySlowly(String serverId, HttpTestExchange exchange, String connectionKey) + throws Exception { + var perBytePauseDuration = Duration.ofMillis(100); + assertTrue( + perBytePauseDuration.multipliedBy(CONTENT_LENGTH).compareTo(REQUEST_TIMEOUT) > 0, + "Per-byte pause duration (%s) must be long enough to exceed the timeout (%s) when delivering the content (%s bytes)".formatted( + perBytePauseDuration, REQUEST_TIMEOUT, CONTENT_LENGTH)); + try (var responseBody = exchange.getResponseBody()) { + for (int i = 0; i < CONTENT_LENGTH; i++) { + LOGGER.log( + "Server[%s] is sending the body %s/%s %s", + serverId, i, CONTENT_LENGTH, Map.of("connectionKey", connectionKey)); + responseBody.write(i); + responseBody.flush(); + Thread.sleep(perBytePauseDuration); + } + throw new AssertionError("Delivery should never have succeeded due to timeout!"); + } catch (IOException _) { + // Client's timeout mechanism is expected to short-circuit and cut the stream. + // Hence, discard I/O failures. + } + } + + public HttpClient createClientWithEstablishedConnection() throws IOException, InterruptedException { + var version = server.getVersion(); + var client = createClientBuilderFor(version) + .version(version) + .sslContext(SSL_CONTEXT) + .proxy(NO_PROXY) + .build(); + // Ensure an established connection is admitted to the pool. This + // helps to cross out any possibilities of a timeout before a + // request makes it to the server handler. For instance, consider + // HTTP/1.1 to HTTP/2 upgrades, or long-running TLS handshakes. + var headRequest = createRequestBuilder(request.uri(), version).HEAD().build(); + client.send(headRequest, HttpResponse.BodyHandlers.discarding()); + return client; + } + + private static HttpRequest.Builder createRequestBuilder(URI uri, Version version) { + var requestBuilder = HttpRequest.newBuilder(uri).version(version); + if (Version.HTTP_3.equals(version)) { + requestBuilder.setOption(HttpOption.H3_DISCOVERY, HttpOption.Http3DiscoveryMode.HTTP_3_URI_ONLY); + } + return requestBuilder; + } + + @Override + public String toString() { + var version = server.getVersion(); + var versionString = version.toString(); + return switch (version) { + case HTTP_1_1, HTTP_2 -> secure ? versionString.replaceFirst("_", "S_") : versionString; + case HTTP_3 -> versionString; + }; + } + + } + + @AfterAll + static void closeServers() { + + // Terminate all handlers before shutting down the server, which would block otherwise. + ServerRequestPair.SHUT_DOWN_LATCH.countDown(); + ServerRequestPair.EXECUTOR.shutdown(); + + // Shut down servers + Exception[] exceptionRef = {null}; + serverRequestPairs() + .forEach(pair -> { + try { + pair.server.stop(); + } catch (Exception exception) { + if (exceptionRef[0] == null) { + exceptionRef[0] = exception; + } else { + exceptionRef[0].addSuppressed(exception); + } + } + }); + if (exceptionRef[0] != null) { + throw new RuntimeException("failed closing one or more server resources", exceptionRef[0]); + } + + } + + /** + * Configures how many times the handler should fail. + */ + @BeforeEach + void resetServerHandlerFailureIndex() { + ServerRequestPair.SERVER_HANDLER_PENDING_FAILURE_COUNT = Math.max(0, RETRY_LIMIT - 1); + } + + /** + * Ensures that the handler has failed as many times as instructed. + */ + @AfterEach + void verifyServerHandlerFailureIndex() { + assertEquals(0, ServerRequestPair.SERVER_HANDLER_PENDING_FAILURE_COUNT); + } + + protected static Stream serverRequestPairs() { + return Stream.of(HTTP1, HTTPS1, HTTP2, HTTPS2, HTTP3); + } + + protected static void assertThrowsHttpTimeoutException(Executable executable) { + var rootException = assertThrows(Exception.class, executable); + // Due to intricacies involved in the way exceptions are generated and + // nested, there is no bullet-proof way to determine at which level of + // the causal chain an `HttpTimeoutException` will show up. Hence, we + // scan through the entire causal chain. + Throwable exception = rootException; + while (exception != null) { + if (exception instanceof HttpTimeoutException) { + return; + } + exception = exception.getCause(); + } + throw new AssertionError("was expecting an `HttpTimeoutException` in the causal chain", rootException); + } + +} diff --git a/test/jdk/java/net/httpclient/access/java.net.http/jdk/internal/net/http/HttpClientTimerAccess.java b/test/jdk/java/net/httpclient/access/java.net.http/jdk/internal/net/http/HttpClientTimerAccess.java new file mode 100644 index 00000000000..8bc1fac7b60 --- /dev/null +++ b/test/jdk/java/net/httpclient/access/java.net.http/jdk/internal/net/http/HttpClientTimerAccess.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2025, 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.net.http; + +import java.net.http.HttpClient; + +public enum HttpClientTimerAccess {; + + public static void assertNoResponseTimerEventRegistrations(HttpClient client) { + assertTimerEventRegistrationCount(client, ResponseTimerEvent.class, 0); + } + + private static void assertTimerEventRegistrationCount( + HttpClient client, + Class clazz, + long expectedCount) { + var facade = assertType(HttpClientFacade.class, client); + var actualCount = facade.impl.timers().stream().filter(clazz::isInstance).count(); + if (actualCount != 0) { + throw new AssertionError( + "Found %s occurrences of `%s` timer event registrations while expecting %s.".formatted( + actualCount, clazz.getCanonicalName(), expectedCount)); + } + } + + private static T assertType(Class expectedType, Object instance) { + if (!expectedType.isInstance(instance)) { + var expectedTypeName = expectedType.getCanonicalName(); + var actualTypeName = instance != null ? instance.getClass().getCanonicalName() : null; + throw new AssertionError( + "Was expecting an instance of type `%s`, found: `%s`".formatted( + expectedTypeName, actualTypeName)); + } + @SuppressWarnings("unchecked") + T typedInstance = (T) instance; + return typedInstance; + } + +} diff --git a/test/jdk/java/net/httpclient/websocket/WebSocketTest.java b/test/jdk/java/net/httpclient/websocket/WebSocketTest.java index 83f8b6eab27..43bcb054b7d 100644 --- a/test/jdk/java/net/httpclient/websocket/WebSocketTest.java +++ b/test/jdk/java/net/httpclient/websocket/WebSocketTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, 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 @@ -23,8 +23,10 @@ /* * @test - * @bug 8217429 + * @bug 8217429 8208693 + * @library ../access * @build DummyWebSocketServer + * java.net.http/jdk.internal.net.http.HttpClientTimerAccess * @run testng/othervm * WebSocketTest */ @@ -40,6 +42,7 @@ import java.net.http.WebSocket; import java.net.http.WebSocketHandshakeException; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; +import java.time.Duration; import java.util.ArrayList; import java.util.Arrays; import java.util.Base64; @@ -48,6 +51,7 @@ import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionException; import java.util.concurrent.CompletionStage; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Function; @@ -58,6 +62,7 @@ import static java.net.http.HttpClient.Builder.NO_PROXY; import static java.net.http.HttpClient.newBuilder; import static java.net.http.WebSocket.NORMAL_CLOSURE; import static java.nio.charset.StandardCharsets.UTF_8; +import static jdk.internal.net.http.HttpClientTimerAccess.assertNoResponseTimerEventRegistrations; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertThrows; import static org.testng.Assert.fail; @@ -143,6 +148,45 @@ public class WebSocketTest { } } + /** + * Verifies that the internally issued request to establish the WebSocket + * connection does not leave any response timers registered at the client + * after the WebSocket handshake. + */ + @Test + public void responseTimerCleanUp() throws Exception { + try (var server = new DummyWebSocketServer()) { + server.open(); + try (var client = newBuilder().proxy(NO_PROXY).build()) { + var connectionEstablished = new CountDownLatch(1); + var webSocketListener = new WebSocket.Listener() { + + @Override + public void onOpen(WebSocket webSocket) { + connectionEstablished.countDown(); + } + + }; + var webSocket = client + .newWebSocketBuilder() + // Explicitly configure a timeout to get a response + // timer event get registered at the client. The query + // should succeed without timing out. + .connectTimeout(Duration.ofMinutes(2)) + .buildAsync(server.getURI(), webSocketListener) + .join(); + try { + connectionEstablished.await(); + // We expect the response timer event to get evicted once + // the WebSocket handshake headers are received. + assertNoResponseTimerEventRegistrations(client); + } finally { + webSocket.abort(); + } + } + } + } + @Test public void partialBinaryThenText() throws IOException { try (var server = new DummyWebSocketServer()) { From df0165bd6933728fdcf1956323401afdc47b3f78 Mon Sep 17 00:00:00 2001 From: Ana-Maria Mihalceanu Date: Thu, 4 Dec 2025 10:09:33 +0000 Subject: [PATCH 168/706] 8321139: jlink's compression plugin doesn't handle -c option correctly Reviewed-by: jpai, alanb --- .../jdk/tools/jlink/internal/TaskHelper.java | 7 ++- .../tools/jlink/resources/plugins.properties | 12 ++--- src/jdk.jlink/share/man/jlink.md | 21 +++++--- test/jdk/tools/jlink/JLinkTest.java | 38 ++++++++++++-- test/jdk/tools/jlink/TaskHelperTest.java | 51 +++++++++++++++++-- test/setup_aot/TestSetupAOT.java | 2 +- 6 files changed, 106 insertions(+), 25 deletions(-) diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/TaskHelper.java b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/TaskHelper.java index d53589dc388..dca4d57f764 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/TaskHelper.java +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/TaskHelper.java @@ -362,10 +362,13 @@ public final class TaskHelper { if (plugin instanceof DefaultCompressPlugin) { plugOption - = new PluginOption(false, + = new PluginOption(true, (task, opt, arg) -> { Map m = addArgumentMap(plugin); - m.put(plugin.getName(), DefaultCompressPlugin.LEVEL_2); + String level = (arg != null && !arg.isEmpty()) + ? arg + :"zip-6"; + m.put(plugin.getName(), level); }, false, "--compress", "-c"); mainOptions.add(plugOption); } else if (plugin instanceof DefaultStripDebugPlugin) { diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins.properties b/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins.properties index e9be0b4e587..7e3c26fa7b8 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins.properties +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins.properties @@ -61,14 +61,14 @@ Class optimization: convert Class.forName calls to constant loads. class-for-name.usage=\ \ --class-for-name Class optimization: convert Class.forName calls to constant loads. -compress.argument=[:filter=] +compress.argument=[:filter=] compress.description= Compression to use in compressing resources. compress.usage=\ \ --compress Compression to use in compressing resources:\n\ \ Accepted values are:\n\ -\ zip-[0-9], where zip-0 provides no compression,\n\ +\ zip-'{0-9}', where zip-0 provides no compression,\n\ \ and zip-9 provides the best compression.\n\ \ Default is zip-6. @@ -307,15 +307,15 @@ plugin.opt.disable-plugin=\ \ --disable-plugin Disable the plugin mentioned plugin.opt.compress=\ -\ --compress Compression to use in compressing resources:\n\ +\ --compress Compress all resources in the output image:\n\ \ Accepted values are:\n\ -\ zip-[0-9], where zip-0 provides no compression,\n\ +\ zip-'{0-9}', where zip-0 provides no compression,\n\ \ and zip-9 provides the best compression.\n\ \ Default is zip-6.\n\ \ Deprecated values to be removed in a future release:\n\ -\ 0: No compression. Equivalent to zip-0.\n\ +\ 0: No compression. Use zip-0 instead.\n\ \ 1: Constant String Sharing\n\ -\ 2: Equivalent to zip-6. +\ 2: ZIP. Use zip-6 instead. plugin.opt.strip-debug=\ \ -G, --strip-debug Strip debug information diff --git a/src/jdk.jlink/share/man/jlink.md b/src/jdk.jlink/share/man/jlink.md index dc256af43b5..0d16e69c9ef 100644 --- a/src/jdk.jlink/share/man/jlink.md +++ b/src/jdk.jlink/share/man/jlink.md @@ -64,12 +64,15 @@ Developers are responsible for updating their custom runtime images. `--bind-services` : Link service provider modules and their dependencies. -`-c ={0|1|2}` or `--compress={0|1|2}` -: Enable compression of resources: +`-c zip-{0-9}` or `--compress=zip-{0-9}` +: Enable compression of resources. The accepted values are: + zip-{0-9}, where zip-0 provides no compression, + and zip-9 provides the best compression. Default is zip-6. - - `0`: No compression +: Deprecated values to be removed in a future release: + - `0`: No compression. Use zip-0 instead. - `1`: Constant string sharing - - `2`: ZIP + - `2`: ZIP. Use zip-6 instead. `--disable-plugin` *pluginname* : Disables the specified plug-in. See [jlink Plug-ins] for the list of @@ -170,14 +173,18 @@ For a complete list of all available plug-ins, run the command ### Plugin `compress` Options -: `--compress=`{`0`\|`1`\|`2`}\[`:filter=`*pattern-list*\] +: `--compress=zip-`{`0`-`9`}\[`:filter=`*pattern-list*\] Description : Compresses all resources in the output image. + Accepted values are: + zip-{0-9}, where zip-0 provides no compression, + and zip-9 provides the best compression. Default is zip-6. - - Level 0: No compression +: Deprecated values to be removed in a future release: + - Level 0: No compression. Use zip-0 instead. - Level 1: Constant string sharing - - Level 2: ZIP + - Level 2: ZIP. Use zip-6 instead. An optional *pattern-list* filter can be specified to list the pattern of files to include. diff --git a/test/jdk/tools/jlink/JLinkTest.java b/test/jdk/tools/jlink/JLinkTest.java index bc4d2a08800..1d84caaa147 100644 --- a/test/jdk/tools/jlink/JLinkTest.java +++ b/test/jdk/tools/jlink/JLinkTest.java @@ -42,10 +42,7 @@ import tests.JImageGenerator; /* * @test * @summary Test image creation - * @bug 8189777 - * @bug 8194922 - * @bug 8206962 - * @bug 8240349 + * @bug 8189777 8194922 8206962 8240349 8163382 8165735 8166810 8173717 8321139 * @author Jean-Francois Denise * @requires (vm.compMode != "Xcomp" & os.maxMemory >= 2g) * @library ../lib @@ -358,6 +355,39 @@ public class JLinkTest { helper.generateDefaultImage(userOptions, moduleName).assertFailure("Error: Invalid compression level invalid"); } + // short command without argument + { + String[] userOptions = {"-c"}; + String moduleName = "invalidCompressLevelEmpty"; + helper.generateDefaultJModule(moduleName, "composite2"); + helper.generateDefaultImage(userOptions, moduleName).assertFailure("Error: no value given for -c"); + } + + // invalid short command + { + String[] userOptions = {"-c", "3", "--output", "image"}; + String moduleName = "invalidCompressLevel3"; + helper.generateDefaultJModule(moduleName, "composite2"); + helper.generateDefaultImage(userOptions, moduleName).assertFailure("Error: Invalid compression level 3"); + } + + + // invalid argument value + { + String[] userOptions = {"--compress", "42", "--output", "image"}; + String moduleName = "invalidCompressLevel42"; + helper.generateDefaultJModule(moduleName, "composite2"); + helper.generateDefaultImage(userOptions, moduleName).assertFailure("Error: Invalid compression level 42"); + } + + // invalid argument value + { + String[] userOptions = {"--compress", "zip-", "--output", "image"}; + String moduleName = "invalidCompressLevelZip"; + helper.generateDefaultJModule(moduleName, "composite2"); + helper.generateDefaultImage(userOptions, moduleName).assertFailure("Error: Invalid compression level zip-"); + } + // orphan argument - JDK-8166810 { String[] userOptions = {"--compress", "2", "foo" }; diff --git a/test/jdk/tools/jlink/TaskHelperTest.java b/test/jdk/tools/jlink/TaskHelperTest.java index 51dea8de24a..26ac376a6ec 100644 --- a/test/jdk/tools/jlink/TaskHelperTest.java +++ b/test/jdk/tools/jlink/TaskHelperTest.java @@ -48,7 +48,7 @@ import jdk.tools.jlink.internal.TaskHelper.BadArgs; /* * @test * @summary Test TaskHelper option parsing - * @bug 8303884 + * @bug 8303884 8321139 * @modules jdk.jlink/jdk.tools.jlink.internal * jdk.jlink/jdk.tools.jlink.plugin * @run junit TaskHelperTest @@ -59,19 +59,22 @@ public class TaskHelperTest { private static final List> OPTIONS = List.of( new Option<>(true, (task, opt, arg) -> { - System.out.println(arg); mainArgValue = arg; }, true, "--main-expecting"), new Option<>(false, (task, opt, arg) -> { mainFlag = true; - }, true, "--main-no-arg") + }, true, "--main-no-arg"), + new Option<>(true, (task, opt, arg) -> { + compressArgValue = (arg != null && !arg.isEmpty()) ? arg : "zip-6"; + }, "--compress", "-c") ); private static String argValue; private static String mainArgValue; private static boolean mainFlag = false; + private static String compressArgValue; - public record ArgTestCase(String cmdLine, String[] tokens, String pluginArgValue, String mainArgValue, boolean mainFlagSet) {}; + public record ArgTestCase(String cmdLine, String[] tokens, String pluginArgValue, String mainArgValue, boolean mainFlagSet) {} public static class TestPluginWithRawOption implements Plugin { @Override @@ -118,6 +121,7 @@ public class TaskHelperTest { argValue = null; mainArgValue = null; mainFlag = false; + compressArgValue= null; } public static Stream gnuStyleUsages() { @@ -217,4 +221,41 @@ public class TaskHelperTest { var remaining = optionsHelper.handleOptions(this, args); assertEquals(2, remaining.size()); } -} \ No newline at end of file + + record CompressTestCase(String[] tokens, String expectedCompressValue) {} + + public static Stream compressUsages() { + return Stream.of( + + new CompressTestCase(new String[] {"-c", "0"}, "0"), + new CompressTestCase(new String[] {"--compress=zip-0"}, "zip-0"), + + new CompressTestCase(new String[] {"-c", "1"}, "1"), + new CompressTestCase(new String[] {"--compress=zip-1"}, "zip-1"), + + new CompressTestCase(new String[] {"-c", "2"}, "2"), + new CompressTestCase(new String[] {"--compress=zip-2"}, "zip-2"), + + new CompressTestCase(new String[] {"--compress=zip-3"}, "zip-3"), + new CompressTestCase(new String[] {"--compress=zip-4"}, "zip-4"), + new CompressTestCase(new String[] {"--compress=zip-5"}, "zip-5"), + new CompressTestCase(new String[] {"--compress=zip-6"}, "zip-6"), + new CompressTestCase(new String[] {"--compress=zip-7"}, "zip-7"), + new CompressTestCase(new String[] {"--compress=zip-8"}, "zip-8"), + new CompressTestCase(new String[] {"--compress=zip-9"}, "zip-9") + ); + } + + @ParameterizedTest + @MethodSource("compressUsages") + public void testCompressOptionArg(CompressTestCase testCase) throws TaskHelper.BadArgs, IOException { + var remaining = optionsHelper.handleOptions(this, testCase.tokens); + + // trigger Plugin::configure + taskHelper.getPluginsConfig(null, null, null); + + assertTrue(remaining.isEmpty()); + assertEquals(testCase.expectedCompressValue, compressArgValue); + } +} + diff --git a/test/setup_aot/TestSetupAOT.java b/test/setup_aot/TestSetupAOT.java index a46bd6e66c7..0ab17d6ca99 100644 --- a/test/setup_aot/TestSetupAOT.java +++ b/test/setup_aot/TestSetupAOT.java @@ -137,7 +137,7 @@ public class TestSetupAOT { String jlinkOutput = tmpDir + File.separator + "jlinkOutput"; execTool("jlink", "--help") - .shouldContain("Compression to use in compressing resources"); + .shouldContain("Compress all resources in the output image"); execTool("jlink", "--list-plugins") .shouldContain("List of available plugins", "--generate-cds-archive "); From 91c5bd550a36e10e8b39d1b322fd433ee8df14f5 Mon Sep 17 00:00:00 2001 From: Jatin Bhateja Date: Thu, 4 Dec 2025 10:17:34 +0000 Subject: [PATCH 169/706] 8337791: VectorAPI jtreg ABSMaskedByteMaxVectorTests crashes with UseAVX=0 -XX:MaxVectorSize=8 Reviewed-by: epeter, sviswanathan, dlunden --- src/hotspot/cpu/x86/x86.ad | 5 ++ .../vectorapi/TestABSMaskedMaxByteVector.java | 54 +++++++++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 test/hotspot/jtreg/compiler/vectorapi/TestABSMaskedMaxByteVector.java diff --git a/src/hotspot/cpu/x86/x86.ad b/src/hotspot/cpu/x86/x86.ad index 1d393897bca..42d2e815e45 100644 --- a/src/hotspot/cpu/x86/x86.ad +++ b/src/hotspot/cpu/x86/x86.ad @@ -3386,6 +3386,11 @@ bool Matcher::match_rule_supported_vector(int opcode, int vlen, BasicType bt) { return false; } break; + case Op_VectorBlend: + if (UseAVX == 0 && size_in_bits < 128) { + return false; + } + break; case Op_VectorTest: if (UseSSE < 4) { return false; // Implementation limitation diff --git a/test/hotspot/jtreg/compiler/vectorapi/TestABSMaskedMaxByteVector.java b/test/hotspot/jtreg/compiler/vectorapi/TestABSMaskedMaxByteVector.java new file mode 100644 index 00000000000..356892fadf8 --- /dev/null +++ b/test/hotspot/jtreg/compiler/vectorapi/TestABSMaskedMaxByteVector.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2025, 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 compiler.vectorapi; + +import compiler.lib.ir_framework.*; +import jdk.incubator.vector.*; + +/* + * @test + * @bug 8337791 + * @summary Test byte vector predicated ABS with UseAVX=0 and MaxVectorSize=8 + * @modules jdk.incubator.vector + * @library /test/lib / + * @run driver compiler.vectorapi.TestABSMaskedMaxByteVector + */ + +public class TestABSMaskedMaxByteVector { + public static final VectorSpecies BSP = ByteVector.SPECIES_MAX; + public static int idx = 0; + + public static void main(String[] args) { + TestFramework.runWithFlags("--add-modules=jdk.incubator.vector", "-ea", "-XX:+IgnoreUnrecognizedVMOptions", "-XX:UseAVX=0", "-XX:MaxVectorSize=8"); + TestFramework.runWithFlags("--add-modules=jdk.incubator.vector", "-ea"); + } + + @Test + @IR(failOn = {IRNode.ABS_VB}, applyIfAnd = {"MaxVectorSize", " <= 8 ", "UseAVX", "0"}, applyIfPlatform = {"x64", "true"}, applyIfCPUFeature = {"sse4.1", "true"}) + @IR(counts = {IRNode.ABS_VB, "1"}, applyIf = {"MaxVectorSize", " > 8 "}, applyIfPlatform = {"x64", "true"}, applyIfCPUFeature = {"sse4.1", "true"}) + public void test() { + assert ByteVector.broadcast(BSP, (byte)-4) + .lanewise(VectorOperators.ABS, VectorMask.fromLong(BSP, 0xF)) + .lane(idx++ & 3) == 4; + } +} From b5970c97bdd5b1e079e9ada0fbd469850c0e23b4 Mon Sep 17 00:00:00 2001 From: Volodymyr Paprotski Date: Thu, 4 Dec 2025 10:21:53 +0000 Subject: [PATCH 170/706] 8373063: Test sun/security/provider/acvp/ML_DSA_Intrinsic_Test.java fails on Aarch64 after JDK-8372816 Reviewed-by: dholmes, mdoerr --- .../provider/acvp/ML_DSA_Intrinsic_Test.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/test/jdk/sun/security/provider/acvp/ML_DSA_Intrinsic_Test.java b/test/jdk/sun/security/provider/acvp/ML_DSA_Intrinsic_Test.java index 7f057603323..1e9faf7fb74 100644 --- a/test/jdk/sun/security/provider/acvp/ML_DSA_Intrinsic_Test.java +++ b/test/jdk/sun/security/provider/acvp/ML_DSA_Intrinsic_Test.java @@ -38,6 +38,8 @@ import java.util.HexFormat; */ /* * @test + * @comment This test should be reenabled on aarch64 + * @requires os.simpleArch == "x64" * @library /test/lib * @key randomness * @modules java.base/sun.security.provider:+open @@ -48,7 +50,7 @@ import java.util.HexFormat; // -XX:+UnlockDiagnosticVMOptions -XX:+UseDilithiumIntrinsics test/jdk/sun/security/provider/acvp/ML_DSA_Intrinsic_Test.java public class ML_DSA_Intrinsic_Test { - public static void main(String[] args) throws Exception, Throwable { + public static void main(String[] args) throws Throwable { MethodHandles.Lookup lookup = MethodHandles.lookup(); Class kClazz = sun.security.provider.ML_DSA.class; @@ -129,7 +131,7 @@ public class ML_DSA_Intrinsic_Test { private static final int ML_DSA_N = 256; public static void testMult(int[] prod1, int[] prod2, int[] coeffs1, int[] coeffs2, MethodHandle mult, MethodHandle multJava, Random rnd, - long seed, int i) throws Exception, Throwable { + long seed, int i) throws Throwable { for (int j = 0; j Date: Thu, 4 Dec 2025 12:25:02 +0000 Subject: [PATCH 171/706] 8373062: JFR build failure with CDS disabled Reviewed-by: egahlin --- .../share/classfile/systemDictionary.cpp | 22 +++++++++---------- src/hotspot/share/jfr/jfr.cpp | 2 ++ src/hotspot/share/jfr/jfr.hpp | 2 +- .../share/jfr/support/jfrClassDefineEvent.cpp | 2 ++ .../share/jfr/support/jfrClassDefineEvent.hpp | 3 ++- 5 files changed, 18 insertions(+), 13 deletions(-) diff --git a/src/hotspot/share/classfile/systemDictionary.cpp b/src/hotspot/share/classfile/systemDictionary.cpp index ac57293687c..c873347a197 100644 --- a/src/hotspot/share/classfile/systemDictionary.cpp +++ b/src/hotspot/share/classfile/systemDictionary.cpp @@ -1146,17 +1146,6 @@ void SystemDictionary::load_shared_class_misc(InstanceKlass* ik, ClassLoaderData } } -#if INCLUDE_JFR -void SystemDictionary::post_class_load_event(EventClassLoad* event, const InstanceKlass* k, const ClassLoaderData* init_cld) { - assert(event != nullptr, "invariant"); - assert(k != nullptr, "invariant"); - event->set_loadedClass(k); - event->set_definingClassLoader(k->class_loader_data()); - event->set_initiatingClassLoader(init_cld); - event->commit(); -} -#endif // INCLUDE_JFR - // This is much more lightweight than SystemDictionary::resolve_or_null // - There's only a single Java thread at this point. No need for placeholder. // - All supertypes of ik have been loaded @@ -1217,6 +1206,17 @@ void SystemDictionary::preload_class(Handle class_loader, InstanceKlass* ik, TRA #endif // INCLUDE_CDS +#if INCLUDE_JFR +void SystemDictionary::post_class_load_event(EventClassLoad* event, const InstanceKlass* k, const ClassLoaderData* init_cld) { + assert(event != nullptr, "invariant"); + assert(k != nullptr, "invariant"); + event->set_loadedClass(k); + event->set_definingClassLoader(k->class_loader_data()); + event->set_initiatingClassLoader(init_cld); + event->commit(); +} +#endif // INCLUDE_JFR + InstanceKlass* SystemDictionary::load_instance_class_impl(Symbol* class_name, Handle class_loader, TRAPS) { if (class_loader.is_null()) { diff --git a/src/hotspot/share/jfr/jfr.cpp b/src/hotspot/share/jfr/jfr.cpp index 3a2465e211d..b09a89594ad 100644 --- a/src/hotspot/share/jfr/jfr.cpp +++ b/src/hotspot/share/jfr/jfr.cpp @@ -173,6 +173,7 @@ bool Jfr::on_start_flight_recording_option(const JavaVMOption** option, char* de return JfrOptionSet::parse_start_flight_recording_option(option, delimiter); } +#if INCLUDE_CDS void Jfr::on_restoration(const Klass* k, JavaThread* jt) { assert(k != nullptr, "invariant"); JfrTraceId::restore(k); @@ -180,3 +181,4 @@ void Jfr::on_restoration(const Klass* k, JavaThread* jt) { JfrClassDefineEvent::on_restoration(InstanceKlass::cast(k), jt); } } +#endif diff --git a/src/hotspot/share/jfr/jfr.hpp b/src/hotspot/share/jfr/jfr.hpp index 7b86e6c917e..db567cc9a29 100644 --- a/src/hotspot/share/jfr/jfr.hpp +++ b/src/hotspot/share/jfr/jfr.hpp @@ -79,7 +79,7 @@ class Jfr : AllStatic { static void initialize_main_thread(JavaThread* jt); static bool has_sample_request(JavaThread* jt); static void check_and_process_sample_request(JavaThread* jt); - static void on_restoration(const Klass* k, JavaThread* jt); + CDS_ONLY(static void on_restoration(const Klass* k, JavaThread* jt);) }; #endif // SHARE_JFR_JFR_HPP diff --git a/src/hotspot/share/jfr/support/jfrClassDefineEvent.cpp b/src/hotspot/share/jfr/support/jfrClassDefineEvent.cpp index 06f361ced8c..5bdc0015a2b 100644 --- a/src/hotspot/share/jfr/support/jfrClassDefineEvent.cpp +++ b/src/hotspot/share/jfr/support/jfrClassDefineEvent.cpp @@ -171,6 +171,7 @@ void JfrClassDefineEvent::on_creation(const InstanceKlass* ik, const ClassFilePa } } +#if INCLUDE_CDS void JfrClassDefineEvent::on_restoration(const InstanceKlass* ik, JavaThread* jt) { assert(ik != nullptr, "invariant"); assert(ik->trace_id() != 0, "invariant"); @@ -186,3 +187,4 @@ void JfrClassDefineEvent::on_restoration(const InstanceKlass* ik, JavaThread* jt send_event(ik, cl->is_modules_image() ? module_path(ik, jt) : get_source(cl, jt)); } } +#endif diff --git a/src/hotspot/share/jfr/support/jfrClassDefineEvent.hpp b/src/hotspot/share/jfr/support/jfrClassDefineEvent.hpp index 4a0926023ca..3e242d8e4f2 100644 --- a/src/hotspot/share/jfr/support/jfrClassDefineEvent.hpp +++ b/src/hotspot/share/jfr/support/jfrClassDefineEvent.hpp @@ -26,6 +26,7 @@ #define SHARE_JFR_SUPPORT_JFRCLASSDEFINEEVENT_HPP #include "memory/allStatic.hpp" +#include "utilities/macros.hpp" class ClassFileParser; class InstanceKlass; @@ -34,7 +35,7 @@ class JavaThread; class JfrClassDefineEvent : AllStatic { public: static void on_creation(const InstanceKlass* ik, const ClassFileParser& parser, JavaThread* jt); - static void on_restoration(const InstanceKlass* ik, JavaThread* jt); + CDS_ONLY(static void on_restoration(const InstanceKlass* ik, JavaThread* jt);) }; #endif // SHARE_JFR_SUPPORT_JFRCLASSDEFINEEVENT_HPP From c4ec983da57ee8aea71e88d5de2570c5d65a69df Mon Sep 17 00:00:00 2001 From: Robert Toyonaga Date: Thu, 4 Dec 2025 13:56:17 +0000 Subject: [PATCH 172/706] 8370715: JFR: Races are possible when dumping recordings Reviewed-by: egahlin, stuefe --- .../jdk/jfr/internal/PlatformRecording.java | 10 ++- .../api/recording/dump/TestDumpOverwrite.java | 79 +++++++++++++++++++ 2 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 test/jdk/jdk/jfr/api/recording/dump/TestDumpOverwrite.java diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformRecording.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformRecording.java index b07a71dd4d5..64454fc3cb4 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformRecording.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformRecording.java @@ -34,6 +34,7 @@ import static jdk.jfr.internal.LogTag.JFR; import java.io.IOException; import java.io.InputStream; import java.nio.channels.FileChannel; +import java.nio.channels.FileLock; import java.nio.file.NoSuchFileException; import java.nio.file.Path; import java.nio.file.StandardOpenOption; @@ -744,7 +745,14 @@ public final class PlatformRecording implements AutoCloseable { } private void transferChunks(WriteablePath path) throws IOException { - try (ChunksChannel cc = new ChunksChannel(chunks); FileChannel fc = FileChannel.open(path.getReal(), StandardOpenOption.WRITE, StandardOpenOption.APPEND)) { + // Before writing, wipe the file if it already exists. + try (ChunksChannel cc = new ChunksChannel(chunks); FileChannel fc = FileChannel.open(path.getReal(), StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.CREATE)) { + // Mitigate races against other processes + FileLock l = fc.tryLock(); + if (l == null) { + Logger.log(LogTag.JFR, LogLevel.INFO, "Dump operation skipped for recording \"" + name + "\" (" + id + "). File " + path.getRealPathText() + " is locked by other dump operation or activity."); + return; + } long bytes = cc.transferTo(fc); Logger.log(LogTag.JFR, LogLevel.INFO, "Transferred " + bytes + " bytes from the disk repository"); // No need to force if no data was transferred, which avoids IOException when device is /dev/null diff --git a/test/jdk/jdk/jfr/api/recording/dump/TestDumpOverwrite.java b/test/jdk/jdk/jfr/api/recording/dump/TestDumpOverwrite.java new file mode 100644 index 00000000000..050b68eb538 --- /dev/null +++ b/test/jdk/jdk/jfr/api/recording/dump/TestDumpOverwrite.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2025, 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.jfr.api.recording.dump; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +import jdk.jfr.Recording; +import jdk.jfr.consumer.RecordedEvent; +import jdk.jfr.consumer.RecordingFile; +import jdk.test.lib.Asserts; +import jdk.test.lib.jfr.SimpleEventHelper; +import jdk.test.lib.jfr.Events; + +/** + * @test + * @summary Test that multiple dumps to the same file by ongoing recordings do not mangle data. + * @requires vm.flagless + * @requires vm.hasJFR + * @library /test/lib + * @run main/othervm jdk.jfr.api.recording.dump.TestDumpOverwrite + */ +public class TestDumpOverwrite { + private static Path DUMP_PATH = Paths.get(".", "rec_TestDumpOverwrite.jfr"); + public static void main(String[] args) throws Exception { + Recording recording1 = new Recording(); + Recording recording2 = new Recording(); + SimpleEventHelper.enable(recording1, true); + SimpleEventHelper.enable(recording2, true); + recording1.setDestination(DUMP_PATH); + recording2.setDestination(DUMP_PATH); + + int actualId = 0; + recording1.start(); + SimpleEventHelper.createEvent(actualId++); + recording2.start(); + SimpleEventHelper.createEvent(actualId++); + // This is results in the initial write to the dump destination + recording2.stop(); + SimpleEventHelper.createEvent(actualId++); + recording2.close(); + SimpleEventHelper.createEvent(actualId++); + // This should first wipe the data previously written by recording2. + recording1.stop(); + recording1.close(); + + Asserts.assertTrue(Files.exists(DUMP_PATH), "Recording file does not exist: " + DUMP_PATH); + + // Verify events are read in order without duplicates (otherwise chunks may be out of order). + // If the dump file is not being overwritten correctly, we will see event ids: 1, 0, 1, 2, 3. + int expectedId = 0; + for (RecordedEvent event : RecordingFile.readAllEvents(DUMP_PATH)) { + Events.assertField(event, "id").equal(expectedId++); + } + Asserts.assertTrue(expectedId == actualId, "incorrect number of events found"); + } +} From 6f03c7808de2b07b1e501d05b1bb7d5bfde5e393 Mon Sep 17 00:00:00 2001 From: Patricio Chilano Mateo Date: Thu, 4 Dec 2025 15:00:09 +0000 Subject: [PATCH 173/706] 8360702: runtime/Thread/AsyncExceptionTest.java timed out Reviewed-by: dholmes, fbredberg --- .../Thread/AsyncExceptionOnMonitorEnter.java | 42 ++++++++++--------- .../runtime/Thread/AsyncExceptionTest.java | 23 +++++----- 2 files changed, 33 insertions(+), 32 deletions(-) diff --git a/test/hotspot/jtreg/runtime/Thread/AsyncExceptionOnMonitorEnter.java b/test/hotspot/jtreg/runtime/Thread/AsyncExceptionOnMonitorEnter.java index a4aa0fe3797..409313b9626 100644 --- a/test/hotspot/jtreg/runtime/Thread/AsyncExceptionOnMonitorEnter.java +++ b/test/hotspot/jtreg/runtime/Thread/AsyncExceptionOnMonitorEnter.java @@ -25,7 +25,6 @@ * @test * @bug 8283044 * @summary Stress delivery of asynchronous exceptions while target is at monitorenter - * @requires test.thread.factory == null * @library /test/hotspot/jtreg/testlibrary * @run main/othervm/native AsyncExceptionOnMonitorEnter 0 * @run main/othervm/native -agentlib:AsyncExceptionOnMonitorEnter AsyncExceptionOnMonitorEnter 1 @@ -45,9 +44,13 @@ public class AsyncExceptionOnMonitorEnter extends Thread { public static native int exitRawMonitor(); public static native void destroyRawMonitor(); + // Avoid using CountDownLatch or similar objects that require unparking the + // main thread. Otherwise, if the main thread is run as a virtual thread, the + // async exception could be sent while the target is still executing FJP logic. + public volatile boolean started = false; + public volatile boolean gotMonitor = false; + private static Object o1 = new Object(); - private static boolean firstWorker = true; - private static Semaphore sem = new Semaphore(0); @Override public void run() { @@ -60,11 +63,9 @@ public class AsyncExceptionOnMonitorEnter extends Thread { public void testWithJavaMonitor() { try { + started = true; synchronized (o1) { - if (firstWorker) { - firstWorker = false; - sem.release(); - } + gotMonitor = true; Thread.sleep(1000); } } catch (ThreadDeath td) { @@ -75,20 +76,16 @@ public class AsyncExceptionOnMonitorEnter extends Thread { public void testWithJVMTIRawMonitor() { - boolean savedFirst = false; try { + started = true; int retCode = enterRawMonitor(); - if (retCode != 0 && firstWorker) { + if (retCode != 0) { throw new RuntimeException("error in JVMTI RawMonitorEnter: retCode=" + retCode); } - if (firstWorker) { - firstWorker = false; - savedFirst = true; - sem.release(); - } - Thread.sleep(1000); + gotMonitor = true; + Thread.sleep(500); retCode = exitRawMonitor(); - if (retCode != 0 && savedFirst) { + if (retCode != 0) { throw new RuntimeException("error in JVMTI RawMonitorExit: retCode=" + retCode); } } catch (ThreadDeath td) { @@ -134,15 +131,18 @@ public class AsyncExceptionOnMonitorEnter extends Thread { AsyncExceptionOnMonitorEnter worker2 = new AsyncExceptionOnMonitorEnter(); try { - // Start firstWorker worker and wait until monitor is acquired - firstWorker = true; + // Start first worker and wait until monitor is acquired worker1.start(); - sem.acquire(); + while (!worker1.gotMonitor) { + Thread.sleep(1); + } // Start second worker and allow some time for target to block on monitorenter // before executing Thread.stop() worker2.start(); - Thread.sleep(300); + while (!worker2.started) { + Thread.sleep(10); + } while (true) { JVMTIUtils.stopThread(worker2); @@ -151,6 +151,8 @@ public class AsyncExceptionOnMonitorEnter extends Thread { // not released worker2 will deadlock on enter JVMTIUtils.stopThread(worker1); } + // Give time to throw exception + Thread.sleep(10); if (!worker1.isAlive() && !worker2.isAlive()) { // Done with Thread.stop() calls since diff --git a/test/hotspot/jtreg/runtime/Thread/AsyncExceptionTest.java b/test/hotspot/jtreg/runtime/Thread/AsyncExceptionTest.java index 52fc4ca1d56..e15022a9fed 100644 --- a/test/hotspot/jtreg/runtime/Thread/AsyncExceptionTest.java +++ b/test/hotspot/jtreg/runtime/Thread/AsyncExceptionTest.java @@ -49,9 +49,11 @@ public class AsyncExceptionTest extends Thread { private final static int DEF_TIME_MAX = 30; // default max # secs to test private final static String PROG_NAME = "AsyncExceptionTest"; - public CountDownLatch startSyncObj = new CountDownLatch(1); + // Avoid using CountDownLatch or similar objects that require unparking the + // main thread. Otherwise, if the main thread is run as a virtual thread, the + // async exception could be sent while the target is still executing FJP logic. + public volatile boolean started = false; - private boolean firstEntry = true; private boolean receivedThreadDeathinInternal1 = false; private boolean receivedThreadDeathinInternal2 = false; private volatile RuntimeException error = null; @@ -77,6 +79,7 @@ public class AsyncExceptionTest extends Thread { public void internalRun1() { try { + started = true; while (!receivedThreadDeathinInternal2) { internalRun2(); } @@ -87,16 +90,10 @@ public class AsyncExceptionTest extends Thread { public void internalRun2() { try { - Integer myLocalCount = 1; - Integer myLocalCount2 = 1; + int myLocalCount = 1; + int myLocalCount2 = 1; - if (firstEntry) { - // Tell main thread we have started. - startSyncObj.countDown(); - firstEntry = false; - } - - while(myLocalCount > 0) { + while (myLocalCount > 0) { myLocalCount2 = (myLocalCount % 3) / 2; myLocalCount -= 1; } @@ -128,7 +125,9 @@ public class AsyncExceptionTest extends Thread { thread.start(); try { // Wait for the worker thread to get going. - thread.startSyncObj.await(); + while (!thread.started) { + Thread.sleep(1); + } // Send async exception and wait until it is thrown JVMTIUtils.stopThread(thread); thread.join(); From 33dda887d99d39b2d003fd6521db97d45da474f0 Mon Sep 17 00:00:00 2001 From: Christoph Langer Date: Thu, 4 Dec 2025 15:03:33 +0000 Subject: [PATCH 174/706] 8351842: Windows specific issues in combination of JEP 493 and --with-external-symbols-in-bundles=public Reviewed-by: erikj, mbaesken --- make/Bundles.gmk | 28 +------------------ make/Images.gmk | 22 +++++++++------ make/hotspot/lib/CompileJvm.gmk | 12 ++++---- src/hotspot/share/prims/whitebox.cpp | 15 ++++++++-- .../NMT/CheckForProperDetailStackTrace.java | 13 +++------ .../jdk/modules/etc/JmodExcludedFiles.java | 24 ++++++++-------- test/lib/jdk/test/whitebox/WhiteBox.java | 9 ++++-- 7 files changed, 56 insertions(+), 67 deletions(-) diff --git a/make/Bundles.gmk b/make/Bundles.gmk index cf3b77e4e52..8161b3b0362 100644 --- a/make/Bundles.gmk +++ b/make/Bundles.gmk @@ -125,13 +125,6 @@ define SetupBundleFileBody && $(TAR) cf - -$(TAR_INCLUDE_PARAM) $$($1_$$d_LIST_FILE) \ $(TAR_IGNORE_EXIT_VALUE) ) \ | ( $(CD) $(SUPPORT_OUTPUTDIR)/bundles/$1/$$($1_SUBDIR) && $(TAR) xf - )$$(NEWLINE) ) - # Rename stripped pdb files - ifeq ($(call isTargetOs, windows)+$(SHIP_DEBUG_SYMBOLS), true+public) - for f in `$(FIND) $(SUPPORT_OUTPUTDIR)/bundles/$1/$$($1_SUBDIR) -name "*.stripped.pdb"`; do \ - $(ECHO) Renaming $$$${f} to $$$${f%stripped.pdb}pdb $(LOG_INFO); \ - $(MV) $$$${f} $$$${f%stripped.pdb}pdb; \ - done - endif # Unzip any zipped debuginfo files ifeq ($$($1_UNZIP_DEBUGINFO), true) for f in `$(FIND) $(SUPPORT_OUTPUTDIR)/bundles/$1/$$($1_SUBDIR) -name "*.diz"`; do \ @@ -222,14 +215,6 @@ ifneq ($(filter product-bundles% legacy-bundles, $(MAKECMDGOALS)), ) ifeq ($(call isTargetOs, windows), true) ifeq ($(SHIP_DEBUG_SYMBOLS), ) JDK_SYMBOLS_EXCLUDE_PATTERN := %.pdb - else - ifeq ($(SHIP_DEBUG_SYMBOLS), public) - JDK_SYMBOLS_EXCLUDE_PATTERN := \ - $(filter-out \ - %.stripped.pdb, \ - $(filter %.pdb, $(ALL_JDK_FILES)) \ - ) - endif endif endif @@ -244,10 +229,7 @@ ifneq ($(filter product-bundles% legacy-bundles, $(MAKECMDGOALS)), ) ) JDK_SYMBOLS_BUNDLE_FILES := \ - $(filter-out \ - %.stripped.pdb, \ - $(call FindFiles, $(SYMBOLS_IMAGE_DIR)) \ - ) + $(call FindFiles, $(SYMBOLS_IMAGE_DIR)) TEST_DEMOS_BUNDLE_FILES := $(filter $(JDK_DEMOS_IMAGE_HOMEDIR)/demo/%, \ $(ALL_JDK_DEMOS_FILES)) @@ -267,14 +249,6 @@ ifneq ($(filter product-bundles% legacy-bundles, $(MAKECMDGOALS)), ) ifeq ($(call isTargetOs, windows), true) ifeq ($(SHIP_DEBUG_SYMBOLS), ) JRE_SYMBOLS_EXCLUDE_PATTERN := %.pdb - else - ifeq ($(SHIP_DEBUG_SYMBOLS), public) - JRE_SYMBOLS_EXCLUDE_PATTERN := \ - $(filter-out \ - %.stripped.pdb, \ - $(filter %.pdb, $(ALL_JRE_FILES)) \ - ) - endif endif endif diff --git a/make/Images.gmk b/make/Images.gmk index c5877e44c22..89c0a834477 100644 --- a/make/Images.gmk +++ b/make/Images.gmk @@ -282,29 +282,33 @@ else endif CMDS_TARGET_SUBDIR := bin -# Param 1 - either JDK or JRE +# Copy debug info files into symbols bundle. +# In case of Windows and --with-external-symbols-in-bundles=public, take care to remove *.stripped.pdb files SetupCopyDebuginfo = \ $(foreach m, $(ALL_$1_MODULES), \ + $(eval dbgfiles := $(call FindDebuginfoFiles, $(SUPPORT_OUTPUTDIR)/modules_libs/$m)) \ + $(eval dbgfiles := $(if $(filter true+public,$(call isTargetOs,windows)+$(SHIP_DEBUG_SYMBOLS)), \ + $(filter-out %.stripped.pdb,$(dbgfiles)),$(dbgfiles)) \ + ) \ $(eval $(call SetupCopyFiles, COPY_$1_LIBS_DEBUGINFO_$m, \ SRC := $(SUPPORT_OUTPUTDIR)/modules_libs/$m, \ DEST := $($1_IMAGE_DIR)/$(LIBS_TARGET_SUBDIR), \ - FILES := $(call FindDebuginfoFiles, \ - $(SUPPORT_OUTPUTDIR)/modules_libs/$m), \ + FILES := $(dbgfiles), \ )) \ $(eval $1_TARGETS += $$(COPY_$1_LIBS_DEBUGINFO_$m)) \ + $(eval dbgfiles := $(call FindDebuginfoFiles, $(SUPPORT_OUTPUTDIR)/modules_cmds/$m)) \ + $(eval dbgfiles := $(if $(filter true+public,$(call isTargetOs,windows)+$(SHIP_DEBUG_SYMBOLS)), \ + $(filter-out %.stripped.pdb,$(dbgfiles)),$(dbgfiles)) \ + ) \ $(eval $(call SetupCopyFiles, COPY_$1_CMDS_DEBUGINFO_$m, \ SRC := $(SUPPORT_OUTPUTDIR)/modules_cmds/$m, \ DEST := $($1_IMAGE_DIR)/$(CMDS_TARGET_SUBDIR), \ - FILES := $(call FindDebuginfoFiles, \ - $(SUPPORT_OUTPUTDIR)/modules_cmds/$m), \ + FILES := $(dbgfiles), \ )) \ $(eval $1_TARGETS += $$(COPY_$1_CMDS_DEBUGINFO_$m)) \ ) -# No space before argument to avoid having to put $(strip ) everywhere in -# implementation above. -$(call SetupCopyDebuginfo,JDK) -$(call SetupCopyDebuginfo,JRE) +# No space before argument to avoid having to put $(strip ) everywhere in implementation above. $(call SetupCopyDebuginfo,SYMBOLS) ################################################################################ diff --git a/make/hotspot/lib/CompileJvm.gmk b/make/hotspot/lib/CompileJvm.gmk index b0ea27e5081..39a549b7db0 100644 --- a/make/hotspot/lib/CompileJvm.gmk +++ b/make/hotspot/lib/CompileJvm.gmk @@ -151,6 +151,12 @@ JVM_STRIPFLAGS ?= $(STRIPFLAGS) # This source set is reused so save in cache. $(call FillFindCache, $(JVM_SRC_DIRS)) +ifeq ($(SHIP_DEBUG_SYMBOLS), full) + CFLAGS_SHIP_DEBUGINFO := -DSHIP_DEBUGINFO_FULL +else ifeq ($(SHIP_DEBUG_SYMBOLS), public) + CFLAGS_SHIP_DEBUGINFO := -DSHIP_DEBUGINFO_PUBLIC +endif + ifeq ($(call isTargetOs, windows), true) ifeq ($(STATIC_LIBS), true) WIN_EXPORT_FILE := $(JVM_OUTPUTDIR)/static-win-exports.def @@ -158,10 +164,6 @@ ifeq ($(call isTargetOs, windows), true) WIN_EXPORT_FILE := $(JVM_OUTPUTDIR)/win-exports.def endif - ifeq ($(SHIP_DEBUG_SYMBOLS), public) - CFLAGS_STRIPPED_DEBUGINFO := -DHAS_STRIPPED_DEBUGINFO - endif - JVM_LDFLAGS += -def:$(WIN_EXPORT_FILE) endif @@ -187,7 +189,7 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBJVM, \ CFLAGS := $(JVM_CFLAGS), \ abstract_vm_version.cpp_CXXFLAGS := $(CFLAGS_VM_VERSION), \ arguments.cpp_CXXFLAGS := $(CFLAGS_VM_VERSION), \ - whitebox.cpp_CXXFLAGS := $(CFLAGS_STRIPPED_DEBUGINFO), \ + whitebox.cpp_CXXFLAGS := $(CFLAGS_SHIP_DEBUGINFO), \ DISABLED_WARNINGS_gcc := $(DISABLED_WARNINGS_gcc), \ DISABLED_WARNINGS_gcc_ad_$(HOTSPOT_TARGET_CPU_ARCH).cpp := nonnull, \ DISABLED_WARNINGS_gcc_bytecodeInterpreter.cpp := unused-label, \ diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index bbd7b4bf795..a6ce092e40d 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -508,8 +508,16 @@ WB_ENTRY(jboolean, WB_ConcurrentGCRunTo(JNIEnv* env, jobject o, jobject at)) return ConcurrentGCBreakpoints::run_to(c_name); WB_END -WB_ENTRY(jboolean, WB_HasExternalSymbolsStripped(JNIEnv* env, jobject o)) -#if defined(HAS_STRIPPED_DEBUGINFO) +WB_ENTRY(jboolean, WB_ShipDebugInfoFull(JNIEnv* env, jobject o)) +#if defined(SHIP_DEBUGINFO_FULL) + return true; +#else + return false; +#endif +WB_END + +WB_ENTRY(jboolean, WB_ShipDebugInfoPublic(JNIEnv* env, jobject o)) +#if defined(SHIP_DEBUGINFO_PUBLIC) return true; #else return false; @@ -2840,7 +2848,8 @@ static JNINativeMethod methods[] = { {CC"getVMLargePageSize", CC"()J", (void*)&WB_GetVMLargePageSize}, {CC"getHeapSpaceAlignment", CC"()J", (void*)&WB_GetHeapSpaceAlignment}, {CC"getHeapAlignment", CC"()J", (void*)&WB_GetHeapAlignment}, - {CC"hasExternalSymbolsStripped", CC"()Z", (void*)&WB_HasExternalSymbolsStripped}, + {CC"shipsFullDebugInfo", CC"()Z", (void*)&WB_ShipDebugInfoFull}, + {CC"shipsPublicDebugInfo", CC"()Z", (void*)&WB_ShipDebugInfoPublic}, {CC"countAliveClasses0", CC"(Ljava/lang/String;)I", (void*)&WB_CountAliveClasses }, {CC"getSymbolRefcount", CC"(Ljava/lang/String;)I", (void*)&WB_GetSymbolRefcount }, {CC"parseCommandLine0", diff --git a/test/hotspot/jtreg/runtime/NMT/CheckForProperDetailStackTrace.java b/test/hotspot/jtreg/runtime/NMT/CheckForProperDetailStackTrace.java index 28af0692721..66c256be3cc 100644 --- a/test/hotspot/jtreg/runtime/NMT/CheckForProperDetailStackTrace.java +++ b/test/hotspot/jtreg/runtime/NMT/CheckForProperDetailStackTrace.java @@ -63,10 +63,9 @@ public class CheckForProperDetailStackTrace { private static final Path SRC_DIR = Paths.get(TEST_SRC, "src"); private static final Path MODS_DIR = Paths.get(TEST_CLASSES, "mods"); - // Windows has source information only in full pdbs, not in stripped pdbs - private static boolean expectSourceInformation = Platform.isLinux() || Platform.isWindows(); - - static WhiteBox wb = WhiteBox.getWhiteBox(); + // In some configurations on Windows, we could have stripped pdbs which do not have source information. + private static boolean expectSourceInformation = (Platform.isLinux() || Platform.isWindows()) && + WhiteBox.getWhiteBox().shipsFullDebugInfo(); /* The stack trace we look for by default. Note that :: has been replaced by .* to make sure it matches even if the symbol is not unmangled. @@ -145,12 +144,8 @@ public class CheckForProperDetailStackTrace { throw new RuntimeException("Expected stack trace missing from output"); } - if (wb.hasExternalSymbolsStripped()) { - expectSourceInformation = false; - } - - System.out.println("Looking for source information:"); if (expectSourceInformation) { + System.out.println("Looking for source information:"); if (!stackTraceMatches(".*moduleEntry.cpp.*", output)) { output.reportDiagnosticSummary(); throw new RuntimeException("Expected source information missing from output"); diff --git a/test/jdk/jdk/modules/etc/JmodExcludedFiles.java b/test/jdk/jdk/modules/etc/JmodExcludedFiles.java index 90ca6840d52..3929419a080 100644 --- a/test/jdk/jdk/modules/etc/JmodExcludedFiles.java +++ b/test/jdk/jdk/modules/etc/JmodExcludedFiles.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, 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,9 +25,12 @@ * @test * @bug 8159927 * @modules java.base/jdk.internal.util + * @library /test/lib * @requires jlink.packagedModules - * @run main JmodExcludedFiles - * @summary Test that JDK JMOD files do not include native debug symbols + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI JmodExcludedFiles + * @summary Test that JDK JMOD files do not include native debug symbols when it is not configured */ import java.nio.file.DirectoryStream; @@ -37,9 +40,11 @@ import java.nio.file.Paths; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import jdk.internal.util.OperatingSystem; +import jdk.test.whitebox.WhiteBox; public class JmodExcludedFiles { private static String javaHome = System.getProperty("java.home"); + private static final boolean expectSymbols = WhiteBox.getWhiteBox().shipsDebugInfo(); public static void main(String[] args) throws Exception { Path jmods = Path.of(javaHome, "jmods"); @@ -76,24 +81,19 @@ public class JmodExcludedFiles { if (i != -1) { if (n.substring(0, i).endsWith(".dSYM")) { System.err.println("Found symbols in " + jmod + ": " + name); - return true; + return expectSymbols ? false: true; } } } if (OperatingSystem.isWindows() && name.endsWith(".pdb")) { - // on Windows we check if we should have public symbols through --with-external-symbols-in-bundles=public (JDK-8237192) - String strippedpdb = javaHome + "/bin/" + name.substring(index + 1, name.length() - 4) + ".stripped.pdb"; - if (!Files.exists(Paths.get(strippedpdb))) { - System.err.println("Found symbols in " + jmod + ": " + name + - ". No stripped pdb file " + strippedpdb + " exists."); - return true; - } + System.err.println("Found symbols in " + jmod + ": " + name); + return expectSymbols ? false: true; } if (name.endsWith(".diz") || name.endsWith(".debuginfo") || name.endsWith(".map")) { System.err.println("Found symbols in " + jmod + ": " + name); - return true; + return expectSymbols ? false: true; } } return false; diff --git a/test/lib/jdk/test/whitebox/WhiteBox.java b/test/lib/jdk/test/whitebox/WhiteBox.java index 5741745e064..8e30c089bcb 100644 --- a/test/lib/jdk/test/whitebox/WhiteBox.java +++ b/test/lib/jdk/test/whitebox/WhiteBox.java @@ -66,7 +66,7 @@ public class WhiteBox { // Memory private native long getObjectAddress0(Object o); - public long getObjectAddress(Object o) { + public long getObjectAddress(Object o) { Objects.requireNonNull(o); return getObjectAddress0(o); } @@ -78,7 +78,12 @@ public class WhiteBox { public native long getHeapSpaceAlignment(); public native long getHeapAlignment(); - public native boolean hasExternalSymbolsStripped(); + public native boolean shipsFullDebugInfo(); + public native boolean shipsPublicDebugInfo(); + + public boolean shipsDebugInfo() { + return shipsFullDebugInfo() || shipsPublicDebugInfo(); + } private native boolean isObjectInOldGen0(Object o); public boolean isObjectInOldGen(Object o) { From 2735140147b159d3a3238804f221db4f835ef744 Mon Sep 17 00:00:00 2001 From: Roland Westrelin Date: Thu, 4 Dec 2025 15:25:37 +0000 Subject: [PATCH 175/706] 8370939: C2: SIGSEGV in SafePointNode::verify_input when processing MH call from Compile::process_late_inline_calls_no_inline() Reviewed-by: thartmann, vlivanov --- src/hotspot/share/opto/callGenerator.cpp | 3 +- src/hotspot/share/opto/callnode.cpp | 1 - src/hotspot/share/opto/callnode.hpp | 7 +- src/hotspot/share/opto/compile.cpp | 4 +- src/hotspot/share/opto/compile.hpp | 9 +- .../inlining/TestLateMHClonedCallNode.java | 110 ++++++++++++++++++ 6 files changed, 122 insertions(+), 12 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/inlining/TestLateMHClonedCallNode.java diff --git a/src/hotspot/share/opto/callGenerator.cpp b/src/hotspot/share/opto/callGenerator.cpp index 483cb731103..db03dd9d80c 100644 --- a/src/hotspot/share/opto/callGenerator.cpp +++ b/src/hotspot/share/opto/callGenerator.cpp @@ -420,7 +420,6 @@ bool LateInlineMHCallGenerator::do_late_inline_check(Compile* C, JVMState* jvms) } assert(!cg->is_late_inline() || cg->is_mh_late_inline() || AlwaysIncrementalInline || StressIncrementalInlining, "we're doing late inlining"); _inline_cg = cg; - C->dec_number_of_mh_late_inlines(); return true; } else { // Method handle call which has a constant appendix argument should be either inlined or replaced with a direct call @@ -432,7 +431,7 @@ bool LateInlineMHCallGenerator::do_late_inline_check(Compile* C, JVMState* jvms) CallGenerator* CallGenerator::for_mh_late_inline(ciMethod* caller, ciMethod* callee, bool input_not_const) { assert(IncrementalInlineMH, "required"); - Compile::current()->inc_number_of_mh_late_inlines(); + Compile::current()->mark_has_mh_late_inlines(); CallGenerator* cg = new LateInlineMHCallGenerator(caller, callee, input_not_const); return cg; } diff --git a/src/hotspot/share/opto/callnode.cpp b/src/hotspot/share/opto/callnode.cpp index ad6548a649e..4cf72fbde4b 100644 --- a/src/hotspot/share/opto/callnode.cpp +++ b/src/hotspot/share/opto/callnode.cpp @@ -1145,7 +1145,6 @@ Node* CallStaticJavaNode::Ideal(PhaseGVN* phase, bool can_reshape) { assert(callee->has_member_arg(), "wrong type of call?"); if (in(TypeFunc::Parms + callee->arg_size() - 1)->Opcode() == Op_ConP) { register_for_late_inline(); - phase->C->inc_number_of_mh_late_inlines(); } } } else { diff --git a/src/hotspot/share/opto/callnode.hpp b/src/hotspot/share/opto/callnode.hpp index 9029a009989..90a86d76679 100644 --- a/src/hotspot/share/opto/callnode.hpp +++ b/src/hotspot/share/opto/callnode.hpp @@ -730,9 +730,10 @@ public: // for some macro nodes whose expansion does not have a safepoint on the fast path. virtual bool guaranteed_safepoint() { return true; } // For macro nodes, the JVMState gets modified during expansion. If calls - // use MachConstantBase, it gets modified during matching. So when cloning - // the node the JVMState must be deep cloned. Default is to shallow clone. - virtual bool needs_deep_clone_jvms(Compile* C) { return C->needs_deep_clone_jvms(); } + // use MachConstantBase, it gets modified during matching. If the call is + // late inlined, it also needs the full JVMState. So when cloning the + // node the JVMState must be deep cloned. Default is to shallow clone. + virtual bool needs_deep_clone_jvms(Compile* C) { return _generator != nullptr || C->needs_deep_clone_jvms(); } // Returns true if the call may modify n virtual bool may_modify(const TypeOopPtr* t_oop, PhaseValues* phase); diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index 89b5e36b120..a89b5b00a25 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -686,7 +686,7 @@ Compile::Compile(ciEnv* ci_env, ciMethod* target, int osr_bci, _boxing_late_inlines(comp_arena(), 2, 0, nullptr), _vector_reboxing_late_inlines(comp_arena(), 2, 0, nullptr), _late_inlines_pos(0), - _number_of_mh_late_inlines(0), + _has_mh_late_inlines(false), _oom(false), _replay_inline_data(nullptr), _inline_printer(this), @@ -948,7 +948,7 @@ Compile::Compile(ciEnv* ci_env, _igvn_worklist(nullptr), _types(nullptr), _node_hash(nullptr), - _number_of_mh_late_inlines(0), + _has_mh_late_inlines(false), _oom(false), _replay_inline_data(nullptr), _inline_printer(this), diff --git a/src/hotspot/share/opto/compile.hpp b/src/hotspot/share/opto/compile.hpp index 845dcf07512..f5611062f2c 100644 --- a/src/hotspot/share/opto/compile.hpp +++ b/src/hotspot/share/opto/compile.hpp @@ -478,7 +478,9 @@ private: GrowableArray _vector_reboxing_late_inlines; // same but for vector reboxing operations int _late_inlines_pos; // Where in the queue should the next late inlining candidate go (emulate depth first inlining) - uint _number_of_mh_late_inlines; // number of method handle late inlining still pending + bool _has_mh_late_inlines; // Can there still be a method handle late inlining pending? + // false: there can't be one + // true: we've enqueued one at some point so there may still be one // "MemLimit" directive was specified and the memory limit was hit during compilation bool _oom; @@ -1096,9 +1098,8 @@ public: } } - void inc_number_of_mh_late_inlines() { _number_of_mh_late_inlines++; } - void dec_number_of_mh_late_inlines() { assert(_number_of_mh_late_inlines > 0, "_number_of_mh_late_inlines < 0 !"); _number_of_mh_late_inlines--; } - bool has_mh_late_inlines() const { return _number_of_mh_late_inlines > 0; } + void mark_has_mh_late_inlines() { _has_mh_late_inlines = true; } + bool has_mh_late_inlines() const { return _has_mh_late_inlines; } bool inline_incrementally_one(); void inline_incrementally_cleanup(PhaseIterGVN& igvn); diff --git a/test/hotspot/jtreg/compiler/inlining/TestLateMHClonedCallNode.java b/test/hotspot/jtreg/compiler/inlining/TestLateMHClonedCallNode.java new file mode 100644 index 00000000000..417fe60ebae --- /dev/null +++ b/test/hotspot/jtreg/compiler/inlining/TestLateMHClonedCallNode.java @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2025 IBM Corporation. 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 8370939 + * @summary C2: SIGSEGV in SafePointNode::verify_input when processing MH call from Compile::process_late_inline_calls_no_inline() + * @run main/othervm -XX:-BackgroundCompilation -XX:CompileOnly=TestLateMHClonedCallNode::test1 + * -XX:CompileOnly=TestLateMHClonedCallNode::test2 TestLateMHClonedCallNode + * @run main TestLateMHClonedCallNode + */ + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; + +public class TestLateMHClonedCallNode { + private static int field; + + public static void main(String[] args) throws Throwable { + for (int i = 0; i < 20_000; i++) { + test1(true); + test1(false); + test2(true); + test2(false); + } + } + + private static int test1(boolean flag) throws Throwable { + return inlined1(flag); + } + + private static int inlined1(boolean flag) throws Throwable { + MethodHandle mh = mh1; + for (int i = 0; i < 3; ++i) { + if (i > 1) { + mh = mh2; + } + } + int res = 0; + for (int i = 0; i < 2; i++) { + if (!flag) { + field = 42; + } + res += (int) mh.invokeExact(); + } + return res; + } + + private static int test2(boolean flag) throws Throwable { + int res = (int)unknownMh.invokeExact(); + return inlined2(flag); + } + + private static int inlined2(boolean flag) throws Throwable { + MethodHandle mh = mh1; + for (int i = 0; i < 3; ++i) { + if (i > 1) { + mh = mh2; + } + } + int res = 0; + for (int i = 0; i < 2; i++) { + if (!flag) { + field = 42; + } + res += (int) mh.invokeExact(); + } + return res; + } + + static final MethodHandle mh1; + static final MethodHandle mh2; + static MethodHandle unknownMh; + + static { + try { + MethodHandles.Lookup lookup = MethodHandles.lookup(); + mh1 = lookup.findStatic(TestLateMHClonedCallNode.class, "method1", MethodType.methodType(int.class)); + mh2 = lookup.findStatic(TestLateMHClonedCallNode.class, "method2", MethodType.methodType(int.class)); + unknownMh = mh1; + } catch (NoSuchMethodException | IllegalAccessException e) { + e.printStackTrace(); + throw new RuntimeException("Method handle lookup failed"); + } + } + + static int method1() { return 0; } + static int method2() { return 42; } +} From 45dcc0e7e26b8130236c5ba80edb54fa530dab57 Mon Sep 17 00:00:00 2001 From: Kurt Miller Date: Thu, 4 Dec 2025 16:59:03 +0000 Subject: [PATCH 176/706] 8371914: PNG defines in CFLAGS can cause compilation errors with external libpng Reviewed-by: erikj, jdv --- .../java.desktop/lib/ClientLibraries.gmk | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/make/modules/java.desktop/lib/ClientLibraries.gmk b/make/modules/java.desktop/lib/ClientLibraries.gmk index 4cd7f5bac90..f273065a6df 100644 --- a/make/modules/java.desktop/lib/ClientLibraries.gmk +++ b/make/modules/java.desktop/lib/ClientLibraries.gmk @@ -164,6 +164,24 @@ ifeq ($(ENABLE_HEADLESS_ONLY), false) ifeq ($(USE_EXTERNAL_LIBPNG), false) LIBSPLASHSCREEN_HEADER_DIRS += libsplashscreen/libpng + LIBSPLASHSCREEN_CFLAGS += -DPNG_NO_MMX_CODE -DPNG_ARM_NEON_OPT=0 + -DPNG_ARM_NEON_IMPLEMENTATION=0 -DPNG_LOONGARCH_LSX_OPT=0 + + ifeq ($(call isTargetOs, linux)+$(call isTargetCpuArch, ppc), true+true) + LIBSPLASHSCREEN_CFLAGS += -DPNG_POWERPC_VSX_OPT=0 + endif + + # The libpng bundled with jdk is a reduced version which does not + # contain .png_init_filter_functions_vsx. + # Therefore we need to disable PNG_POWERPC_VSX_OPT explicitly by setting + # it to 0. If this define is not set, it would be automatically set to 2, + # because + # "#if defined(__PPC64__) && defined(__ALTIVEC__) && defined(__VSX__)" + # expands to true. This would results in the fact that + # .png_init_filter_functions_vsx is needed in libpng. + ifeq ($(call isTargetOs, aix), true) + LIBSPLASHSCREEN_CFLAGS += -DPNG_POWERPC_VSX_OPT=0 + endif else LIBSPLASHSCREEN_EXCLUDES += libpng endif @@ -176,25 +194,7 @@ ifeq ($(ENABLE_HEADLESS_ONLY), false) LIBSPLASHSCREEN_STATIC_LIB_EXCLUDE_OBJS += $(LIBZIP_OBJS) endif - LIBSPLASHSCREEN_CFLAGS += -DSPLASHSCREEN -DPNG_NO_MMX_CODE \ - -DPNG_ARM_NEON_OPT=0 -DPNG_ARM_NEON_IMPLEMENTATION=0 \ - -DPNG_LOONGARCH_LSX_OPT=0 - - ifeq ($(call isTargetOs, linux)+$(call isTargetCpuArch, ppc), true+true) - LIBSPLASHSCREEN_CFLAGS += -DPNG_POWERPC_VSX_OPT=0 - endif - - # The external libpng submitted in the jdk is a reduced version - # which does not contain .png_init_filter_functions_vsx. - # Therefore we need to disable PNG_POWERPC_VSX_OPT explicitly by setting - # it to 0. If this define is not set, it would be automatically set to 2, - # because - # "#if defined(__PPC64__) && defined(__ALTIVEC__) && defined(__VSX__)" - # expands to true. This would results in the fact that - # .png_init_filter_functions_vsx is needed in libpng. - ifeq ($(call isTargetOs, aix), true) - LIBSPLASHSCREEN_CFLAGS += -DPNG_POWERPC_VSX_OPT=0 - endif + LIBSPLASHSCREEN_CFLAGS += -DSPLASHSCREEN ifeq ($(call isTargetOs, macosx), true) # libsplashscreen on macosx does not use the unix code From c55287d197ef024033f8dfbb5a365cb091bc67fb Mon Sep 17 00:00:00 2001 From: Nizar Benalla Date: Thu, 4 Dec 2025 17:01:41 +0000 Subject: [PATCH 177/706] 8370890: Start of release updates for JDK 27 8370893: Add SourceVersion.RELEASE_27 8370894: Add source 27 and target 27 to javac Reviewed-by: darcy, iris, liach, erikj, dholmes --- .jcheck/conf | 2 +- make/conf/version-numbers.conf | 10 +- .../share/classfile/classFileParser.cpp | 2 + .../java/lang/classfile/ClassFile.java | 10 +- .../lang/reflect/ClassFileFormatVersion.java | 14 +- .../javax/lang/model/SourceVersion.java | 19 +- .../AbstractAnnotationValueVisitor14.java | 2 +- ...AbstractAnnotationValueVisitorPreview.java | 2 +- .../model/util/AbstractElementVisitor14.java | 2 +- .../util/AbstractElementVisitorPreview.java | 2 +- .../model/util/AbstractTypeVisitor14.java | 2 +- .../util/AbstractTypeVisitorPreview.java | 2 +- .../lang/model/util/ElementKindVisitor14.java | 2 +- .../model/util/ElementKindVisitorPreview.java | 2 +- .../lang/model/util/ElementScanner14.java | 2 +- .../model/util/ElementScannerPreview.java | 2 +- .../util/SimpleAnnotationValueVisitor14.java | 2 +- .../SimpleAnnotationValueVisitorPreview.java | 2 +- .../model/util/SimpleElementVisitor14.java | 2 +- .../util/SimpleElementVisitorPreview.java | 2 +- .../lang/model/util/SimpleTypeVisitor14.java | 2 +- .../model/util/SimpleTypeVisitorPreview.java | 2 +- .../lang/model/util/TypeKindVisitor14.java | 2 +- .../model/util/TypeKindVisitorPreview.java | 2 +- .../com/sun/tools/javac/code/Source.java | 7 + .../com/sun/tools/javac/jvm/ClassFile.java | 1 + .../com/sun/tools/javac/jvm/Target.java | 3 + .../javac/processing/PrintingProcessor.java | 2 +- .../share/data/symbols/java.base-Q.sym.txt | 558 ++++++++++++++++++ .../data/symbols/java.compiler-Q.sym.txt | 85 +++ .../share/data/symbols/java.desktop-Q.sym.txt | 90 +++ .../data/symbols/java.management-Q.sym.txt | 37 ++ .../data/symbols/java.net.http-Q.sym.txt | 125 ++++ .../data/symbols/jdk.httpserver-Q.sym.txt | 32 + .../symbols/jdk.incubator.vector-Q.sym.txt | 32 + .../share/data/symbols/jdk.jartool-Q.sym.txt | 31 + .../share/data/symbols/jdk.jdeps-Q.sym.txt | 31 + .../share/data/symbols/jdk.jfr-Q.sym.txt | 31 + .../share/data/symbols/jdk.jlink-Q.sym.txt | 31 + .../share/data/symbols/jdk.jshell-Q.sym.txt | 169 ++++++ .../share/data/symbols/jdk.jsobject-Q.sym.txt | 34 ++ .../data/symbols/jdk.localedata-Q.sym.txt | 31 + src/jdk.compiler/share/data/symbols/symbols | 3 +- test/jdk/ProblemList.txt | 1 + .../javac/api/TestGetSourceVersions.java | 4 +- .../javac/classfiles/ClassVersionChecker.java | 3 +- .../lib/JavacTestingAbstractProcessor.java | 18 +- .../classReaderTest/Client.nopreview.out | 2 +- .../classReaderTest/Client.preview.out | 2 +- .../tools/javac/versions/Versions.java | 7 +- 50 files changed, 1415 insertions(+), 48 deletions(-) create mode 100644 src/jdk.compiler/share/data/symbols/java.base-Q.sym.txt create mode 100644 src/jdk.compiler/share/data/symbols/java.compiler-Q.sym.txt create mode 100644 src/jdk.compiler/share/data/symbols/java.desktop-Q.sym.txt create mode 100644 src/jdk.compiler/share/data/symbols/java.management-Q.sym.txt create mode 100644 src/jdk.compiler/share/data/symbols/java.net.http-Q.sym.txt create mode 100644 src/jdk.compiler/share/data/symbols/jdk.httpserver-Q.sym.txt create mode 100644 src/jdk.compiler/share/data/symbols/jdk.incubator.vector-Q.sym.txt create mode 100644 src/jdk.compiler/share/data/symbols/jdk.jartool-Q.sym.txt create mode 100644 src/jdk.compiler/share/data/symbols/jdk.jdeps-Q.sym.txt create mode 100644 src/jdk.compiler/share/data/symbols/jdk.jfr-Q.sym.txt create mode 100644 src/jdk.compiler/share/data/symbols/jdk.jlink-Q.sym.txt create mode 100644 src/jdk.compiler/share/data/symbols/jdk.jshell-Q.sym.txt create mode 100644 src/jdk.compiler/share/data/symbols/jdk.jsobject-Q.sym.txt create mode 100644 src/jdk.compiler/share/data/symbols/jdk.localedata-Q.sym.txt diff --git a/.jcheck/conf b/.jcheck/conf index 60881e74d2a..25af49f8ef8 100644 --- a/.jcheck/conf +++ b/.jcheck/conf @@ -1,7 +1,7 @@ [general] project=jdk jbs=JDK -version=26 +version=27 [checks] error=author,committer,reviewers,merge,issues,executable,symlink,message,hg-tag,whitespace,problemlists,copyright diff --git a/make/conf/version-numbers.conf b/make/conf/version-numbers.conf index 977809535ba..4392d86ac33 100644 --- a/make/conf/version-numbers.conf +++ b/make/conf/version-numbers.conf @@ -26,17 +26,17 @@ # Default version, product, and vendor information to use, # unless overridden by configure -DEFAULT_VERSION_FEATURE=26 +DEFAULT_VERSION_FEATURE=27 DEFAULT_VERSION_INTERIM=0 DEFAULT_VERSION_UPDATE=0 DEFAULT_VERSION_PATCH=0 DEFAULT_VERSION_EXTRA1=0 DEFAULT_VERSION_EXTRA2=0 DEFAULT_VERSION_EXTRA3=0 -DEFAULT_VERSION_DATE=2026-03-17 -DEFAULT_VERSION_CLASSFILE_MAJOR=70 # "`$EXPR $DEFAULT_VERSION_FEATURE + 44`" +DEFAULT_VERSION_DATE=2026-09-15 +DEFAULT_VERSION_CLASSFILE_MAJOR=71 # "`$EXPR $DEFAULT_VERSION_FEATURE + 44`" DEFAULT_VERSION_CLASSFILE_MINOR=0 DEFAULT_VERSION_DOCS_API_SINCE=11 -DEFAULT_ACCEPTABLE_BOOT_VERSIONS="25 26" -DEFAULT_JDK_SOURCE_TARGET_VERSION=26 +DEFAULT_ACCEPTABLE_BOOT_VERSIONS="25 26 27" +DEFAULT_JDK_SOURCE_TARGET_VERSION=27 DEFAULT_PROMOTED_VERSION_PRE=ea diff --git a/src/hotspot/share/classfile/classFileParser.cpp b/src/hotspot/share/classfile/classFileParser.cpp index 312accb1df9..c9d9d3632b5 100644 --- a/src/hotspot/share/classfile/classFileParser.cpp +++ b/src/hotspot/share/classfile/classFileParser.cpp @@ -154,6 +154,8 @@ #define JAVA_26_VERSION 70 +#define JAVA_27_VERSION 71 + void ClassFileParser::set_class_bad_constant_seen(short bad_constant) { assert((bad_constant == JVM_CONSTANT_Module || bad_constant == JVM_CONSTANT_Package) && _major_version >= JAVA_9_VERSION, 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 216facbdddf..5a2b7e6297e 100644 --- a/src/java.base/share/classes/java/lang/classfile/ClassFile.java +++ b/src/java.base/share/classes/java/lang/classfile/ClassFile.java @@ -1038,6 +1038,14 @@ public sealed interface ClassFile */ int JAVA_26_VERSION = 70; + /** + * The class major version introduced by Java SE 27, {@value}. + * + * @see ClassFileFormatVersion#RELEASE_27 + * @since 27 + */ + int JAVA_27_VERSION = 71; + /** * A minor version number {@value} indicating a class uses preview features * of a Java SE release since 12, for major versions {@value @@ -1049,7 +1057,7 @@ public sealed interface ClassFile * {@return the latest class major version supported by the current runtime} */ static int latestMajorVersion() { - return JAVA_26_VERSION; + return JAVA_27_VERSION; } /** diff --git a/src/java.base/share/classes/java/lang/reflect/ClassFileFormatVersion.java b/src/java.base/share/classes/java/lang/reflect/ClassFileFormatVersion.java index a4009915922..1990a467b60 100644 --- a/src/java.base/share/classes/java/lang/reflect/ClassFileFormatVersion.java +++ b/src/java.base/share/classes/java/lang/reflect/ClassFileFormatVersion.java @@ -383,6 +383,18 @@ public enum ClassFileFormatVersion { * The Java Virtual Machine Specification, Java SE 26 Edition */ RELEASE_26(70), + + /** + * The version introduced by the Java Platform, Standard Edition + * 27. + * + * @since 27 + * + * @see + * The Java Virtual Machine Specification, Java SE 27 Edition + */ + RELEASE_27(71), ; // Reduce code churn when appending new constants // Note to maintainers: when adding constants for newer releases, @@ -398,7 +410,7 @@ public enum ClassFileFormatVersion { * {@return the latest class file format version} */ public static ClassFileFormatVersion latest() { - return RELEASE_26; + return RELEASE_27; } /** 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 e21e9e1db9a..2835143dc4e 100644 --- a/src/java.compiler/share/classes/javax/lang/model/SourceVersion.java +++ b/src/java.compiler/share/classes/javax/lang/model/SourceVersion.java @@ -86,7 +86,8 @@ public enum SourceVersion { * (primitive Types in Patterns, instanceof, and switch in * third preview) * 26: no changes (primitive Types in Patterns, instanceof, and - * switch in in fourth preview) + * switch in fourth preview) + * 27: tbd */ /** @@ -484,6 +485,18 @@ public enum SourceVersion { * The Java Language Specification, Java SE 26 Edition */ RELEASE_26, + + /** + * The version introduced by the Java Platform, Standard Edition + * 27. + * + * @since 27 + * + * @see + * The Java Language Specification, Java SE 27 Edition + */ + RELEASE_27, ; // Reduce code churn when appending new constants // Note that when adding constants for newer releases, the @@ -493,7 +506,7 @@ public enum SourceVersion { * {@return the latest source version that can be modeled} */ public static SourceVersion latest() { - return RELEASE_26; + return RELEASE_27; } private static final SourceVersion latestSupported = getLatestSupported(); @@ -508,7 +521,7 @@ public enum SourceVersion { private static SourceVersion getLatestSupported() { int intVersion = Runtime.version().feature(); return (intVersion >= 11) ? - valueOf("RELEASE_" + Math.min(26, intVersion)): + valueOf("RELEASE_" + Math.min(27, intVersion)): RELEASE_10; } diff --git a/src/java.compiler/share/classes/javax/lang/model/util/AbstractAnnotationValueVisitor14.java b/src/java.compiler/share/classes/javax/lang/model/util/AbstractAnnotationValueVisitor14.java index 2b2f80358b0..bfd3b64a757 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/AbstractAnnotationValueVisitor14.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/AbstractAnnotationValueVisitor14.java @@ -44,7 +44,7 @@ import javax.annotation.processing.SupportedSourceVersion; * @see AbstractAnnotationValueVisitor9 * @since 14 */ -@SupportedSourceVersion(RELEASE_26) +@SupportedSourceVersion(RELEASE_27) public abstract class AbstractAnnotationValueVisitor14 extends AbstractAnnotationValueVisitor9 { /** diff --git a/src/java.compiler/share/classes/javax/lang/model/util/AbstractAnnotationValueVisitorPreview.java b/src/java.compiler/share/classes/javax/lang/model/util/AbstractAnnotationValueVisitorPreview.java index 59d1eb28282..31d0545744a 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/AbstractAnnotationValueVisitorPreview.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/AbstractAnnotationValueVisitorPreview.java @@ -50,7 +50,7 @@ import javax.annotation.processing.ProcessingEnvironment; * @see AbstractAnnotationValueVisitor14 * @since 23 */ -@SupportedSourceVersion(RELEASE_26) +@SupportedSourceVersion(RELEASE_27) @PreviewFeature(feature=PreviewFeature.Feature.LANGUAGE_MODEL, reflective=true) public abstract class AbstractAnnotationValueVisitorPreview extends AbstractAnnotationValueVisitor14 { diff --git a/src/java.compiler/share/classes/javax/lang/model/util/AbstractElementVisitor14.java b/src/java.compiler/share/classes/javax/lang/model/util/AbstractElementVisitor14.java index b624bb9f999..72b796a2cb7 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/AbstractElementVisitor14.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/AbstractElementVisitor14.java @@ -50,7 +50,7 @@ import static javax.lang.model.SourceVersion.*; * @see AbstractElementVisitor9 * @since 16 */ -@SupportedSourceVersion(RELEASE_26) +@SupportedSourceVersion(RELEASE_27) public abstract class AbstractElementVisitor14 extends AbstractElementVisitor9 { /** * Constructor for concrete subclasses to call. diff --git a/src/java.compiler/share/classes/javax/lang/model/util/AbstractElementVisitorPreview.java b/src/java.compiler/share/classes/javax/lang/model/util/AbstractElementVisitorPreview.java index 761916a1434..009cf06a8ce 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/AbstractElementVisitorPreview.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/AbstractElementVisitorPreview.java @@ -53,7 +53,7 @@ import static javax.lang.model.SourceVersion.*; * @see AbstractElementVisitor14 * @since 23 */ -@SupportedSourceVersion(RELEASE_26) +@SupportedSourceVersion(RELEASE_27) @PreviewFeature(feature=PreviewFeature.Feature.LANGUAGE_MODEL, reflective=true) public abstract class AbstractElementVisitorPreview extends AbstractElementVisitor14 { /** diff --git a/src/java.compiler/share/classes/javax/lang/model/util/AbstractTypeVisitor14.java b/src/java.compiler/share/classes/javax/lang/model/util/AbstractTypeVisitor14.java index 1860cd09ac5..95dfc473da1 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/AbstractTypeVisitor14.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/AbstractTypeVisitor14.java @@ -47,7 +47,7 @@ import static javax.lang.model.SourceVersion.*; * @see AbstractTypeVisitor9 * @since 14 */ -@SupportedSourceVersion(RELEASE_26) +@SupportedSourceVersion(RELEASE_27) public abstract class AbstractTypeVisitor14 extends AbstractTypeVisitor9 { /** * Constructor for concrete subclasses to call. diff --git a/src/java.compiler/share/classes/javax/lang/model/util/AbstractTypeVisitorPreview.java b/src/java.compiler/share/classes/javax/lang/model/util/AbstractTypeVisitorPreview.java index 6b701262a4f..257d7f5aa17 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/AbstractTypeVisitorPreview.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/AbstractTypeVisitorPreview.java @@ -53,7 +53,7 @@ import static javax.lang.model.SourceVersion.*; * @see AbstractTypeVisitor14 * @since 23 */ -@SupportedSourceVersion(RELEASE_26) +@SupportedSourceVersion(RELEASE_27) @PreviewFeature(feature=PreviewFeature.Feature.LANGUAGE_MODEL, reflective=true) public abstract class AbstractTypeVisitorPreview extends AbstractTypeVisitor14 { /** diff --git a/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitor14.java b/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitor14.java index cb0e1cfbc9f..58b1d81bcf9 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitor14.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitor14.java @@ -61,7 +61,7 @@ import javax.lang.model.SourceVersion; * @see ElementKindVisitor9 * @since 16 */ -@SupportedSourceVersion(RELEASE_26) +@SupportedSourceVersion(RELEASE_27) public class ElementKindVisitor14 extends ElementKindVisitor9 { /** * Constructor for concrete subclasses; uses {@code null} for the diff --git a/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitorPreview.java b/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitorPreview.java index 0f436e6d1e5..e2183185b80 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitorPreview.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitorPreview.java @@ -67,7 +67,7 @@ import static javax.lang.model.SourceVersion.*; * @see ElementKindVisitor14 * @since 23 */ -@SupportedSourceVersion(RELEASE_26) +@SupportedSourceVersion(RELEASE_27) @PreviewFeature(feature=PreviewFeature.Feature.LANGUAGE_MODEL, reflective=true) public class ElementKindVisitorPreview extends ElementKindVisitor14 { /** diff --git a/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner14.java b/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner14.java index 946cf97b092..6f7d8bc5fed 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner14.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner14.java @@ -77,7 +77,7 @@ import static javax.lang.model.SourceVersion.*; * @see ElementScanner9 * @since 16 */ -@SupportedSourceVersion(RELEASE_26) +@SupportedSourceVersion(RELEASE_27) public class ElementScanner14 extends ElementScanner9 { /** * Constructor for concrete subclasses; uses {@code null} for the diff --git a/src/java.compiler/share/classes/javax/lang/model/util/ElementScannerPreview.java b/src/java.compiler/share/classes/javax/lang/model/util/ElementScannerPreview.java index a9d8e7c1f3f..27080c7abc5 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/ElementScannerPreview.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/ElementScannerPreview.java @@ -81,7 +81,7 @@ import static javax.lang.model.SourceVersion.*; * @see ElementScanner14 * @since 23 */ -@SupportedSourceVersion(RELEASE_26) +@SupportedSourceVersion(RELEASE_27) @PreviewFeature(feature=PreviewFeature.Feature.LANGUAGE_MODEL, reflective=true) public class ElementScannerPreview extends ElementScanner14 { /** diff --git a/src/java.compiler/share/classes/javax/lang/model/util/SimpleAnnotationValueVisitor14.java b/src/java.compiler/share/classes/javax/lang/model/util/SimpleAnnotationValueVisitor14.java index 9320e18d5dd..a5e32c936e4 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/SimpleAnnotationValueVisitor14.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/SimpleAnnotationValueVisitor14.java @@ -52,7 +52,7 @@ import static javax.lang.model.SourceVersion.*; * @see SimpleAnnotationValueVisitor9 * @since 14 */ -@SupportedSourceVersion(RELEASE_26) +@SupportedSourceVersion(RELEASE_27) public class SimpleAnnotationValueVisitor14 extends SimpleAnnotationValueVisitor9 { /** * Constructor for concrete subclasses; uses {@code null} for the diff --git a/src/java.compiler/share/classes/javax/lang/model/util/SimpleAnnotationValueVisitorPreview.java b/src/java.compiler/share/classes/javax/lang/model/util/SimpleAnnotationValueVisitorPreview.java index 01509c0c4a5..a98161812fe 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/SimpleAnnotationValueVisitorPreview.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/SimpleAnnotationValueVisitorPreview.java @@ -58,7 +58,7 @@ import static javax.lang.model.SourceVersion.*; * @see SimpleAnnotationValueVisitor14 * @since 23 */ -@SupportedSourceVersion(RELEASE_26) +@SupportedSourceVersion(RELEASE_27) @PreviewFeature(feature=PreviewFeature.Feature.LANGUAGE_MODEL, reflective=true) public class SimpleAnnotationValueVisitorPreview extends SimpleAnnotationValueVisitor14 { /** diff --git a/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitor14.java b/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitor14.java index dff1731d3c9..da9797b2750 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitor14.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitor14.java @@ -58,7 +58,7 @@ import static javax.lang.model.SourceVersion.*; * @see SimpleElementVisitor9 * @since 16 */ -@SupportedSourceVersion(RELEASE_26) +@SupportedSourceVersion(RELEASE_27) public class SimpleElementVisitor14 extends SimpleElementVisitor9 { /** * Constructor for concrete subclasses; uses {@code null} for the diff --git a/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitorPreview.java b/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitorPreview.java index c3896a794c0..158dd24450f 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitorPreview.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitorPreview.java @@ -61,7 +61,7 @@ import static javax.lang.model.SourceVersion.*; * @see SimpleElementVisitor14 * @since 23 */ -@SupportedSourceVersion(RELEASE_26) +@SupportedSourceVersion(RELEASE_27) @PreviewFeature(feature=PreviewFeature.Feature.LANGUAGE_MODEL, reflective=true) public class SimpleElementVisitorPreview extends SimpleElementVisitor14 { /** diff --git a/src/java.compiler/share/classes/javax/lang/model/util/SimpleTypeVisitor14.java b/src/java.compiler/share/classes/javax/lang/model/util/SimpleTypeVisitor14.java index d06f5d673d3..07b6b2bedbe 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/SimpleTypeVisitor14.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/SimpleTypeVisitor14.java @@ -56,7 +56,7 @@ import static javax.lang.model.SourceVersion.*; * @see SimpleTypeVisitor9 * @since 14 */ -@SupportedSourceVersion(RELEASE_26) +@SupportedSourceVersion(RELEASE_27) public class SimpleTypeVisitor14 extends SimpleTypeVisitor9 { /** * Constructor for concrete subclasses; uses {@code null} for the diff --git a/src/java.compiler/share/classes/javax/lang/model/util/SimpleTypeVisitorPreview.java b/src/java.compiler/share/classes/javax/lang/model/util/SimpleTypeVisitorPreview.java index 11e2e8a50d5..ff9a3050e12 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/SimpleTypeVisitorPreview.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/SimpleTypeVisitorPreview.java @@ -62,7 +62,7 @@ import static javax.lang.model.SourceVersion.*; * @see SimpleTypeVisitor14 * @since 23 */ -@SupportedSourceVersion(RELEASE_26) +@SupportedSourceVersion(RELEASE_27) @PreviewFeature(feature=PreviewFeature.Feature.LANGUAGE_MODEL, reflective=true) public class SimpleTypeVisitorPreview extends SimpleTypeVisitor14 { /** diff --git a/src/java.compiler/share/classes/javax/lang/model/util/TypeKindVisitor14.java b/src/java.compiler/share/classes/javax/lang/model/util/TypeKindVisitor14.java index 295ceb200b8..8c80f4ad79a 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/TypeKindVisitor14.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/TypeKindVisitor14.java @@ -61,7 +61,7 @@ import static javax.lang.model.SourceVersion.*; * @see TypeKindVisitor9 * @since 14 */ -@SupportedSourceVersion(RELEASE_26) +@SupportedSourceVersion(RELEASE_27) public class TypeKindVisitor14 extends TypeKindVisitor9 { /** * Constructor for concrete subclasses to call; uses {@code null} diff --git a/src/java.compiler/share/classes/javax/lang/model/util/TypeKindVisitorPreview.java b/src/java.compiler/share/classes/javax/lang/model/util/TypeKindVisitorPreview.java index c0ca3a0450a..62c059c605f 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/TypeKindVisitorPreview.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/TypeKindVisitorPreview.java @@ -66,7 +66,7 @@ import static javax.lang.model.SourceVersion.*; * @see TypeKindVisitor14 * @since 23 */ -@SupportedSourceVersion(RELEASE_26) +@SupportedSourceVersion(RELEASE_27) @PreviewFeature(feature=PreviewFeature.Feature.LANGUAGE_MODEL, reflective=true) public class TypeKindVisitorPreview extends TypeKindVisitor14 { /** diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java index d0cb45ebc09..84a823f785f 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java @@ -158,6 +158,11 @@ public enum Source { * 26, tbd */ JDK26("26"), + + /** + * 27, tbd + */ + JDK27("27"), ; // Reduce code churn when appending new constants private static final Context.Key sourceKey = new Context.Key<>(); @@ -210,6 +215,7 @@ public enum Source { public Target requiredTarget() { return switch(this) { + case JDK27 -> Target.JDK1_27; case JDK26 -> Target.JDK1_26; case JDK25 -> Target.JDK1_25; case JDK24 -> Target.JDK1_24; @@ -366,6 +372,7 @@ public enum Source { case JDK24 -> RELEASE_24; case JDK25 -> RELEASE_25; case JDK26 -> RELEASE_26; + case JDK27 -> RELEASE_27; default -> null; }; } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassFile.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassFile.java index e5adecdb107..ae1aab1cefd 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassFile.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassFile.java @@ -130,6 +130,7 @@ public class ClassFile { V68(68, 0), // JDK 24 V69(69, 0), // JDK 25 V70(70, 0), // JDK 26 + V71(71, 0), // JDK 27 ; // Reduce code churn when appending new constants Version(int major, int minor) { this.major = major; diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Target.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Target.java index f60adcb3b80..b0a298fc845 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Target.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Target.java @@ -113,6 +113,9 @@ public enum Target { /** JDK 26. */ JDK1_26("26", 70, 0), + + /** JDK 27. */ + JDK1_27("27", 71, 0), ; // Reduce code churn when appending new constants private static final Context.Key targetKey = new Context.Key<>(); diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/PrintingProcessor.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/PrintingProcessor.java index 7aaf035fd36..bcc9ccd0113 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/PrintingProcessor.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/PrintingProcessor.java @@ -55,7 +55,7 @@ import com.sun.tools.javac.util.StringUtils; * deletion without notice. */ @SupportedAnnotationTypes("*") -@SupportedSourceVersion(SourceVersion.RELEASE_26) +@SupportedSourceVersion(SourceVersion.RELEASE_27) public class PrintingProcessor extends AbstractProcessor { PrintWriter writer; diff --git a/src/jdk.compiler/share/data/symbols/java.base-Q.sym.txt b/src/jdk.compiler/share/data/symbols/java.base-Q.sym.txt new file mode 100644 index 00000000000..fb1ec6ec7bb --- /dev/null +++ b/src/jdk.compiler/share/data/symbols/java.base-Q.sym.txt @@ -0,0 +1,558 @@ +# +# Copyright (c) 2025, 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. +# +# ########################################################## +# ### THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. ### +# ########################################################## +# +module name java.base +header exports java/io,java/lang,java/lang/annotation,java/lang/classfile,java/lang/classfile/attribute,java/lang/classfile/constantpool,java/lang/classfile/instruction,java/lang/constant,java/lang/foreign,java/lang/invoke,java/lang/module,java/lang/ref,java/lang/reflect,java/lang/runtime,java/math,java/net,java/net/spi,java/nio,java/nio/channels,java/nio/channels/spi,java/nio/charset,java/nio/charset/spi,java/nio/file,java/nio/file/attribute,java/nio/file/spi,java/security,java/security/cert,java/security/interfaces,java/security/spec,java/text,java/text/spi,java/time,java/time/chrono,java/time/format,java/time/temporal,java/time/zone,java/util,java/util/concurrent,java/util/concurrent/atomic,java/util/concurrent/locks,java/util/function,java/util/jar,java/util/random,java/util/regex,java/util/spi,java/util/stream,java/util/zip,javax/crypto,javax/crypto/interfaces,javax/crypto/spec,javax/net,javax/net/ssl,javax/security/auth,javax/security/auth/callback,javax/security/auth/login,javax/security/auth/spi,javax/security/auth/x500,javax/security/cert,jdk/internal/event[jdk.jfr],jdk/internal/javac[java.compiler\u005C;u002C;jdk.compiler],jdk/internal/vm/vector[jdk.incubator.vector] extraModulePackages jdk/internal/access/foreign,jdk/internal/classfile/impl,jdk/internal/constant,jdk/internal/foreign/abi,jdk/internal/foreign/abi/aarch64/linux,jdk/internal/foreign/abi/aarch64/macos,jdk/internal/foreign/abi/aarch64/windows,jdk/internal/foreign/abi/fallback,jdk/internal/foreign/abi/ppc64/aix,jdk/internal/foreign/abi/ppc64/linux,jdk/internal/foreign/abi/riscv64/linux,jdk/internal/foreign/abi/s390/linux,jdk/internal/foreign/abi/x64/sysv,jdk/internal/foreign/abi/x64/windows,jdk/internal/foreign/layout,jdk/internal/lang,sun/nio,sun/nio/ch,sun/net,jdk/internal/foreign,jdk/internal/foreign,sun/net,sun/nio/ch uses java/lang/System$LoggerFinder,java/net/ContentHandlerFactory,java/net/spi/InetAddressResolverProvider,java/net/spi/URLStreamHandlerProvider,java/nio/channels/spi/AsynchronousChannelProvider,java/nio/channels/spi/SelectorProvider,java/nio/charset/spi/CharsetProvider,java/nio/file/spi/FileSystemProvider,java/nio/file/spi/FileTypeDetector,java/security/Provider,java/text/spi/BreakIteratorProvider,java/text/spi/CollatorProvider,java/text/spi/DateFormatProvider,java/text/spi/DateFormatSymbolsProvider,java/text/spi/DecimalFormatSymbolsProvider,java/text/spi/NumberFormatProvider,java/time/chrono/AbstractChronology,java/time/chrono/Chronology,java/time/zone/ZoneRulesProvider,java/util/spi/CalendarDataProvider,java/util/spi/CalendarNameProvider,java/util/spi/CurrencyNameProvider,java/util/spi/LocaleNameProvider,java/util/spi/ResourceBundleControlProvider,java/util/spi/ResourceBundleProvider,java/util/spi/TimeZoneNameProvider,java/util/spi/ToolProvider,javax/security/auth/spi/LoginModule,jdk/internal/io/JdkConsoleProvider,jdk/internal/logger/DefaultLoggerFinder,sun/text/spi/JavaTimeDateTimePatternProvider,sun/util/locale/provider/LocaleDataMetaInfo,sun/util/resources/LocaleData$LocaleDataResourceBundleProvider,sun/util/spi/CalendarProvider provides interface\u0020;java/nio/file/spi/FileSystemProvider\u0020;impls\u0020;jdk/internal/jrtfs/JrtFileSystemProvider target macos-aarch64 flags 8000 + +class name java/lang/Character$UnicodeBlock +field name SIDETIC descriptor Ljava/lang/Character$UnicodeBlock; flags 19 +field name SHARADA_SUPPLEMENT descriptor Ljava/lang/Character$UnicodeBlock; flags 19 +field name TOLONG_SIKI descriptor Ljava/lang/Character$UnicodeBlock; flags 19 +field name BERIA_ERFE descriptor Ljava/lang/Character$UnicodeBlock; flags 19 +field name TANGUT_COMPONENTS_SUPPLEMENT descriptor Ljava/lang/Character$UnicodeBlock; flags 19 +field name MISCELLANEOUS_SYMBOLS_SUPPLEMENT descriptor Ljava/lang/Character$UnicodeBlock; flags 19 +field name TAI_YO descriptor Ljava/lang/Character$UnicodeBlock; flags 19 +field name CJK_UNIFIED_IDEOGRAPHS_EXTENSION_J descriptor Ljava/lang/Character$UnicodeBlock; flags 19 + +class name java/lang/Character$UnicodeScript +field name SIDETIC descriptor Ljava/lang/Character$UnicodeScript; flags 4019 +field name TOLONG_SIKI descriptor Ljava/lang/Character$UnicodeScript; flags 4019 +field name BERIA_ERFE descriptor Ljava/lang/Character$UnicodeScript; flags 4019 +field name TAI_YO descriptor Ljava/lang/Character$UnicodeScript; flags 4019 + +class name java/lang/Class +header extends java/lang/Object implements java/io/Serializable,java/lang/reflect/GenericDeclaration,java/lang/reflect/Type,java/lang/reflect/AnnotatedElement,java/lang/invoke/TypeDescriptor$OfField,java/lang/constant/Constable flags 31 signature Ljava/lang/Object;Ljava/io/Serializable;Ljava/lang/reflect/GenericDeclaration;Ljava/lang/reflect/Type;Ljava/lang/reflect/AnnotatedElement;Ljava/lang/invoke/TypeDescriptor$OfField;>;Ljava/lang/constant/Constable; runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/lang/reflect/AccessFlag$Location outerClass java/lang/reflect/AccessFlag innerClassName Location flags 4019 +innerclass innerClass java/util/Map$Entry outerClass java/util/Map innerClassName Entry flags 609 +innerclass innerClass java/lang/invoke/TypeDescriptor$OfField outerClass java/lang/invoke/TypeDescriptor innerClassName OfField flags 609 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 + +class name java/lang/ClassLoader +header extends java/lang/Object flags 421 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/util/Map$Entry outerClass java/util/Map innerClassName Entry flags 609 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 + +class name java/lang/LazyConstant +header extends java/lang/Object implements java/util/function/Supplier sealed true permittedSubclasses jdk/internal/lang/LazyConstantImpl flags 601 signature Ljava/lang/Object;Ljava/util/function/Supplier; classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;LAZY_CONSTANTS;) +method name orElse descriptor (Ljava/lang/Object;)Ljava/lang/Object; flags 401 signature (TT;)TT; +method name get descriptor ()Ljava/lang/Object; flags 401 signature ()TT; +method name isInitialized descriptor ()Z flags 401 +method name equals descriptor (Ljava/lang/Object;)Z flags 401 +method name hashCode descriptor ()I flags 401 +method name toString descriptor ()Ljava/lang/String; flags 401 +method name of descriptor (Ljava/util/function/Supplier;)Ljava/lang/LazyConstant; flags 9 signature (Ljava/util/function/Supplier<+TT;>;)Ljava/lang/LazyConstant; + +class name java/lang/Math +-method name sinh descriptor (D)D +method name sinh descriptor (D)D flags 9 runtimeAnnotations @Ljdk/internal/vm/annotation/IntrinsicCandidate; + +class name java/lang/Object +header flags 21 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; + +class name java/lang/Process +header extends java/lang/Object implements java/io/Closeable flags 421 +innerclass innerClass java/util/concurrent/ForkJoinPool$ManagedBlocker outerClass java/util/concurrent/ForkJoinPool innerClassName ManagedBlocker flags 609 +innerclass innerClass java/lang/ProcessHandle$Info outerClass java/lang/ProcessHandle innerClassName Info flags 609 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 +method name close descriptor ()V thrownTypes java/io/IOException flags 1 + +-class name java/lang/StableValue + +class name java/lang/Thread +-method name stop descriptor ()V + +class name java/lang/classfile/ClassFile +field name JAVA_26_VERSION descriptor I constantValue 70 flags 19 + +class name java/lang/classfile/Signature$ClassTypeSig +-method name of descriptor (Ljava/lang/classfile/Signature$ClassTypeSig;Ljava/lang/constant/ClassDesc;[Ljava/lang/classfile/Signature$TypeArg;)Ljava/lang/classfile/Signature$ClassTypeSig; +method name of descriptor (Ljava/lang/classfile/Signature$ClassTypeSig;Ljava/lang/constant/ClassDesc;[Ljava/lang/classfile/Signature$TypeArg;)Ljava/lang/classfile/Signature$ClassTypeSig; flags 89 deprecated true runtimeAnnotations @Ljava/lang/Deprecated;(forRemoval=Ztrue,since="26") + +-class name java/lang/constant/AsTypeMethodHandleDesc + +class name java/lang/constant/ConstantDescs +header extends java/lang/Object flags 31 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/lang/constant/DirectMethodHandleDesc$Kind outerClass java/lang/constant/DirectMethodHandleDesc innerClassName Kind flags 4019 + +class name java/lang/constant/DynamicConstantDesc +header extends java/lang/Object implements java/lang/constant/ConstantDesc flags 421 signature Ljava/lang/Object;Ljava/lang/constant/ConstantDesc; runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 +innerclass innerClass java/lang/Enum$EnumDesc outerClass java/lang/Enum innerClassName EnumDesc flags 19 +innerclass innerClass java/lang/invoke/VarHandle$VarHandleDesc outerClass java/lang/invoke/VarHandle innerClassName VarHandleDesc flags 19 + +class name java/lang/constant/MethodHandleDesc +header extends java/lang/Object implements java/lang/constant/ConstantDesc sealed true permittedSubclasses jdk/internal/constant/AsTypeMethodHandleDesc,java/lang/constant/DirectMethodHandleDesc flags 601 +innerclass innerClass java/lang/constant/DirectMethodHandleDesc$Kind outerClass java/lang/constant/DirectMethodHandleDesc innerClassName Kind flags 4019 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 + +class name java/lang/invoke/BoundMethodHandle +header extends java/lang/invoke/MethodHandle flags 420 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; + +class name java/lang/invoke/DelegatingMethodHandle +header extends java/lang/invoke/MethodHandle sealed true permittedSubclasses java/lang/invoke/MethodHandleImpl$AsVarargsCollector,java/lang/invoke/MethodHandleImpl$WrappedMember,java/lang/invoke/MethodHandleImpl$IntrinsicMethodHandle,java/lang/invoke/MethodHandleImpl$CountingWrapper flags 420 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/lang/invoke/MethodHandleImpl$AsVarargsCollector outerClass java/lang/invoke/MethodHandleImpl innerClassName AsVarargsCollector flags 18 +innerclass innerClass java/lang/invoke/MethodHandleImpl$WrappedMember outerClass java/lang/invoke/MethodHandleImpl innerClassName WrappedMember flags 18 +innerclass innerClass java/lang/invoke/MethodHandleImpl$IntrinsicMethodHandle outerClass java/lang/invoke/MethodHandleImpl innerClassName IntrinsicMethodHandle flags 18 +innerclass innerClass java/lang/invoke/MethodHandleImpl$CountingWrapper outerClass java/lang/invoke/MethodHandleImpl innerClassName CountingWrapper flags 18 + +class name java/lang/invoke/DirectMethodHandle +header extends java/lang/invoke/MethodHandle nestMembers java/lang/invoke/DirectMethodHandle$StaticAccessor,java/lang/invoke/DirectMethodHandle$Accessor,java/lang/invoke/DirectMethodHandle$Constructor,java/lang/invoke/DirectMethodHandle$Interface,java/lang/invoke/DirectMethodHandle$Special sealed true permittedSubclasses java/lang/invoke/DirectMethodHandle$Special,java/lang/invoke/DirectMethodHandle$Interface,java/lang/invoke/DirectMethodHandle$Constructor,java/lang/invoke/DirectMethodHandle$Accessor,java/lang/invoke/DirectMethodHandle$StaticAccessor flags 20 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/lang/invoke/DirectMethodHandle$Special outerClass java/lang/invoke/DirectMethodHandle innerClassName Special flags 18 +innerclass innerClass java/lang/invoke/DirectMethodHandle$Interface outerClass java/lang/invoke/DirectMethodHandle innerClassName Interface flags 18 +innerclass innerClass java/lang/invoke/DirectMethodHandle$StaticAccessor outerClass java/lang/invoke/DirectMethodHandle innerClassName StaticAccessor flags 18 +innerclass innerClass java/lang/invoke/DirectMethodHandle$Accessor outerClass java/lang/invoke/DirectMethodHandle innerClassName Accessor flags 18 +innerclass innerClass java/lang/invoke/DirectMethodHandle$Constructor outerClass java/lang/invoke/DirectMethodHandle innerClassName Constructor flags 18 + +class name java/lang/invoke/DirectMethodHandle$Constructor +header extends java/lang/invoke/DirectMethodHandle nestHost java/lang/invoke/DirectMethodHandle flags 30 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/lang/invoke/DirectMethodHandle$Constructor outerClass java/lang/invoke/DirectMethodHandle innerClassName Constructor flags 18 + +class name java/lang/invoke/LambdaForm +header extends java/lang/Object flags 20 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; + +class name java/lang/invoke/LambdaMetafactory +header extends java/lang/Object flags 31 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 + +class name java/lang/invoke/MethodHandle +header extends java/lang/Object implements java/lang/constant/Constable sealed true permittedSubclasses java/lang/invoke/NativeMethodHandle,java/lang/invoke/DirectMethodHandle,java/lang/invoke/DelegatingMethodHandle,java/lang/invoke/BoundMethodHandle flags 421 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 +innerclass innerClass java/lang/constant/DirectMethodHandleDesc$Kind outerClass java/lang/constant/DirectMethodHandleDesc innerClassName Kind flags 4019 + +class name java/lang/invoke/MethodHandleImpl +header extends java/lang/Object nestMembers java/lang/invoke/MethodHandleImpl$IntrinsicMethodHandle,java/lang/invoke/MethodHandleImpl$WrappedMember,java/lang/invoke/MethodHandleImpl$CountingWrapper,java/lang/invoke/MethodHandleImpl$AsVarargsCollector flags 420 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/util/Map$Entry outerClass java/util/Map innerClassName Entry flags 609 +innerclass innerClass java/lang/invoke/MethodHandleImpl$AsVarargsCollector outerClass java/lang/invoke/MethodHandleImpl innerClassName AsVarargsCollector flags 18 +innerclass innerClass java/lang/invoke/MethodHandleImpl$CountingWrapper outerClass java/lang/invoke/MethodHandleImpl innerClassName CountingWrapper flags 18 +innerclass innerClass java/lang/invoke/MethodHandleImpl$WrappedMember outerClass java/lang/invoke/MethodHandleImpl innerClassName WrappedMember flags 18 +innerclass innerClass java/lang/invoke/MethodHandleImpl$IntrinsicMethodHandle outerClass java/lang/invoke/MethodHandleImpl innerClassName IntrinsicMethodHandle flags 18 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 + +class name java/lang/invoke/MethodHandleImpl$AsVarargsCollector +header extends java/lang/invoke/DelegatingMethodHandle nestHost java/lang/invoke/MethodHandleImpl flags 30 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/lang/invoke/MethodHandleImpl$AsVarargsCollector outerClass java/lang/invoke/MethodHandleImpl innerClassName AsVarargsCollector flags 18 + +class name java/lang/invoke/MethodHandleImpl$CountingWrapper +header extends java/lang/invoke/DelegatingMethodHandle nestHost java/lang/invoke/MethodHandleImpl flags 30 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/lang/invoke/MethodHandleImpl$CountingWrapper outerClass java/lang/invoke/MethodHandleImpl innerClassName CountingWrapper flags 18 + +class name java/lang/invoke/MethodHandleImpl$IntrinsicMethodHandle +header extends java/lang/invoke/DelegatingMethodHandle nestHost java/lang/invoke/MethodHandleImpl flags 30 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/lang/invoke/MethodHandleImpl$IntrinsicMethodHandle outerClass java/lang/invoke/MethodHandleImpl innerClassName IntrinsicMethodHandle flags 18 + +class name java/lang/invoke/MethodHandleImpl$WrappedMember +header extends java/lang/invoke/DelegatingMethodHandle nestHost java/lang/invoke/MethodHandleImpl flags 30 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/lang/invoke/MethodHandleImpl$WrappedMember outerClass java/lang/invoke/MethodHandleImpl innerClassName WrappedMember flags 18 + +class name java/lang/invoke/MethodHandles +header extends java/lang/Object nestMembers java/lang/invoke/MethodHandles$Lookup,java/lang/invoke/MethodHandles$Lookup$ClassOption flags 31 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 +innerclass innerClass java/lang/invoke/VarHandle$AccessMode outerClass java/lang/invoke/VarHandle innerClassName AccessMode flags 4019 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup$ClassOption outerClass java/lang/invoke/MethodHandles$Lookup innerClassName ClassOption flags 4019 + +class name java/lang/invoke/StringConcatFactory +header extends java/lang/Object flags 31 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 + +class name java/lang/module/ModuleDescriptor +header extends java/lang/Object implements java/lang/Comparable nestMembers java/lang/module/ModuleDescriptor$Builder,java/lang/module/ModuleDescriptor$Version,java/lang/module/ModuleDescriptor$Provides,java/lang/module/ModuleDescriptor$Opens,java/lang/module/ModuleDescriptor$Opens$Modifier,java/lang/module/ModuleDescriptor$Exports,java/lang/module/ModuleDescriptor$Exports$Modifier,java/lang/module/ModuleDescriptor$Requires,java/lang/module/ModuleDescriptor$Requires$Modifier,java/lang/module/ModuleDescriptor$Modifier flags 31 signature Ljava/lang/Object;Ljava/lang/Comparable; runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/lang/module/ModuleDescriptor$Version outerClass java/lang/module/ModuleDescriptor innerClassName Version flags 19 +innerclass innerClass java/lang/module/ModuleDescriptor$Modifier outerClass java/lang/module/ModuleDescriptor innerClassName Modifier flags 4019 +innerclass innerClass java/lang/reflect/AccessFlag$Location outerClass java/lang/reflect/AccessFlag innerClassName Location flags 4019 +innerclass innerClass java/lang/module/ModuleDescriptor$Builder outerClass java/lang/module/ModuleDescriptor innerClassName Builder flags 19 +innerclass innerClass java/lang/module/ModuleDescriptor$Provides outerClass java/lang/module/ModuleDescriptor innerClassName Provides flags 19 +innerclass innerClass java/lang/module/ModuleDescriptor$Opens outerClass java/lang/module/ModuleDescriptor innerClassName Opens flags 19 +innerclass innerClass java/lang/module/ModuleDescriptor$Exports outerClass java/lang/module/ModuleDescriptor innerClassName Exports flags 19 +innerclass innerClass java/lang/module/ModuleDescriptor$Requires outerClass java/lang/module/ModuleDescriptor innerClassName Requires flags 19 +innerclass innerClass java/lang/module/ModuleDescriptor$Opens$Modifier outerClass java/lang/module/ModuleDescriptor$Opens innerClassName Modifier flags 4019 +innerclass innerClass java/lang/module/ModuleDescriptor$Exports$Modifier outerClass java/lang/module/ModuleDescriptor$Exports innerClassName Modifier flags 4019 +innerclass innerClass java/lang/module/ModuleDescriptor$Requires$Modifier outerClass java/lang/module/ModuleDescriptor$Requires innerClassName Modifier flags 4019 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 + +class name java/lang/ref/PhantomReference +header extends java/lang/ref/Reference flags 21 signature Ljava/lang/ref/Reference; runtimeTypeAnnotations @Ljdk/internal/RequiresIdentity;{typeParameterIndex=I0,targetType="CLASS_TYPE_PARAMETER"} + +class name java/lang/ref/Reference +header extends java/lang/Object sealed true permittedSubclasses java/lang/ref/PhantomReference,java/lang/ref/SoftReference,java/lang/ref/WeakReference,java/lang/ref/FinalReference flags 421 signature Ljava/lang/Object; runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; runtimeTypeAnnotations @Ljdk/internal/RequiresIdentity;{typeParameterIndex=I0,targetType="CLASS_TYPE_PARAMETER"} +-method name get descriptor ()Ljava/lang/Object; +method name get descriptor ()Ljava/lang/Object; flags 1 signature ()TT; + +class name java/lang/ref/ReferenceQueue +header extends java/lang/Object flags 21 signature Ljava/lang/Object; runtimeTypeAnnotations @Ljdk/internal/RequiresIdentity;{typeParameterIndex=I0,targetType="CLASS_TYPE_PARAMETER"} + +class name java/lang/ref/SoftReference +header extends java/lang/ref/Reference flags 21 signature Ljava/lang/ref/Reference; runtimeTypeAnnotations @Ljdk/internal/RequiresIdentity;{typeParameterIndex=I0,targetType="CLASS_TYPE_PARAMETER"} + +class name java/lang/ref/WeakReference +header extends java/lang/ref/Reference flags 21 signature Ljava/lang/ref/Reference; runtimeTypeAnnotations @Ljdk/internal/RequiresIdentity;{typeParameterIndex=I0,targetType="CLASS_TYPE_PARAMETER"} + +class name java/lang/reflect/ClassFileFormatVersion +field name RELEASE_26 descriptor Ljava/lang/reflect/ClassFileFormatVersion; flags 4019 + +class name java/lang/reflect/Field +header extends java/lang/reflect/AccessibleObject implements java/lang/reflect/Member flags 31 +innerclass innerClass java/lang/reflect/AccessFlag$Location outerClass java/lang/reflect/AccessFlag innerClassName Location flags 4019 +innerclass innerClass java/lang/StackWalker$Option outerClass java/lang/StackWalker innerClassName Option flags 4019 +innerclass innerClass java/lang/StackWalker$StackFrame outerClass java/lang/StackWalker innerClassName StackFrame flags 609 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 + +class name java/lang/runtime/ObjectMethods +header extends java/lang/Object flags 31 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 +innerclass innerClass java/lang/classfile/ClassFile$Option outerClass java/lang/classfile/ClassFile innerClassName Option flags 609 +innerclass innerClass java/lang/classfile/ClassFile$ClassHierarchyResolverOption outerClass java/lang/classfile/ClassFile innerClassName ClassHierarchyResolverOption flags 609 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup$ClassOption outerClass java/lang/invoke/MethodHandles$Lookup innerClassName ClassOption flags 4019 + +class name java/math/BigInteger +method name rootn descriptor (I)Ljava/math/BigInteger; flags 1 +method name rootnAndRemainder descriptor (I)[Ljava/math/BigInteger; flags 1 + +class name java/net/DatagramSocketImpl +-method name setTTL descriptor (B)V +-method name getTTL descriptor ()B + +class name java/net/MulticastSocket +-method name setTTL descriptor (B)V +-method name getTTL descriptor ()B +-method name send descriptor (Ljava/net/DatagramPacket;B)V + +class name java/net/ServerSocket +-method name setPerformancePreferences descriptor (III)V +method name setPerformancePreferences descriptor (III)V flags 1 deprecated true runtimeAnnotations @Ljava/lang/Deprecated;(forRemoval=Ztrue,since="26") + +class name java/net/Socket +-method name setPerformancePreferences descriptor (III)V +method name setPerformancePreferences descriptor (III)V flags 1 deprecated true runtimeAnnotations @Ljava/lang/Deprecated;(forRemoval=Ztrue,since="26") + +class name java/net/SocketImpl +-method name setPerformancePreferences descriptor (III)V +method name setPerformancePreferences descriptor (III)V flags 4 deprecated true runtimeAnnotations @Ljava/lang/Deprecated;(forRemoval=Ztrue,since="26") + +class name java/net/SocketPermission +header extends java/security/Permission implements java/io/Serializable flags 31 deprecated true runtimeAnnotations @Ljava/lang/Deprecated;(forRemoval=Ztrue,since="26") +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 + +class name java/net/URI +header extends java/lang/Object implements java/lang/Comparable,java/io/Serializable flags 31 signature Ljava/lang/Object;Ljava/lang/Comparable;Ljava/io/Serializable; runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/text/Normalizer$Form outerClass java/text/Normalizer innerClassName Form flags 4019 + +class name java/net/URL +header extends java/lang/Object implements java/io/Serializable flags 31 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/lang/ScopedValue$Carrier outerClass java/lang/ScopedValue innerClassName Carrier flags 19 +innerclass innerClass java/lang/ScopedValue$CallableOp outerClass java/lang/ScopedValue innerClassName CallableOp flags 609 +innerclass innerClass java/io/ObjectInputStream$GetField outerClass java/io/ObjectInputStream innerClassName GetField flags 409 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 + +class name java/nio/ByteOrder +header extends java/lang/Enum flags 4031 signature Ljava/lang/Enum; +-field name BIG_ENDIAN descriptor Ljava/nio/ByteOrder; +-field name LITTLE_ENDIAN descriptor Ljava/nio/ByteOrder; +-method name toString descriptor ()Ljava/lang/String; +field name LITTLE_ENDIAN descriptor Ljava/nio/ByteOrder; flags 4019 +field name BIG_ENDIAN descriptor Ljava/nio/ByteOrder; flags 4019 +method name values descriptor ()[Ljava/nio/ByteOrder; flags 9 +method name valueOf descriptor (Ljava/lang/String;)Ljava/nio/ByteOrder; flags 9 methodParameters 8000:null + +class name java/nio/DirectByteBuffer +-method name cleaner descriptor ()Ljdk/internal/ref/Cleaner; +method name cleaner descriptor ()Lsun/nio/Cleaner; flags 1 + +class name java/nio/DirectCharBufferS +-method name cleaner descriptor ()Ljdk/internal/ref/Cleaner; +method name cleaner descriptor ()Lsun/nio/Cleaner; flags 1 + +class name java/nio/DirectCharBufferU +-method name cleaner descriptor ()Ljdk/internal/ref/Cleaner; +method name cleaner descriptor ()Lsun/nio/Cleaner; flags 1 + +class name java/nio/DirectDoubleBufferS +-method name cleaner descriptor ()Ljdk/internal/ref/Cleaner; +method name cleaner descriptor ()Lsun/nio/Cleaner; flags 1 + +class name java/nio/DirectDoubleBufferU +-method name cleaner descriptor ()Ljdk/internal/ref/Cleaner; +method name cleaner descriptor ()Lsun/nio/Cleaner; flags 1 + +class name java/nio/DirectFloatBufferS +-method name cleaner descriptor ()Ljdk/internal/ref/Cleaner; +method name cleaner descriptor ()Lsun/nio/Cleaner; flags 1 + +class name java/nio/DirectFloatBufferU +-method name cleaner descriptor ()Ljdk/internal/ref/Cleaner; +method name cleaner descriptor ()Lsun/nio/Cleaner; flags 1 + +class name java/nio/DirectIntBufferS +-method name cleaner descriptor ()Ljdk/internal/ref/Cleaner; +method name cleaner descriptor ()Lsun/nio/Cleaner; flags 1 + +class name java/nio/DirectIntBufferU +-method name cleaner descriptor ()Ljdk/internal/ref/Cleaner; +method name cleaner descriptor ()Lsun/nio/Cleaner; flags 1 + +class name java/nio/DirectLongBufferS +-method name cleaner descriptor ()Ljdk/internal/ref/Cleaner; +method name cleaner descriptor ()Lsun/nio/Cleaner; flags 1 + +class name java/nio/DirectLongBufferU +-method name cleaner descriptor ()Ljdk/internal/ref/Cleaner; +method name cleaner descriptor ()Lsun/nio/Cleaner; flags 1 + +class name java/nio/DirectShortBufferS +-method name cleaner descriptor ()Ljdk/internal/ref/Cleaner; +method name cleaner descriptor ()Lsun/nio/Cleaner; flags 1 + +class name java/nio/DirectShortBufferU +-method name cleaner descriptor ()Ljdk/internal/ref/Cleaner; +method name cleaner descriptor ()Lsun/nio/Cleaner; flags 1 + +class name java/nio/charset/Charset +header extends java/lang/Object implements java/lang/Comparable flags 421 signature Ljava/lang/Object;Ljava/lang/Comparable; +innerclass innerClass java/lang/ScopedValue$Carrier outerClass java/lang/ScopedValue innerClassName Carrier flags 19 +innerclass innerClass java/lang/ScopedValue$CallableOp outerClass java/lang/ScopedValue innerClassName CallableOp flags 609 + +class name java/security/DEREncodable +header extends java/lang/Object sealed true permittedSubclasses java/security/AsymmetricKey,java/security/KeyPair,java/security/spec/PKCS8EncodedKeySpec,java/security/spec/X509EncodedKeySpec,javax/crypto/EncryptedPrivateKeyInfo,java/security/cert/X509Certificate,java/security/cert/X509CRL,java/security/PEM flags 601 classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;PEM_API;) + +class name java/security/PEM +header extends java/lang/Record implements java/security/DEREncodable record true flags 31 classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;PEM_API;) +recordcomponent name type descriptor Ljava/lang/String; +recordcomponent name content descriptor Ljava/lang/String; +recordcomponent name leadingData descriptor [B +innerclass innerClass java/util/Base64$Decoder outerClass java/util/Base64 innerClassName Decoder flags 9 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 +method name descriptor (Ljava/lang/String;Ljava/lang/String;[B)V flags 1 methodParameters 8000:type,8000:content,8000:leadingData +method name descriptor (Ljava/lang/String;Ljava/lang/String;)V flags 1 +method name toString descriptor ()Ljava/lang/String; flags 11 +method name decode descriptor ()[B flags 11 +method name hashCode descriptor ()I flags 11 +method name equals descriptor (Ljava/lang/Object;)Z flags 11 +method name type descriptor ()Ljava/lang/String; flags 1 +method name content descriptor ()Ljava/lang/String; flags 1 +method name leadingData descriptor ()[B flags 1 + +class name java/security/PEMDecoder +header extends java/lang/Object flags 31 classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;PEM_API;) +innerclass innerClass java/lang/ref/Cleaner$Cleanable outerClass java/lang/ref/Cleaner innerClassName Cleanable flags 609 +innerclass innerClass java/util/Base64$Decoder outerClass java/util/Base64 innerClassName Decoder flags 9 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 + +-class name java/security/PEMRecord + +class name java/security/SecureRandom +method name nextLong descriptor ()J flags 1 + +class name java/time/Duration +field name MIN descriptor Ljava/time/Duration; flags 19 +field name MAX descriptor Ljava/time/Duration; flags 19 + +class name java/time/Instant +method name plusSaturating descriptor (Ljava/time/Duration;)Ljava/time/Instant; flags 1 + +class name java/util/AbstractMap +header extends java/lang/Object implements java/util/Map nestMembers java/util/AbstractMap$SimpleImmutableEntry,java/util/AbstractMap$SimpleEntry flags 421 signature Ljava/lang/Object;Ljava/util/Map; runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/util/Map$Entry outerClass java/util/Map innerClassName Entry flags 609 +innerclass innerClass java/util/AbstractMap$SimpleImmutableEntry outerClass java/util/AbstractMap innerClassName SimpleImmutableEntry flags 9 +innerclass innerClass java/util/AbstractMap$SimpleEntry outerClass java/util/AbstractMap innerClassName SimpleEntry flags 9 + +class name java/util/Collections +header extends java/lang/Object flags 31 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; + +class name java/util/Comparator +method name max descriptor (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; flags 1 signature (TU;TU;)TU; +method name min descriptor (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; flags 1 signature (TU;TU;)TU; + +class name java/util/List +method name ofLazy descriptor (ILjava/util/function/IntFunction;)Ljava/util/List; flags 9 signature (ILjava/util/function/IntFunction<+TE;>;)Ljava/util/List; classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;LAZY_CONSTANTS;) + +class name java/util/Locale +header extends java/lang/Object implements java/lang/Cloneable,java/io/Serializable nestMembers java/util/Locale$LanguageRange,java/util/Locale$FilteringMode,java/util/Locale$Builder,java/util/Locale$Category,java/util/Locale$IsoCountryCode flags 31 +innerclass innerClass java/util/Locale$Category outerClass java/util/Locale innerClassName Category flags 4019 +innerclass innerClass java/util/Locale$IsoCountryCode outerClass java/util/Locale innerClassName IsoCountryCode flags 4019 +innerclass innerClass java/io/ObjectOutputStream$PutField outerClass java/io/ObjectOutputStream innerClassName PutField flags 409 +innerclass innerClass java/io/ObjectInputStream$GetField outerClass java/io/ObjectInputStream innerClassName GetField flags 409 +innerclass innerClass java/util/Locale$FilteringMode outerClass java/util/Locale innerClassName FilteringMode flags 4019 +innerclass innerClass java/util/Locale$LanguageRange outerClass java/util/Locale innerClassName LanguageRange flags 19 +innerclass innerClass java/util/Locale$Builder outerClass java/util/Locale innerClassName Builder flags 19 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 + +class name java/util/Locale$IsoCountryCode +header extends java/lang/Enum nestHost java/util/Locale flags 4031 signature Ljava/lang/Enum; +innerclass innerClass java/util/Locale$IsoCountryCode outerClass java/util/Locale innerClassName IsoCountryCode flags 4019 + +class name java/util/Map +method name ofLazy descriptor (Ljava/util/Set;Ljava/util/function/Function;)Ljava/util/Map; flags 9 signature (Ljava/util/Set<+TK;>;Ljava/util/function/Function<-TK;+TV;>;)Ljava/util/Map; classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;LAZY_CONSTANTS;) + +class name java/util/UUID +method name ofEpochMillis descriptor (J)Ljava/util/UUID; flags 9 + +class name java/util/WeakHashMap +header extends java/util/AbstractMap implements java/util/Map flags 21 signature Ljava/util/AbstractMap;Ljava/util/Map; runtimeTypeAnnotations @Ljdk/internal/RequiresIdentity;{typeParameterIndex=I0,targetType="CLASS_TYPE_PARAMETER"} +innerclass innerClass java/util/Map$Entry outerClass java/util/Map innerClassName Entry flags 609 + +class name java/util/concurrent/ConcurrentHashMap +header extends java/util/AbstractMap implements java/util/concurrent/ConcurrentMap,java/io/Serializable nestMembers java/util/concurrent/ConcurrentHashMap$EntrySetView,java/util/concurrent/ConcurrentHashMap$ValuesView,java/util/concurrent/ConcurrentHashMap$KeySetView,java/util/concurrent/ConcurrentHashMap$CollectionView flags 21 signature Ljava/util/AbstractMap;Ljava/util/concurrent/ConcurrentMap;Ljava/io/Serializable; runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/util/Map$Entry outerClass java/util/Map innerClassName Entry flags 609 +innerclass innerClass java/util/concurrent/ConcurrentHashMap$KeySetView outerClass java/util/concurrent/ConcurrentHashMap innerClassName KeySetView flags 19 +innerclass innerClass java/util/concurrent/ConcurrentHashMap$ValuesView outerClass java/util/concurrent/ConcurrentHashMap innerClassName ValuesView flags 18 +innerclass innerClass java/util/concurrent/ConcurrentHashMap$EntrySetView outerClass java/util/concurrent/ConcurrentHashMap innerClassName EntrySetView flags 18 +innerclass innerClass java/io/ObjectOutputStream$PutField outerClass java/io/ObjectOutputStream innerClassName PutField flags 409 +innerclass innerClass java/util/AbstractMap$SimpleImmutableEntry outerClass java/util/AbstractMap innerClassName SimpleImmutableEntry flags 9 +innerclass innerClass java/util/concurrent/ConcurrentHashMap$CollectionView outerClass java/util/concurrent/ConcurrentHashMap innerClassName CollectionView flags 408 + +class name java/util/concurrent/StructuredTaskScope +-method name open descriptor (Ljava/util/concurrent/StructuredTaskScope$Joiner;Ljava/util/function/Function;)Ljava/util/concurrent/StructuredTaskScope; +method name open descriptor (Ljava/util/concurrent/StructuredTaskScope$Joiner;Ljava/util/function/UnaryOperator;)Ljava/util/concurrent/StructuredTaskScope; flags 9 signature (Ljava/util/concurrent/StructuredTaskScope$Joiner<-TT;+TR;>;Ljava/util/function/UnaryOperator;)Ljava/util/concurrent/StructuredTaskScope; + +class name java/util/concurrent/StructuredTaskScope$Joiner +header extends java/lang/Object nestHost java/util/concurrent/StructuredTaskScope flags 601 signature Ljava/lang/Object; classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;STRUCTURED_CONCURRENCY;) +innerclass innerClass java/util/concurrent/StructuredTaskScope$Subtask outerClass java/util/concurrent/StructuredTaskScope innerClassName Subtask flags 609 +innerclass innerClass java/util/concurrent/StructuredTaskScope$Subtask$State outerClass java/util/concurrent/StructuredTaskScope$Subtask innerClassName State flags 4019 +innerclass innerClass java/util/concurrent/StructuredTaskScope$TimeoutException outerClass java/util/concurrent/StructuredTaskScope innerClassName TimeoutException flags 19 +innerclass innerClass java/util/concurrent/StructuredTaskScope$Joiner outerClass java/util/concurrent/StructuredTaskScope innerClassName Joiner flags 609 +-method name onFork descriptor (Ljava/util/concurrent/StructuredTaskScope$Subtask;)Z +-method name onComplete descriptor (Ljava/util/concurrent/StructuredTaskScope$Subtask;)Z +-method name allSuccessfulOrThrow descriptor ()Ljava/util/concurrent/StructuredTaskScope$Joiner; +-method name anySuccessfulResultOrThrow descriptor ()Ljava/util/concurrent/StructuredTaskScope$Joiner; +-method name allUntil descriptor (Ljava/util/function/Predicate;)Ljava/util/concurrent/StructuredTaskScope$Joiner; +method name onFork descriptor (Ljava/util/concurrent/StructuredTaskScope$Subtask;)Z flags 1 signature (Ljava/util/concurrent/StructuredTaskScope$Subtask;)Z +method name onComplete descriptor (Ljava/util/concurrent/StructuredTaskScope$Subtask;)Z flags 1 signature (Ljava/util/concurrent/StructuredTaskScope$Subtask;)Z +method name onTimeout descriptor ()V flags 1 +method name allSuccessfulOrThrow descriptor ()Ljava/util/concurrent/StructuredTaskScope$Joiner; flags 9 signature ()Ljava/util/concurrent/StructuredTaskScope$Joiner;>; +method name anySuccessfulOrThrow descriptor ()Ljava/util/concurrent/StructuredTaskScope$Joiner; flags 9 signature ()Ljava/util/concurrent/StructuredTaskScope$Joiner; +method name allUntil descriptor (Ljava/util/function/Predicate;)Ljava/util/concurrent/StructuredTaskScope$Joiner; flags 9 signature (Ljava/util/function/Predicate;>;)Ljava/util/concurrent/StructuredTaskScope$Joiner;>;>; + +class name java/util/concurrent/StructuredTaskScopeImpl +header extends java/lang/Object implements java/util/concurrent/StructuredTaskScope nestMembers java/util/concurrent/StructuredTaskScopeImpl$ConfigImpl,java/util/concurrent/StructuredTaskScopeImpl$SubtaskImpl flags 30 signature Ljava/lang/Object;Ljava/util/concurrent/StructuredTaskScope; +innerclass innerClass java/util/concurrent/StructuredTaskScope$Joiner outerClass java/util/concurrent/StructuredTaskScope innerClassName Joiner flags 609 +innerclass innerClass java/util/concurrent/StructuredTaskScopeImpl$ConfigImpl outerClass java/util/concurrent/StructuredTaskScopeImpl innerClassName ConfigImpl flags 18 +innerclass innerClass java/util/concurrent/StructuredTaskScope$Configuration outerClass java/util/concurrent/StructuredTaskScope innerClassName Configuration flags 609 +innerclass innerClass java/util/concurrent/StructuredTaskScopeImpl$SubtaskImpl outerClass java/util/concurrent/StructuredTaskScopeImpl innerClassName SubtaskImpl flags 18 +innerclass innerClass java/util/concurrent/StructuredTaskScope$Subtask outerClass java/util/concurrent/StructuredTaskScope innerClassName Subtask flags 609 +innerclass innerClass java/util/concurrent/StructuredTaskScope$Subtask$State outerClass java/util/concurrent/StructuredTaskScope$Subtask innerClassName State flags 4019 +innerclass innerClass java/util/concurrent/StructuredTaskScope$FailedException outerClass java/util/concurrent/StructuredTaskScope innerClassName FailedException flags 19 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 + +class name java/util/concurrent/StructuredTaskScopeImpl$SubtaskImpl +header extends java/lang/Object implements java/util/concurrent/StructuredTaskScope$Subtask,java/lang/Runnable nestHost java/util/concurrent/StructuredTaskScopeImpl flags 30 signature Ljava/lang/Object;Ljava/util/concurrent/StructuredTaskScope$Subtask;Ljava/lang/Runnable; +innerclass innerClass java/util/concurrent/StructuredTaskScopeImpl$SubtaskImpl outerClass java/util/concurrent/StructuredTaskScopeImpl innerClassName SubtaskImpl flags 18 +innerclass innerClass java/lang/Thread$State outerClass java/lang/Thread innerClassName State flags 4019 +innerclass innerClass java/util/concurrent/StructuredTaskScope$Subtask outerClass java/util/concurrent/StructuredTaskScope innerClassName Subtask flags 609 +innerclass innerClass java/util/concurrent/StructuredTaskScope$Subtask$State outerClass java/util/concurrent/StructuredTaskScope$Subtask innerClassName State flags 4019 + +class name java/util/stream/Collectors +header extends java/lang/Object flags 31 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/util/stream/Collector$Characteristics outerClass java/util/stream/Collector innerClassName Characteristics flags 4019 +innerclass innerClass java/util/Map$Entry outerClass java/util/Map innerClassName Entry flags 609 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 + +class name javax/crypto/EncryptedPrivateKeyInfo +header extends java/lang/Object implements java/security/DEREncodable flags 21 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 +-method name encryptKey descriptor (Ljava/security/PrivateKey;[CLjava/lang/String;Ljava/security/spec/AlgorithmParameterSpec;Ljava/security/Provider;)Ljavax/crypto/EncryptedPrivateKeyInfo; +-method name encryptKey descriptor (Ljava/security/PrivateKey;[C)Ljavax/crypto/EncryptedPrivateKeyInfo; +-method name encryptKey descriptor (Ljava/security/PrivateKey;Ljava/security/Key;Ljava/lang/String;Ljava/security/spec/AlgorithmParameterSpec;Ljava/security/Provider;Ljava/security/SecureRandom;)Ljavax/crypto/EncryptedPrivateKeyInfo; +-method name getKey descriptor ([C)Ljava/security/PrivateKey; +-method name getKey descriptor (Ljava/security/Key;Ljava/security/Provider;)Ljava/security/PrivateKey; +method name encrypt descriptor (Ljava/security/DEREncodable;[CLjava/lang/String;Ljava/security/spec/AlgorithmParameterSpec;Ljava/security/Provider;)Ljavax/crypto/EncryptedPrivateKeyInfo; flags 9 classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;PEM_API;) +method name encrypt descriptor (Ljava/security/DEREncodable;[C)Ljavax/crypto/EncryptedPrivateKeyInfo; flags 9 classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;PEM_API;) +method name encrypt descriptor (Ljava/security/DEREncodable;Ljava/security/Key;Ljava/lang/String;Ljava/security/spec/AlgorithmParameterSpec;Ljava/security/Provider;Ljava/security/SecureRandom;)Ljavax/crypto/EncryptedPrivateKeyInfo; flags 9 classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;PEM_API;) +method name getKey descriptor ([C)Ljava/security/PrivateKey; thrownTypes java/security/NoSuchAlgorithmException,java/security/InvalidKeyException flags 1 classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;PEM_API;) +method name getKey descriptor (Ljava/security/Key;Ljava/security/Provider;)Ljava/security/PrivateKey; thrownTypes java/security/NoSuchAlgorithmException,java/security/InvalidKeyException flags 1 classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;PEM_API;) +method name getKeyPair descriptor ([C)Ljava/security/KeyPair; thrownTypes java/security/NoSuchAlgorithmException,java/security/InvalidKeyException flags 1 classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;PEM_API;) +method name getKeyPair descriptor (Ljava/security/Key;Ljava/security/Provider;)Ljava/security/KeyPair; thrownTypes java/security/NoSuchAlgorithmException,java/security/InvalidKeyException flags 1 classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;PEM_API;) + +class name jdk/internal/classfile/impl/DirectCodeBuilder +header extends jdk/internal/classfile/impl/AbstractDirectBuilder implements jdk/internal/classfile/impl/TerminalCodeBuilder flags 31 signature Ljdk/internal/classfile/impl/AbstractDirectBuilder;Ljdk/internal/classfile/impl/TerminalCodeBuilder; +innerclass innerClass jdk/internal/classfile/impl/AbstractPseudoInstruction$ExceptionCatchImpl outerClass jdk/internal/classfile/impl/AbstractPseudoInstruction innerClassName ExceptionCatchImpl flags 19 +innerclass innerClass java/lang/classfile/Opcode$Kind outerClass java/lang/classfile/Opcode innerClassName Kind flags 4019 + +class name jdk/internal/classfile/impl/SignaturesImpl +method name nextIdentifierEnd descriptor (Ljava/lang/String;I)I flags 9 +method name validateIdentifier descriptor (Ljava/lang/String;)Ljava/lang/String; flags 9 +method name validatePackageSpecifierPlusIdentifier descriptor (Ljava/lang/String;)Ljava/lang/String; flags 9 +method name validateNonVoid descriptor (Ljava/lang/classfile/Signature;)Ljava/lang/classfile/Signature; flags 9 +method name validateArgumentList descriptor ([Ljava/lang/classfile/Signature;)Ljava/util/List; flags 9 signature ([Ljava/lang/classfile/Signature;)Ljava/util/List; +method name validateArgumentList descriptor (Ljava/util/List;)Ljava/util/List; flags 9 signature (Ljava/util/List;)Ljava/util/List; + +class name jdk/internal/classfile/impl/Util +header extends java/lang/Object nestMembers jdk/internal/classfile/impl/Util$WritableLocalVariable,jdk/internal/classfile/impl/Util$Writable flags 31 +innerclass innerClass java/lang/classfile/AttributeMapper$AttributeStability outerClass java/lang/classfile/AttributeMapper innerClassName AttributeStability flags 4019 +innerclass innerClass java/lang/classfile/ClassFile$AttributesProcessingOption outerClass java/lang/classfile/ClassFile innerClassName AttributesProcessingOption flags 4019 +innerclass innerClass java/lang/classfile/Opcode$Kind outerClass java/lang/classfile/Opcode innerClassName Kind flags 4019 +innerclass innerClass jdk/internal/classfile/impl/AbstractPoolEntry$Utf8EntryImpl outerClass jdk/internal/classfile/impl/AbstractPoolEntry innerClassName Utf8EntryImpl flags 19 +innerclass innerClass jdk/internal/classfile/impl/Util$Writable outerClass jdk/internal/classfile/impl/Util innerClassName Writable flags 608 +innerclass innerClass jdk/internal/classfile/impl/Util$WritableLocalVariable outerClass jdk/internal/classfile/impl/Util innerClassName WritableLocalVariable flags 608 +innerclass innerClass java/lang/reflect/AccessFlag$Location outerClass java/lang/reflect/AccessFlag innerClassName Location flags 4019 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 +method name sanitizeU1List descriptor (Ljava/util/List;)Ljava/util/List; flags 9 signature (Ljava/util/List;)Ljava/util/List; +method name sanitizeU2List descriptor (Ljava/util/Collection;)Ljava/util/List; flags 9 signature (Ljava/util/Collection;)Ljava/util/List; +method name sanitizeParameterAnnotations descriptor (Ljava/util/List;)Ljava/util/List; flags 9 signature (Ljava/util/List;>;)Ljava/util/List;>; +method name checkU1 descriptor (ILjava/lang/String;)I flags 9 +method name checkU2 descriptor (ILjava/lang/String;)C flags 9 +method name outOfRangeException descriptor (ILjava/lang/String;Ljava/lang/String;)Ljava/lang/IllegalArgumentException; flags 9 +method name checkFlags descriptor (I)C flags 9 + +class name jdk/internal/constant/AsTypeMethodHandleDesc +header extends java/lang/constant/DynamicConstantDesc implements java/lang/constant/MethodHandleDesc flags 31 signature Ljava/lang/constant/DynamicConstantDesc;Ljava/lang/constant/MethodHandleDesc; +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 +innerclass innerClass java/lang/constant/DirectMethodHandleDesc$Kind outerClass java/lang/constant/DirectMethodHandleDesc innerClassName Kind flags 4019 +method name descriptor (Ljava/lang/constant/MethodHandleDesc;Ljava/lang/constant/MethodTypeDesc;)V flags 1 +method name invocationType descriptor ()Ljava/lang/constant/MethodTypeDesc; flags 1 +method name resolveConstantDesc descriptor (Ljava/lang/invoke/MethodHandles$Lookup;)Ljava/lang/invoke/MethodHandle; thrownTypes java/lang/ReflectiveOperationException flags 1 +method name toString descriptor ()Ljava/lang/String; flags 1 +method name resolveConstantDesc descriptor (Ljava/lang/invoke/MethodHandles$Lookup;)Ljava/lang/Object; thrownTypes java/lang/ReflectiveOperationException flags 1041 methodParameters 1000:null + +class name jdk/internal/constant/PrimitiveClassDescImpl +header extends java/lang/constant/DynamicConstantDesc implements java/lang/constant/ClassDesc flags 31 signature Ljava/lang/constant/DynamicConstantDesc;>;Ljava/lang/constant/ClassDesc; runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 +innerclass innerClass java/lang/invoke/TypeDescriptor$OfField outerClass java/lang/invoke/TypeDescriptor innerClassName OfField flags 609 + +class name jdk/internal/lang/LazyConstantImpl +header extends java/lang/Object implements java/lang/LazyConstant flags 31 signature Ljava/lang/Object;Ljava/lang/LazyConstant; runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +method name get descriptor ()Ljava/lang/Object; flags 1 signature ()TT; runtimeAnnotations @Ljdk/internal/vm/annotation/ForceInline; +method name orElse descriptor (Ljava/lang/Object;)Ljava/lang/Object; flags 1 signature (TT;)TT; runtimeAnnotations @Ljdk/internal/vm/annotation/ForceInline; +method name isInitialized descriptor ()Z flags 1 runtimeAnnotations @Ljdk/internal/vm/annotation/ForceInline; +method name toString descriptor ()Ljava/lang/String; flags 1 +method name ofLazy descriptor (Ljava/util/function/Supplier;)Ljdk/internal/lang/LazyConstantImpl; flags 9 signature (Ljava/util/function/Supplier<+TT;>;)Ljdk/internal/lang/LazyConstantImpl; + +-class name jdk/internal/lang/stable/StableValueImpl + +class name jdk/internal/vm/vector/VectorSupport +-method name loadWithMap descriptor (Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/Class;ILjava/lang/Class;Ljava/lang/Object;JLjdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$VectorMask;Ljava/lang/Object;I[IILjdk/internal/vm/vector/VectorSupport$VectorSpecies;Ljdk/internal/vm/vector/VectorSupport$LoadVectorOperationWithMap;)Ljdk/internal/vm/vector/VectorSupport$Vector; +-method name storeWithMap descriptor (Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/Class;ILjava/lang/Class;Ljava/lang/Object;JLjdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$VectorMask;Ljava/lang/Object;I[IILjdk/internal/vm/vector/VectorSupport$StoreVectorOperationWithMap;)V +method name loadWithMap descriptor (Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/Class;ILjava/lang/Class;ILjava/lang/Object;JLjdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$VectorMask;Ljava/lang/Object;I[IILjdk/internal/vm/vector/VectorSupport$VectorSpecies;Ljdk/internal/vm/vector/VectorSupport$LoadVectorOperationWithMap;)Ljdk/internal/vm/vector/VectorSupport$Vector; flags 9 signature ;W:Ljdk/internal/vm/vector/VectorSupport$Vector;S:Ljdk/internal/vm/vector/VectorSupport$VectorSpecies;M:Ljdk/internal/vm/vector/VectorSupport$VectorMask;E:Ljava/lang/Object;>(Ljava/lang/Class<+TV;>;Ljava/lang/Class;Ljava/lang/Class;ILjava/lang/Class<+Ljdk/internal/vm/vector/VectorSupport$Vector;>;ILjava/lang/Object;JTW;TW;TW;TW;TM;TC;I[IITS;Ljdk/internal/vm/vector/VectorSupport$LoadVectorOperationWithMap;)TV; runtimeAnnotations @Ljdk/internal/vm/annotation/IntrinsicCandidate; +method name storeWithMap descriptor (Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/Class;ILjava/lang/Class;ILjava/lang/Object;JLjdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$VectorMask;Ljava/lang/Object;I[IILjdk/internal/vm/vector/VectorSupport$StoreVectorOperationWithMap;)V flags 9 signature ;W:Ljdk/internal/vm/vector/VectorSupport$Vector;M:Ljdk/internal/vm/vector/VectorSupport$VectorMask;E:Ljava/lang/Object;>(Ljava/lang/Class<+TV;>;Ljava/lang/Class;Ljava/lang/Class;ILjava/lang/Class<+Ljdk/internal/vm/vector/VectorSupport$Vector;>;ILjava/lang/Object;JTW;TV;TM;TC;I[IILjdk/internal/vm/vector/VectorSupport$StoreVectorOperationWithMap;)V runtimeAnnotations @Ljdk/internal/vm/annotation/IntrinsicCandidate; + +class name sun/nio/Cleaner +header extends java/lang/Object flags 601 +method name clean descriptor ()V flags 401 + +class name sun/nio/ch/DirectBuffer +-method name cleaner descriptor ()Ljdk/internal/ref/Cleaner; +method name cleaner descriptor ()Lsun/nio/Cleaner; flags 401 + diff --git a/src/jdk.compiler/share/data/symbols/java.compiler-Q.sym.txt b/src/jdk.compiler/share/data/symbols/java.compiler-Q.sym.txt new file mode 100644 index 00000000000..cb6ad893ace --- /dev/null +++ b/src/jdk.compiler/share/data/symbols/java.compiler-Q.sym.txt @@ -0,0 +1,85 @@ +# +# Copyright (c) 2025, 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. +# +# ########################################################## +# ### THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. ### +# ########################################################## +# +class name javax/lang/model/SourceVersion +field name RELEASE_26 descriptor Ljavax/lang/model/SourceVersion; flags 4019 + +class name javax/lang/model/util/AbstractAnnotationValueVisitor14 +header extends javax/lang/model/util/AbstractAnnotationValueVisitor9 flags 421 signature Ljavax/lang/model/util/AbstractAnnotationValueVisitor9; runtimeAnnotations @Ljavax/annotation/processing/SupportedSourceVersion;(value=eLjavax/lang/model/SourceVersion;RELEASE_26;) + +class name javax/lang/model/util/AbstractAnnotationValueVisitorPreview +header extends javax/lang/model/util/AbstractAnnotationValueVisitor14 flags 421 signature Ljavax/lang/model/util/AbstractAnnotationValueVisitor14; classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;LANGUAGE_MODEL;,reflective=Ztrue) runtimeAnnotations @Ljavax/annotation/processing/SupportedSourceVersion;(value=eLjavax/lang/model/SourceVersion;RELEASE_26;) + +class name javax/lang/model/util/AbstractElementVisitor14 +header extends javax/lang/model/util/AbstractElementVisitor9 flags 421 signature Ljavax/lang/model/util/AbstractElementVisitor9; runtimeAnnotations @Ljavax/annotation/processing/SupportedSourceVersion;(value=eLjavax/lang/model/SourceVersion;RELEASE_26;) + +class name javax/lang/model/util/AbstractElementVisitorPreview +header extends javax/lang/model/util/AbstractElementVisitor14 flags 421 signature Ljavax/lang/model/util/AbstractElementVisitor14; classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;LANGUAGE_MODEL;,reflective=Ztrue) runtimeAnnotations @Ljavax/annotation/processing/SupportedSourceVersion;(value=eLjavax/lang/model/SourceVersion;RELEASE_26;) + +class name javax/lang/model/util/AbstractTypeVisitor14 +header extends javax/lang/model/util/AbstractTypeVisitor9 flags 421 signature Ljavax/lang/model/util/AbstractTypeVisitor9; runtimeAnnotations @Ljavax/annotation/processing/SupportedSourceVersion;(value=eLjavax/lang/model/SourceVersion;RELEASE_26;) + +class name javax/lang/model/util/AbstractTypeVisitorPreview +header extends javax/lang/model/util/AbstractTypeVisitor14 flags 421 signature Ljavax/lang/model/util/AbstractTypeVisitor14; classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;LANGUAGE_MODEL;,reflective=Ztrue) runtimeAnnotations @Ljavax/annotation/processing/SupportedSourceVersion;(value=eLjavax/lang/model/SourceVersion;RELEASE_26;) + +class name javax/lang/model/util/ElementKindVisitor14 +header extends javax/lang/model/util/ElementKindVisitor9 flags 21 signature Ljavax/lang/model/util/ElementKindVisitor9; runtimeAnnotations @Ljavax/annotation/processing/SupportedSourceVersion;(value=eLjavax/lang/model/SourceVersion;RELEASE_26;) + +class name javax/lang/model/util/ElementKindVisitorPreview +header extends javax/lang/model/util/ElementKindVisitor14 flags 21 signature Ljavax/lang/model/util/ElementKindVisitor14; classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;LANGUAGE_MODEL;,reflective=Ztrue) runtimeAnnotations @Ljavax/annotation/processing/SupportedSourceVersion;(value=eLjavax/lang/model/SourceVersion;RELEASE_26;) + +class name javax/lang/model/util/ElementScanner14 +header extends javax/lang/model/util/ElementScanner9 flags 21 signature Ljavax/lang/model/util/ElementScanner9; runtimeAnnotations @Ljavax/annotation/processing/SupportedSourceVersion;(value=eLjavax/lang/model/SourceVersion;RELEASE_26;) + +class name javax/lang/model/util/ElementScannerPreview +header extends javax/lang/model/util/ElementScanner14 flags 21 signature Ljavax/lang/model/util/ElementScanner14; classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;LANGUAGE_MODEL;,reflective=Ztrue) runtimeAnnotations @Ljavax/annotation/processing/SupportedSourceVersion;(value=eLjavax/lang/model/SourceVersion;RELEASE_26;) + +class name javax/lang/model/util/SimpleAnnotationValueVisitor14 +header extends javax/lang/model/util/SimpleAnnotationValueVisitor9 flags 21 signature Ljavax/lang/model/util/SimpleAnnotationValueVisitor9; runtimeAnnotations @Ljavax/annotation/processing/SupportedSourceVersion;(value=eLjavax/lang/model/SourceVersion;RELEASE_26;) + +class name javax/lang/model/util/SimpleAnnotationValueVisitorPreview +header extends javax/lang/model/util/SimpleAnnotationValueVisitor14 flags 21 signature Ljavax/lang/model/util/SimpleAnnotationValueVisitor14; classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;LANGUAGE_MODEL;,reflective=Ztrue) runtimeAnnotations @Ljavax/annotation/processing/SupportedSourceVersion;(value=eLjavax/lang/model/SourceVersion;RELEASE_26;) + +class name javax/lang/model/util/SimpleElementVisitor14 +header extends javax/lang/model/util/SimpleElementVisitor9 flags 21 signature Ljavax/lang/model/util/SimpleElementVisitor9; runtimeAnnotations @Ljavax/annotation/processing/SupportedSourceVersion;(value=eLjavax/lang/model/SourceVersion;RELEASE_26;) + +class name javax/lang/model/util/SimpleElementVisitorPreview +header extends javax/lang/model/util/SimpleElementVisitor14 flags 21 signature Ljavax/lang/model/util/SimpleElementVisitor14; classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;LANGUAGE_MODEL;,reflective=Ztrue) runtimeAnnotations @Ljavax/annotation/processing/SupportedSourceVersion;(value=eLjavax/lang/model/SourceVersion;RELEASE_26;) + +class name javax/lang/model/util/SimpleTypeVisitor14 +header extends javax/lang/model/util/SimpleTypeVisitor9 flags 21 signature Ljavax/lang/model/util/SimpleTypeVisitor9; runtimeAnnotations @Ljavax/annotation/processing/SupportedSourceVersion;(value=eLjavax/lang/model/SourceVersion;RELEASE_26;) + +class name javax/lang/model/util/SimpleTypeVisitorPreview +header extends javax/lang/model/util/SimpleTypeVisitor14 flags 21 signature Ljavax/lang/model/util/SimpleTypeVisitor14; classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;LANGUAGE_MODEL;,reflective=Ztrue) runtimeAnnotations @Ljavax/annotation/processing/SupportedSourceVersion;(value=eLjavax/lang/model/SourceVersion;RELEASE_26;) + +class name javax/lang/model/util/TypeKindVisitor14 +header extends javax/lang/model/util/TypeKindVisitor9 flags 21 signature Ljavax/lang/model/util/TypeKindVisitor9; runtimeAnnotations @Ljavax/annotation/processing/SupportedSourceVersion;(value=eLjavax/lang/model/SourceVersion;RELEASE_26;) + +class name javax/lang/model/util/TypeKindVisitorPreview +header extends javax/lang/model/util/TypeKindVisitor14 flags 21 signature Ljavax/lang/model/util/TypeKindVisitor14; classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;LANGUAGE_MODEL;,reflective=Ztrue) runtimeAnnotations @Ljavax/annotation/processing/SupportedSourceVersion;(value=eLjavax/lang/model/SourceVersion;RELEASE_26;) + diff --git a/src/jdk.compiler/share/data/symbols/java.desktop-Q.sym.txt b/src/jdk.compiler/share/data/symbols/java.desktop-Q.sym.txt new file mode 100644 index 00000000000..f75ff5b3fac --- /dev/null +++ b/src/jdk.compiler/share/data/symbols/java.desktop-Q.sym.txt @@ -0,0 +1,90 @@ +# +# Copyright (c) 2025, 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. +# +# ########################################################## +# ### THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. ### +# ########################################################## +# +module name java.desktop +header exports java/awt,java/awt/color,java/awt/desktop,java/awt/dnd,java/awt/event,java/awt/font,java/awt/geom,java/awt/im,java/awt/im/spi,java/awt/image,java/awt/image/renderable,java/awt/print,java/beans,java/beans/beancontext,javax/accessibility,javax/imageio,javax/imageio/event,javax/imageio/metadata,javax/imageio/plugins/bmp,javax/imageio/plugins/jpeg,javax/imageio/plugins/tiff,javax/imageio/spi,javax/imageio/stream,javax/print,javax/print/attribute,javax/print/attribute/standard,javax/print/event,javax/sound,javax/sound/midi,javax/sound/midi/spi,javax/sound/sampled,javax/sound/sampled/spi,javax/swing,javax/swing/border,javax/swing/colorchooser,javax/swing/event,javax/swing/filechooser,javax/swing/plaf,javax/swing/plaf/basic,javax/swing/plaf/metal,javax/swing/plaf/multi,javax/swing/plaf/nimbus,javax/swing/plaf/synth,javax/swing/table,javax/swing/text,javax/swing/text/html,javax/swing/text/html/parser,javax/swing/text/rtf,javax/swing/tree,javax/swing/undo extraModulePackages sun/print requires name\u0020;java.base\u0020;flags\u0020;8000,name\u0020;java.prefs\u0020;flags\u0020;0,name\u0020;java.datatransfer\u0020;flags\u0020;20,name\u0020;java.xml\u0020;flags\u0020;20 uses java/awt/im/spi/InputMethodDescriptor,javax/accessibility/AccessibilityProvider,javax/imageio/spi/ImageInputStreamSpi,javax/imageio/spi/ImageOutputStreamSpi,javax/imageio/spi/ImageReaderSpi,javax/imageio/spi/ImageTranscoderSpi,javax/imageio/spi/ImageWriterSpi,javax/print/PrintServiceLookup,javax/print/StreamPrintServiceFactory,javax/sound/midi/spi/MidiDeviceProvider,javax/sound/midi/spi/MidiFileReader,javax/sound/midi/spi/MidiFileWriter,javax/sound/midi/spi/SoundbankReader,javax/sound/sampled/spi/AudioFileReader,javax/sound/sampled/spi/AudioFileWriter,javax/sound/sampled/spi/FormatConversionProvider,javax/sound/sampled/spi/MixerProvider,sun/swing/InteropProvider provides interface\u0020;sun/datatransfer/DesktopDatatransferService\u0020;impls\u0020;sun/awt/datatransfer/DesktopDatatransferServiceImpl,interface\u0020;java/net/ContentHandlerFactory\u0020;impls\u0020;sun/awt/www/content/MultimediaContentHandlers,interface\u0020;javax/print/PrintServiceLookup\u0020;impls\u0020;sun/print/PrintServiceLookupProvider,interface\u0020;javax/print/StreamPrintServiceFactory\u0020;impls\u0020;sun/print/PSStreamPrinterFactory,interface\u0020;javax/sound/midi/spi/MidiDeviceProvider\u0020;impls\u0020;com/sun/media/sound/MidiInDeviceProvider\u005C;u002C;com/sun/media/sound/MidiOutDeviceProvider\u005C;u002C;com/sun/media/sound/RealTimeSequencerProvider\u005C;u002C;com/sun/media/sound/SoftProvider,interface\u0020;javax/sound/midi/spi/MidiFileReader\u0020;impls\u0020;com/sun/media/sound/StandardMidiFileReader,interface\u0020;javax/sound/midi/spi/MidiFileWriter\u0020;impls\u0020;com/sun/media/sound/StandardMidiFileWriter,interface\u0020;javax/sound/midi/spi/SoundbankReader\u0020;impls\u0020;com/sun/media/sound/AudioFileSoundbankReader\u005C;u002C;com/sun/media/sound/DLSSoundbankReader\u005C;u002C;com/sun/media/sound/JARSoundbankReader\u005C;u002C;com/sun/media/sound/SF2SoundbankReader,interface\u0020;javax/sound/sampled/spi/AudioFileReader\u0020;impls\u0020;com/sun/media/sound/AiffFileReader\u005C;u002C;com/sun/media/sound/AuFileReader\u005C;u002C;com/sun/media/sound/SoftMidiAudioFileReader\u005C;u002C;com/sun/media/sound/WaveFileReader\u005C;u002C;com/sun/media/sound/WaveFloatFileReader\u005C;u002C;com/sun/media/sound/WaveExtensibleFileReader,interface\u0020;javax/sound/sampled/spi/AudioFileWriter\u0020;impls\u0020;com/sun/media/sound/AiffFileWriter\u005C;u002C;com/sun/media/sound/AuFileWriter\u005C;u002C;com/sun/media/sound/WaveFileWriter\u005C;u002C;com/sun/media/sound/WaveFloatFileWriter,interface\u0020;javax/sound/sampled/spi/FormatConversionProvider\u0020;impls\u0020;com/sun/media/sound/AlawCodec\u005C;u002C;com/sun/media/sound/AudioFloatFormatConverter\u005C;u002C;com/sun/media/sound/PCMtoPCMCodec\u005C;u002C;com/sun/media/sound/UlawCodec,interface\u0020;javax/sound/sampled/spi/MixerProvider\u0020;impls\u0020;com/sun/media/sound/DirectAudioDeviceProvider\u005C;u002C;com/sun/media/sound/PortMixerProvider target macos-aarch64 flags 8000 + +-class name java/applet/Applet + +-class name java/applet/Applet$AccessibleApplet + +-class name java/applet/AppletContext + +-class name java/applet/AppletStub + +-class name java/applet/AudioClip + +class name java/awt/Robot +field name DEFAULT_DELAY descriptor I constantValue 20 flags 19 +field name DEFAULT_STEP_LENGTH descriptor I constantValue 2 flags 19 +method name click descriptor (I)V flags 1 +method name click descriptor ()V flags 1 +method name waitForIdle descriptor (I)V flags 1 +method name glide descriptor (II)V flags 1 +method name glide descriptor (IIII)V flags 1 +method name glide descriptor (IIIIII)V flags 1 +method name type descriptor (I)V flags 21 +method name type descriptor (C)V flags 21 + +-class name java/beans/AppletInitializer + +class name java/beans/Beans +-method name instantiate descriptor (Ljava/lang/ClassLoader;Ljava/lang/String;Ljava/beans/beancontext/BeanContext;Ljava/beans/AppletInitializer;)Ljava/lang/Object; + +class name javax/imageio/spi/ServiceRegistry +-method name finalize descriptor ()V + +class name javax/imageio/stream/FileCacheImageInputStream +-method name finalize descriptor ()V + +class name javax/imageio/stream/FileImageInputStream +-method name finalize descriptor ()V + +class name javax/imageio/stream/FileImageOutputStream +-method name finalize descriptor ()V + +class name javax/imageio/stream/ImageInputStreamImpl +-method name finalize descriptor ()V + +class name javax/imageio/stream/MemoryCacheImageInputStream +-method name finalize descriptor ()V + +-class name javax/swing/JApplet + +-class name javax/swing/JApplet$AccessibleJApplet + +class name javax/swing/JTable +-method name setShowGrid descriptor (Z)V +method name setShowGrid descriptor (Z)V flags 1 runtimeAnnotations @Ljava/beans/BeanProperty;(description="Whether\u005C;u0020;grid\u005C;u0020;lines\u005C;u0020;are\u005C;u0020;drawn\u005C;u0020;around\u005C;u0020;the\u005C;u0020;cells.") + +class name javax/swing/RepaintManager +-method name addDirtyRegion descriptor (Ljava/applet/Applet;IIII)V + +class name javax/swing/plaf/synth/SynthPasswordFieldUI +-method name installKeyboardActions descriptor ()V + diff --git a/src/jdk.compiler/share/data/symbols/java.management-Q.sym.txt b/src/jdk.compiler/share/data/symbols/java.management-Q.sym.txt new file mode 100644 index 00000000000..03dacce810b --- /dev/null +++ b/src/jdk.compiler/share/data/symbols/java.management-Q.sym.txt @@ -0,0 +1,37 @@ +# +# Copyright (c) 2025, 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. +# +# ########################################################## +# ### THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. ### +# ########################################################## +# +class name java/lang/management/MemoryMXBean +method name getTotalGcCpuTime descriptor ()J flags 1 + +class name javax/management/modelmbean/DescriptorSupport +-method name descriptor (Ljava/lang/String;)V +-method name toXMLString descriptor ()Ljava/lang/String; + +-class name javax/management/modelmbean/XMLParseException + diff --git a/src/jdk.compiler/share/data/symbols/java.net.http-Q.sym.txt b/src/jdk.compiler/share/data/symbols/java.net.http-Q.sym.txt new file mode 100644 index 00000000000..bddf5c8d137 --- /dev/null +++ b/src/jdk.compiler/share/data/symbols/java.net.http-Q.sym.txt @@ -0,0 +1,125 @@ +# +# Copyright (c) 2025, 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. +# +# ########################################################## +# ### THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. ### +# ########################################################## +# +class name java/net/http/HttpClient$Version +field name HTTP_3 descriptor Ljava/net/http/HttpClient$Version; flags 4019 + +class name java/net/http/HttpOption +header extends java/lang/Object nestMembers java/net/http/HttpOption$Http3DiscoveryMode sealed true permittedSubclasses java/net/http/HttpRequestOptionImpl flags 601 signature Ljava/lang/Object; +innerclass innerClass java/net/http/HttpOption$Http3DiscoveryMode outerClass java/net/http/HttpOption innerClassName Http3DiscoveryMode flags 4019 +field name H3_DISCOVERY descriptor Ljava/net/http/HttpOption; flags 19 signature Ljava/net/http/HttpOption; +method name name descriptor ()Ljava/lang/String; flags 401 +method name type descriptor ()Ljava/lang/Class; flags 401 signature ()Ljava/lang/Class; + +class name java/net/http/HttpOption$Http3DiscoveryMode +header extends java/lang/Enum nestHost java/net/http/HttpOption flags 4031 signature Ljava/lang/Enum; +innerclass innerClass java/net/http/HttpOption$Http3DiscoveryMode outerClass java/net/http/HttpOption innerClassName Http3DiscoveryMode flags 4019 +field name ANY descriptor Ljava/net/http/HttpOption$Http3DiscoveryMode; flags 4019 +field name ALT_SVC descriptor Ljava/net/http/HttpOption$Http3DiscoveryMode; flags 4019 +field name HTTP_3_URI_ONLY descriptor Ljava/net/http/HttpOption$Http3DiscoveryMode; flags 4019 +method name values descriptor ()[Ljava/net/http/HttpOption$Http3DiscoveryMode; flags 9 +method name valueOf descriptor (Ljava/lang/String;)Ljava/net/http/HttpOption$Http3DiscoveryMode; flags 9 methodParameters 8000:null + +class name java/net/http/HttpRequest +header extends java/lang/Object nestMembers java/net/http/HttpRequest$BodyPublishers,java/net/http/HttpRequest$BodyPublisher,java/net/http/HttpRequest$Builder flags 421 +innerclass innerClass java/net/http/HttpRequest$Builder outerClass java/net/http/HttpRequest innerClassName Builder flags 609 +innerclass innerClass java/net/http/HttpRequest$BodyPublishers outerClass java/net/http/HttpRequest innerClassName BodyPublishers flags 9 +innerclass innerClass java/net/http/HttpRequest$BodyPublisher outerClass java/net/http/HttpRequest innerClassName BodyPublisher flags 609 +innerclass innerClass java/net/http/HttpClient$Version outerClass java/net/http/HttpClient innerClassName Version flags 4019 +innerclass innerClass java/net/http/HttpOption$Http3DiscoveryMode outerClass java/net/http/HttpOption innerClassName Http3DiscoveryMode flags 4019 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 +method name getOption descriptor (Ljava/net/http/HttpOption;)Ljava/util/Optional; flags 1 signature (Ljava/net/http/HttpOption;)Ljava/util/Optional; + +class name java/net/http/HttpRequest$BodyPublishers +method name ofFileChannel descriptor (Ljava/nio/channels/FileChannel;JJ)Ljava/net/http/HttpRequest$BodyPublisher; thrownTypes java/io/IOException flags 9 + +class name java/net/http/HttpRequest$Builder +method name setOption descriptor (Ljava/net/http/HttpOption;Ljava/lang/Object;)Ljava/net/http/HttpRequest$Builder; flags 1 signature (Ljava/net/http/HttpOption;TT;)Ljava/net/http/HttpRequest$Builder; + +class name java/net/http/HttpRequestOptionImpl +header extends java/lang/Record implements java/net/http/HttpOption record true flags 30 signature Ljava/lang/Record;Ljava/net/http/HttpOption; +recordcomponent name type descriptor Ljava/lang/Class; signature Ljava/lang/Class; +recordcomponent name name descriptor Ljava/lang/String; +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 +method name toString descriptor ()Ljava/lang/String; flags 1 +method name hashCode descriptor ()I flags 11 +method name equals descriptor (Ljava/lang/Object;)Z flags 11 +method name type descriptor ()Ljava/lang/Class; flags 1 signature ()Ljava/lang/Class; +method name name descriptor ()Ljava/lang/String; flags 1 + +class name java/net/http/HttpResponse +header extends java/lang/Object nestMembers java/net/http/HttpResponse$BodySubscribers,java/net/http/HttpResponse$BodySubscriber,java/net/http/HttpResponse$PushPromiseHandler,java/net/http/HttpResponse$PushPromiseHandler$PushId,java/net/http/HttpResponse$PushPromiseHandler$PushId$Http3PushId,java/net/http/HttpResponse$BodyHandlers,java/net/http/HttpResponse$BodyHandler,java/net/http/HttpResponse$ResponseInfo flags 601 signature Ljava/lang/Object; +innerclass innerClass java/net/http/HttpResponse$BodySubscribers outerClass java/net/http/HttpResponse innerClassName BodySubscribers flags 9 +innerclass innerClass java/net/http/HttpResponse$BodySubscriber outerClass java/net/http/HttpResponse innerClassName BodySubscriber flags 609 +innerclass innerClass java/net/http/HttpResponse$PushPromiseHandler outerClass java/net/http/HttpResponse innerClassName PushPromiseHandler flags 609 +innerclass innerClass java/net/http/HttpResponse$BodyHandlers outerClass java/net/http/HttpResponse innerClassName BodyHandlers flags 9 +innerclass innerClass java/net/http/HttpResponse$BodyHandler outerClass java/net/http/HttpResponse innerClassName BodyHandler flags 609 +innerclass innerClass java/net/http/HttpResponse$ResponseInfo outerClass java/net/http/HttpResponse innerClassName ResponseInfo flags 609 +innerclass innerClass java/net/http/HttpClient$Version outerClass java/net/http/HttpClient innerClassName Version flags 4019 +innerclass innerClass java/net/http/HttpResponse$PushPromiseHandler$PushId outerClass java/net/http/HttpResponse$PushPromiseHandler innerClassName PushId flags 609 +innerclass innerClass java/net/http/HttpResponse$PushPromiseHandler$PushId$Http3PushId outerClass java/net/http/HttpResponse$PushPromiseHandler$PushId innerClassName Http3PushId flags 19 + +class name java/net/http/HttpResponse$PushPromiseHandler +header extends java/lang/Object nestHost java/net/http/HttpResponse flags 601 signature Ljava/lang/Object; +innerclass innerClass java/net/http/HttpResponse$PushPromiseHandler outerClass java/net/http/HttpResponse innerClassName PushPromiseHandler flags 609 +innerclass innerClass java/net/http/HttpResponse$PushPromiseHandler$PushId outerClass java/net/http/HttpResponse$PushPromiseHandler innerClassName PushId flags 609 +innerclass innerClass java/net/http/HttpResponse$BodyHandler outerClass java/net/http/HttpResponse innerClassName BodyHandler flags 609 +method name applyPushPromise descriptor (Ljava/net/http/HttpRequest;Ljava/net/http/HttpRequest;Ljava/net/http/HttpResponse$PushPromiseHandler$PushId;Ljava/util/function/Function;)V flags 1 signature (Ljava/net/http/HttpRequest;Ljava/net/http/HttpRequest;Ljava/net/http/HttpResponse$PushPromiseHandler$PushId;Ljava/util/function/Function;Ljava/util/concurrent/CompletableFuture;>;>;)V +method name notifyAdditionalPromise descriptor (Ljava/net/http/HttpRequest;Ljava/net/http/HttpResponse$PushPromiseHandler$PushId;)V flags 1 + +class name java/net/http/HttpResponse$PushPromiseHandler$PushId +header extends java/lang/Object nestHost java/net/http/HttpResponse sealed true permittedSubclasses java/net/http/HttpResponse$PushPromiseHandler$PushId$Http3PushId flags 601 +innerclass innerClass java/net/http/HttpResponse$PushPromiseHandler outerClass java/net/http/HttpResponse innerClassName PushPromiseHandler flags 609 +innerclass innerClass java/net/http/HttpResponse$PushPromiseHandler$PushId outerClass java/net/http/HttpResponse$PushPromiseHandler innerClassName PushId flags 609 +innerclass innerClass java/net/http/HttpResponse$PushPromiseHandler$PushId$Http3PushId outerClass java/net/http/HttpResponse$PushPromiseHandler$PushId innerClassName Http3PushId flags 19 + +class name java/net/http/HttpResponse$PushPromiseHandler$PushId$Http3PushId +header extends java/lang/Record implements java/net/http/HttpResponse$PushPromiseHandler$PushId nestHost java/net/http/HttpResponse record true flags 31 +recordcomponent name pushId descriptor J +recordcomponent name connectionLabel descriptor Ljava/lang/String; +innerclass innerClass java/net/http/HttpResponse$PushPromiseHandler outerClass java/net/http/HttpResponse innerClassName PushPromiseHandler flags 609 +innerclass innerClass java/net/http/HttpResponse$PushPromiseHandler$PushId outerClass java/net/http/HttpResponse$PushPromiseHandler innerClassName PushId flags 609 +innerclass innerClass java/net/http/HttpResponse$PushPromiseHandler$PushId$Http3PushId outerClass java/net/http/HttpResponse$PushPromiseHandler$PushId innerClassName Http3PushId flags 19 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 +method name descriptor (JLjava/lang/String;)V flags 1 methodParameters 0:pushId,0:connectionLabel +method name toString descriptor ()Ljava/lang/String; flags 11 +method name hashCode descriptor ()I flags 11 +method name equals descriptor (Ljava/lang/Object;)Z flags 11 +method name pushId descriptor ()J flags 1 +method name connectionLabel descriptor ()Ljava/lang/String; flags 1 + +class name java/net/http/StreamLimitException +header extends java/io/IOException flags 31 +innerclass innerClass java/net/http/HttpClient$Version outerClass java/net/http/HttpClient innerClassName Version flags 4019 +method name descriptor (Ljava/net/http/HttpClient$Version;Ljava/lang/String;)V flags 1 +method name version descriptor ()Ljava/net/http/HttpClient$Version; flags 11 + +class name java/net/http/UnsupportedProtocolVersionException +header extends java/io/IOException flags 31 +method name descriptor (Ljava/lang/String;)V flags 1 + diff --git a/src/jdk.compiler/share/data/symbols/jdk.httpserver-Q.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.httpserver-Q.sym.txt new file mode 100644 index 00000000000..70cc330edca --- /dev/null +++ b/src/jdk.compiler/share/data/symbols/jdk.httpserver-Q.sym.txt @@ -0,0 +1,32 @@ +# +# Copyright (c) 2025, 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. +# +# ########################################################## +# ### THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. ### +# ########################################################## +# +class name com/sun/net/httpserver/HttpExchange +field name RSPBODY_EMPTY descriptor J constantValue -1 flags 19 +field name RSPBODY_CHUNKED descriptor J constantValue 0 flags 19 + diff --git a/src/jdk.compiler/share/data/symbols/jdk.incubator.vector-Q.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.incubator.vector-Q.sym.txt new file mode 100644 index 00000000000..223be24ab56 --- /dev/null +++ b/src/jdk.compiler/share/data/symbols/jdk.incubator.vector-Q.sym.txt @@ -0,0 +1,32 @@ +# +# Copyright (c) 2025, 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. +# +# ########################################################## +# ### THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. ### +# ########################################################## +# +class name jdk/incubator/vector/VectorOperators +-field name SUADD descriptor Ljdk/incubator/vector/VectorOperators$Binary; +field name SUADD descriptor Ljdk/incubator/vector/VectorOperators$Associative; flags 19 + diff --git a/src/jdk.compiler/share/data/symbols/jdk.jartool-Q.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jartool-Q.sym.txt new file mode 100644 index 00000000000..47838de0844 --- /dev/null +++ b/src/jdk.compiler/share/data/symbols/jdk.jartool-Q.sym.txt @@ -0,0 +1,31 @@ +# +# Copyright (c) 2025, 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. +# +# ########################################################## +# ### THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. ### +# ########################################################## +# +module name jdk.jartool +header exports jdk/security/jarsigner requires name\u0020;java.base\u0020;flags\u0020;8000,name\u0020;jdk.internal.opt\u0020;flags\u0020;0 provides interface\u0020;java/util/spi/ToolProvider\u0020;impls\u0020;sun/tools/jar/JarToolProvider target macos-aarch64 moduleMainClass sun/tools/jar/Main flags 8000 + diff --git a/src/jdk.compiler/share/data/symbols/jdk.jdeps-Q.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jdeps-Q.sym.txt new file mode 100644 index 00000000000..e5d0bb627e5 --- /dev/null +++ b/src/jdk.compiler/share/data/symbols/jdk.jdeps-Q.sym.txt @@ -0,0 +1,31 @@ +# +# Copyright (c) 2025, 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. +# +# ########################################################## +# ### THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. ### +# ########################################################## +# +module name jdk.jdeps +header requires name\u0020;java.base\u0020;flags\u0020;8000,name\u0020;java.compiler\u0020;flags\u0020;0,name\u0020;jdk.compiler\u0020;flags\u0020;0,name\u0020;jdk.internal.opt\u0020;flags\u0020;0 uses com/sun/tools/javac/platform/PlatformProvider provides interface\u0020;java/util/spi/ToolProvider\u0020;impls\u0020;com/sun/tools/javap/Main$JavapToolProvider\u005C;u002C;com/sun/tools/jdeps/Main$JDepsToolProvider\u005C;u002C;com/sun/tools/jnativescan/Main$Provider target macos-aarch64 flags 8000 + diff --git a/src/jdk.compiler/share/data/symbols/jdk.jfr-Q.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jfr-Q.sym.txt new file mode 100644 index 00000000000..2e3c13ea64c --- /dev/null +++ b/src/jdk.compiler/share/data/symbols/jdk.jfr-Q.sym.txt @@ -0,0 +1,31 @@ +# +# Copyright (c) 2025, 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. +# +# ########################################################## +# ### THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. ### +# ########################################################## +# +module name jdk.jfr +header exports jdk/jfr,jdk/jfr/consumer requires name\u0020;java.base\u0020;flags\u0020;8000 target macos-aarch64 moduleMainClass jdk/jfr/internal/tool/Main flags 8000 + diff --git a/src/jdk.compiler/share/data/symbols/jdk.jlink-Q.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jlink-Q.sym.txt new file mode 100644 index 00000000000..e3e9eadf355 --- /dev/null +++ b/src/jdk.compiler/share/data/symbols/jdk.jlink-Q.sym.txt @@ -0,0 +1,31 @@ +# +# Copyright (c) 2025, 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. +# +# ########################################################## +# ### THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. ### +# ########################################################## +# +module name jdk.jlink +header requires name\u0020;java.base\u0020;flags\u0020;8000,name\u0020;jdk.internal.opt\u0020;flags\u0020;0,name\u0020;jdk.jdeps\u0020;flags\u0020;0 uses jdk/tools/jlink/plugin/Plugin provides interface\u0020;java/util/spi/ToolProvider\u0020;impls\u0020;jdk/tools/jmod/Main$JmodToolProvider\u005C;u002C;jdk/tools/jlink/internal/Main$JlinkToolProvider,interface\u0020;jdk/tools/jlink/plugin/Plugin\u0020;impls\u0020;jdk/tools/jlink/internal/plugins/DefaultStripDebugPlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/StripJavaDebugAttributesPlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/ExcludePlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/ExcludeFilesPlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/ExcludeJmodSectionPlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/LegalNoticeFilePlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/SystemModulesPlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/StripNativeCommandsPlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/OrderResourcesPlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/DefaultCompressPlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/ExcludeVMPlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/IncludeLocalesPlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/GenerateJLIClassesPlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/ReleaseInfoPlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/AddOptionsPlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/VendorBugURLPlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/VendorVMBugURLPlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/VendorVersionPlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/CDSPlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/SaveJlinkArgfilesPlugin target macos-aarch64 flags 8000 + diff --git a/src/jdk.compiler/share/data/symbols/jdk.jshell-Q.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jshell-Q.sym.txt new file mode 100644 index 00000000000..1dff60fc776 --- /dev/null +++ b/src/jdk.compiler/share/data/symbols/jdk.jshell-Q.sym.txt @@ -0,0 +1,169 @@ +# +# Copyright (c) 2025, 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. +# +# ########################################################## +# ### THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. ### +# ########################################################## +# +module name jdk.jshell +header exports jdk/jshell,jdk/jshell/execution,jdk/jshell/spi,jdk/jshell/tool requires name\u0020;java.base\u0020;flags\u0020;8000,name\u0020;java.logging\u0020;flags\u0020;0,name\u0020;jdk.compiler\u0020;flags\u0020;0,name\u0020;jdk.internal.ed\u0020;flags\u0020;0,name\u0020;jdk.internal.le\u0020;flags\u0020;0,name\u0020;jdk.internal.md\u0020;flags\u0020;0,name\u0020;jdk.internal.opt\u0020;flags\u0020;0,name\u0020;java.compiler\u0020;flags\u0020;20,name\u0020;java.prefs\u0020;flags\u0020;20,name\u0020;jdk.jdi\u0020;flags\u0020;20 uses jdk/jshell/spi/ExecutionControlProvider,jdk/internal/editor/spi/BuildInEditorProvider provides interface\u0020;javax/tools/Tool\u0020;impls\u0020;jdk/internal/jshell/tool/JShellToolProvider,interface\u0020;jdk/jshell/spi/ExecutionControlProvider\u0020;impls\u0020;jdk/jshell/execution/JdiExecutionControlProvider\u005C;u002C;jdk/jshell/execution/LocalExecutionControlProvider\u005C;u002C;jdk/jshell/execution/FailOverExecutionControlProvider,interface\u0020;jdk/internal/io/JdkConsoleProvider\u0020;impls\u0020;jdk/jshell/execution/impl/ConsoleImpl$ConsoleProviderImpl target macos-aarch64 moduleMainClass jdk/internal/jshell/tool/JShellToolProvider flags 8000 + +class name jdk/jshell/SourceCodeAnalysis +header extends java/lang/Object nestMembers jdk/jshell/SourceCodeAnalysis$Attribute,jdk/jshell/SourceCodeAnalysis$Highlight,jdk/jshell/SourceCodeAnalysis$SnippetWrapper,jdk/jshell/SourceCodeAnalysis$QualifiedNames,jdk/jshell/SourceCodeAnalysis$Documentation,jdk/jshell/SourceCodeAnalysis$ElementSuggestionConvertor,jdk/jshell/SourceCodeAnalysis$CompletionContext,jdk/jshell/SourceCodeAnalysis$CompletionState,jdk/jshell/SourceCodeAnalysis$ElementSuggestion,jdk/jshell/SourceCodeAnalysis$Suggestion,jdk/jshell/SourceCodeAnalysis$Completeness,jdk/jshell/SourceCodeAnalysis$CompletionInfo flags 421 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$Attribute outerClass jdk/jshell/SourceCodeAnalysis innerClassName Attribute flags 4019 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$Highlight outerClass jdk/jshell/SourceCodeAnalysis innerClassName Highlight flags 19 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$SnippetWrapper outerClass jdk/jshell/SourceCodeAnalysis innerClassName SnippetWrapper flags 609 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$QualifiedNames outerClass jdk/jshell/SourceCodeAnalysis innerClassName QualifiedNames flags 19 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$Documentation outerClass jdk/jshell/SourceCodeAnalysis innerClassName Documentation flags 609 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$ElementSuggestionConvertor outerClass jdk/jshell/SourceCodeAnalysis innerClassName ElementSuggestionConvertor flags 609 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$CompletionContext outerClass jdk/jshell/SourceCodeAnalysis innerClassName CompletionContext flags 4019 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$CompletionState outerClass jdk/jshell/SourceCodeAnalysis innerClassName CompletionState flags 609 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$ElementSuggestion outerClass jdk/jshell/SourceCodeAnalysis innerClassName ElementSuggestion flags 609 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$Suggestion outerClass jdk/jshell/SourceCodeAnalysis innerClassName Suggestion flags 609 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$Completeness outerClass jdk/jshell/SourceCodeAnalysis innerClassName Completeness flags 4019 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$CompletionInfo outerClass jdk/jshell/SourceCodeAnalysis innerClassName CompletionInfo flags 609 +method name completionSuggestions descriptor (Ljava/lang/String;ILjdk/jshell/SourceCodeAnalysis$ElementSuggestionConvertor;)Ljava/util/List; flags 401 signature (Ljava/lang/String;ILjdk/jshell/SourceCodeAnalysis$ElementSuggestionConvertor;)Ljava/util/List; + +class name jdk/jshell/SourceCodeAnalysis$CompletionContext +header extends java/lang/Enum nestHost jdk/jshell/SourceCodeAnalysis flags 4031 signature Ljava/lang/Enum; +innerclass innerClass jdk/jshell/SourceCodeAnalysis$CompletionContext outerClass jdk/jshell/SourceCodeAnalysis innerClassName CompletionContext flags 4019 +field name ANNOTATION_ATTRIBUTE descriptor Ljdk/jshell/SourceCodeAnalysis$CompletionContext; flags 4019 +field name NO_PAREN descriptor Ljdk/jshell/SourceCodeAnalysis$CompletionContext; flags 4019 +field name TYPES_AS_ANNOTATIONS descriptor Ljdk/jshell/SourceCodeAnalysis$CompletionContext; flags 4019 +field name QUALIFIED descriptor Ljdk/jshell/SourceCodeAnalysis$CompletionContext; flags 4019 +method name values descriptor ()[Ljdk/jshell/SourceCodeAnalysis$CompletionContext; flags 9 +method name valueOf descriptor (Ljava/lang/String;)Ljdk/jshell/SourceCodeAnalysis$CompletionContext; flags 9 methodParameters 8000:null + +class name jdk/jshell/SourceCodeAnalysis$CompletionState +header extends java/lang/Object nestHost jdk/jshell/SourceCodeAnalysis sealed true permittedSubclasses jdk/jshell/SourceCodeAnalysisImpl$CompletionStateImpl flags 601 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$CompletionState outerClass jdk/jshell/SourceCodeAnalysis innerClassName CompletionState flags 609 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$CompletionContext outerClass jdk/jshell/SourceCodeAnalysis innerClassName CompletionContext flags 4019 +innerclass innerClass jdk/jshell/SourceCodeAnalysisImpl$CompletionStateImpl outerClass jdk/jshell/SourceCodeAnalysisImpl innerClassName CompletionStateImpl flags 18 +method name availableUsingSimpleName descriptor (Ljavax/lang/model/element/Element;)Z flags 401 +method name completionContext descriptor ()Ljava/util/Set; flags 401 signature ()Ljava/util/Set; +method name selectorType descriptor ()Ljavax/lang/model/type/TypeMirror; flags 401 +method name elementUtils descriptor ()Ljavax/lang/model/util/Elements; flags 401 +method name typeUtils descriptor ()Ljavax/lang/model/util/Types; flags 401 + +class name jdk/jshell/SourceCodeAnalysis$Documentation +method name activeParameterIndex descriptor ()I flags 1 + +class name jdk/jshell/SourceCodeAnalysis$ElementSuggestion +header extends java/lang/Object nestHost jdk/jshell/SourceCodeAnalysis sealed true permittedSubclasses jdk/jshell/SourceCodeAnalysisImpl$ElementSuggestionImpl flags 601 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$ElementSuggestion outerClass jdk/jshell/SourceCodeAnalysis innerClassName ElementSuggestion flags 609 +innerclass innerClass jdk/jshell/SourceCodeAnalysisImpl$ElementSuggestionImpl outerClass jdk/jshell/SourceCodeAnalysisImpl innerClassName ElementSuggestionImpl flags 18 +method name element descriptor ()Ljavax/lang/model/element/Element; flags 401 +method name keyword descriptor ()Ljava/lang/String; flags 401 +method name matchesType descriptor ()Z flags 401 +method name anchor descriptor ()I flags 401 +method name documentation descriptor ()Ljava/util/function/Supplier; flags 401 signature ()Ljava/util/function/Supplier; + +class name jdk/jshell/SourceCodeAnalysis$ElementSuggestionConvertor +header extends java/lang/Object nestHost jdk/jshell/SourceCodeAnalysis flags 601 signature Ljava/lang/Object; +innerclass innerClass jdk/jshell/SourceCodeAnalysis$ElementSuggestionConvertor outerClass jdk/jshell/SourceCodeAnalysis innerClassName ElementSuggestionConvertor flags 609 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$CompletionState outerClass jdk/jshell/SourceCodeAnalysis innerClassName CompletionState flags 609 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$ElementSuggestion outerClass jdk/jshell/SourceCodeAnalysis innerClassName ElementSuggestion flags 609 +method name convert descriptor (Ljdk/jshell/SourceCodeAnalysis$CompletionState;Ljava/util/List;)Ljava/util/List; flags 401 signature (Ljdk/jshell/SourceCodeAnalysis$CompletionState;Ljava/util/List<+Ljdk/jshell/SourceCodeAnalysis$ElementSuggestion;>;)Ljava/util/List; + +class name jdk/jshell/SourceCodeAnalysisImpl +header extends jdk/jshell/SourceCodeAnalysis nestMembers jdk/jshell/SourceCodeAnalysisImpl$CompletionStateImpl,jdk/jshell/SourceCodeAnalysisImpl$ElementSuggestionImpl flags 20 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$Completeness outerClass jdk/jshell/SourceCodeAnalysis innerClassName Completeness flags 4019 +innerclass innerClass com/sun/source/tree/Tree$Kind outerClass com/sun/source/tree/Tree innerClassName Kind flags 4019 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$ElementSuggestionConvertor outerClass jdk/jshell/SourceCodeAnalysis innerClassName ElementSuggestionConvertor flags 609 +innerclass innerClass jdk/jshell/SourceCodeAnalysisImpl$ElementSuggestionImpl outerClass jdk/jshell/SourceCodeAnalysisImpl innerClassName ElementSuggestionImpl flags 18 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$CompletionState outerClass jdk/jshell/SourceCodeAnalysis innerClassName CompletionState flags 609 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$CompletionContext outerClass jdk/jshell/SourceCodeAnalysis innerClassName CompletionContext flags 4019 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$QualifiedNames outerClass jdk/jshell/SourceCodeAnalysis innerClassName QualifiedNames flags 19 +innerclass innerClass javax/tools/JavaFileManager$Location outerClass javax/tools/JavaFileManager innerClassName Location flags 609 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$CompletionInfo outerClass jdk/jshell/SourceCodeAnalysis innerClassName CompletionInfo flags 609 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$Documentation outerClass jdk/jshell/SourceCodeAnalysis innerClassName Documentation flags 609 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$Highlight outerClass jdk/jshell/SourceCodeAnalysis innerClassName Highlight flags 19 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$Attribute outerClass jdk/jshell/SourceCodeAnalysis innerClassName Attribute flags 4019 +innerclass innerClass jdk/jshell/SourceCodeAnalysisImpl$CompletionStateImpl outerClass jdk/jshell/SourceCodeAnalysisImpl innerClassName CompletionStateImpl flags 18 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$ElementSuggestion outerClass jdk/jshell/SourceCodeAnalysis innerClassName ElementSuggestion flags 609 +innerclass innerClass java/lang/Thread$UncaughtExceptionHandler outerClass java/lang/Thread innerClassName UncaughtExceptionHandler flags 609 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$Suggestion outerClass jdk/jshell/SourceCodeAnalysis innerClassName Suggestion flags 609 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$SnippetWrapper outerClass jdk/jshell/SourceCodeAnalysis innerClassName SnippetWrapper flags 609 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 +method name analyzeCompletion descriptor (Ljava/lang/String;)Ljdk/jshell/SourceCodeAnalysis$CompletionInfo; flags 1 +method name completionSuggestions descriptor (Ljava/lang/String;I[I)Ljava/util/List; flags 1 signature (Ljava/lang/String;I[I)Ljava/util/List; +method name completionSuggestions descriptor (Ljava/lang/String;ILjdk/jshell/SourceCodeAnalysis$ElementSuggestionConvertor;)Ljava/util/List; flags 1 signature (Ljava/lang/String;ILjdk/jshell/SourceCodeAnalysis$ElementSuggestionConvertor;)Ljava/util/List; +method name wrapper descriptor (Ljdk/jshell/Snippet;)Ljdk/jshell/SourceCodeAnalysis$SnippetWrapper; flags 1 +method name wrappers descriptor (Ljava/lang/String;)Ljava/util/List; flags 1 signature (Ljava/lang/String;)Ljava/util/List; +method name sourceToSnippets descriptor (Ljava/lang/String;)Ljava/util/List; flags 1 signature (Ljava/lang/String;)Ljava/util/List; +method name dependents descriptor (Ljdk/jshell/Snippet;)Ljava/util/Collection; flags 1 signature (Ljdk/jshell/Snippet;)Ljava/util/Collection; +method name highlights descriptor (Ljava/lang/String;)Ljava/util/List; flags 1 signature (Ljava/lang/String;)Ljava/util/List; +method name documentation descriptor (Ljava/lang/String;IZ)Ljava/util/List; flags 1 signature (Ljava/lang/String;IZ)Ljava/util/List; +method name close descriptor ()V flags 1 +method name analyzeType descriptor (Ljava/lang/String;I)Ljava/lang/String; flags 1 +method name listQualifiedNames descriptor (Ljava/lang/String;I)Ljdk/jshell/SourceCodeAnalysis$QualifiedNames; flags 1 +method name suspendIndexing descriptor ()V flags 1 +method name resumeIndexing descriptor ()V flags 1 +method name waitBackgroundTaskFinished descriptor ()V thrownTypes java/lang/Exception flags 1 +method name waitCurrentBackgroundTasksFinished descriptor ()V thrownTypes java/lang/Exception flags 9 + +class name jdk/jshell/SourceCodeAnalysisImpl$CompletionStateImpl +header extends java/lang/Object implements jdk/jshell/SourceCodeAnalysis$CompletionState nestHost jdk/jshell/SourceCodeAnalysisImpl flags 30 +innerclass innerClass jdk/jshell/SourceCodeAnalysisImpl$CompletionStateImpl outerClass jdk/jshell/SourceCodeAnalysisImpl innerClassName CompletionStateImpl flags 18 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$CompletionState outerClass jdk/jshell/SourceCodeAnalysis innerClassName CompletionState flags 609 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$CompletionContext outerClass jdk/jshell/SourceCodeAnalysis innerClassName CompletionContext flags 4019 +method name descriptor (Ljava/util/Collection;Ljava/util/Set;Ljavax/lang/model/type/TypeMirror;Ljavax/lang/model/util/Elements;Ljavax/lang/model/util/Types;)V flags 1 signature (Ljava/util/Collection<+Ljavax/lang/model/element/Element;>;Ljava/util/Set;Ljavax/lang/model/type/TypeMirror;Ljavax/lang/model/util/Elements;Ljavax/lang/model/util/Types;)V +method name availableUsingSimpleName descriptor (Ljavax/lang/model/element/Element;)Z flags 1 +method name completionContext descriptor ()Ljava/util/Set; flags 1 signature ()Ljava/util/Set; +method name selectorType descriptor ()Ljavax/lang/model/type/TypeMirror; flags 1 +method name elementUtils descriptor ()Ljavax/lang/model/util/Elements; flags 1 +method name typeUtils descriptor ()Ljavax/lang/model/util/Types; flags 1 + +class name jdk/jshell/SourceCodeAnalysisImpl$ElementSuggestionImpl +header extends java/lang/Record implements jdk/jshell/SourceCodeAnalysis$ElementSuggestion nestHost jdk/jshell/SourceCodeAnalysisImpl record true flags 30 +recordcomponent name element descriptor Ljavax/lang/model/element/Element; +recordcomponent name keyword descriptor Ljava/lang/String; +recordcomponent name matchesType descriptor Z +recordcomponent name anchor descriptor I +recordcomponent name documentation descriptor Ljava/util/function/Supplier; signature Ljava/util/function/Supplier; +innerclass innerClass jdk/jshell/SourceCodeAnalysisImpl$ElementSuggestionImpl outerClass jdk/jshell/SourceCodeAnalysisImpl innerClassName ElementSuggestionImpl flags 18 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$ElementSuggestion outerClass jdk/jshell/SourceCodeAnalysis innerClassName ElementSuggestion flags 609 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 +method name toString descriptor ()Ljava/lang/String; flags 11 +method name hashCode descriptor ()I flags 11 +method name equals descriptor (Ljava/lang/Object;)Z flags 11 +method name element descriptor ()Ljavax/lang/model/element/Element; flags 1 +method name keyword descriptor ()Ljava/lang/String; flags 1 +method name matchesType descriptor ()Z flags 1 +method name anchor descriptor ()I flags 1 +method name documentation descriptor ()Ljava/util/function/Supplier; flags 1 signature ()Ljava/util/function/Supplier; + +class name jdk/jshell/execution/LocalExecutionControl +header extends jdk/jshell/execution/DirectExecutionControl flags 21 +innerclass innerClass jdk/jshell/spi/ExecutionControl$ClassBytecodes outerClass jdk/jshell/spi/ExecutionControl innerClassName ClassBytecodes flags 19 +innerclass innerClass java/lang/classfile/ClassFile$Option outerClass java/lang/classfile/ClassFile innerClassName Option flags 609 +innerclass innerClass java/lang/classfile/ClassFile$ClassHierarchyResolverOption outerClass java/lang/classfile/ClassFile innerClassName ClassHierarchyResolverOption flags 609 +innerclass innerClass jdk/jshell/spi/ExecutionControl$StoppedException outerClass jdk/jshell/spi/ExecutionControl innerClassName StoppedException flags 9 +innerclass innerClass jdk/jshell/spi/ExecutionControl$InternalException outerClass jdk/jshell/spi/ExecutionControl innerClassName InternalException flags 9 +innerclass innerClass java/lang/classfile/CodeBuilder$BlockCodeBuilder outerClass java/lang/classfile/CodeBuilder innerClassName BlockCodeBuilder flags 609 +innerclass innerClass jdk/jshell/spi/ExecutionControl$ClassInstallException outerClass jdk/jshell/spi/ExecutionControl innerClassName ClassInstallException flags 9 +innerclass innerClass jdk/jshell/spi/ExecutionControl$NotImplementedException outerClass jdk/jshell/spi/ExecutionControl innerClassName NotImplementedException flags 9 +innerclass innerClass jdk/jshell/spi/ExecutionControl$EngineTerminationException outerClass jdk/jshell/spi/ExecutionControl innerClassName EngineTerminationException flags 9 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 + diff --git a/src/jdk.compiler/share/data/symbols/jdk.jsobject-Q.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jsobject-Q.sym.txt new file mode 100644 index 00000000000..c8b83f6800b --- /dev/null +++ b/src/jdk.compiler/share/data/symbols/jdk.jsobject-Q.sym.txt @@ -0,0 +1,34 @@ +# +# Copyright (c) 2025, 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. +# +# ########################################################## +# ### THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. ### +# ########################################################## +# +-module name jdk.jsobject + +-class name netscape/javascript/JSException + +-class name netscape/javascript/JSObject + diff --git a/src/jdk.compiler/share/data/symbols/jdk.localedata-Q.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.localedata-Q.sym.txt new file mode 100644 index 00000000000..71d9c3fea14 --- /dev/null +++ b/src/jdk.compiler/share/data/symbols/jdk.localedata-Q.sym.txt @@ -0,0 +1,31 @@ +# +# Copyright (c) 2025, 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. +# +# ########################################################## +# ### THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. ### +# ########################################################## +# +module name jdk.localedata +header requires name\u0020;java.base\u0020;flags\u0020;8000 provides interface\u0020;sun/util/locale/provider/LocaleDataMetaInfo\u0020;impls\u0020;sun/util/resources/cldr/provider/CLDRLocaleDataMetaInfo\u005C;u002C;sun/util/resources/provider/NonBaseLocaleDataMetaInfo,interface\u0020;sun/util/resources/LocaleData$LocaleDataResourceBundleProvider\u0020;impls\u0020;sun/util/resources/provider/LocaleDataProvider target macos-aarch64 flags 8000 + diff --git a/src/jdk.compiler/share/data/symbols/symbols b/src/jdk.compiler/share/data/symbols/symbols index 34619bed887..4bc5127310f 100644 --- a/src/jdk.compiler/share/data/symbols/symbols +++ b/src/jdk.compiler/share/data/symbols/symbols @@ -29,7 +29,7 @@ #command used to generate this file: #build.tools.symbolgenerator.CreateSymbols build-description-incremental symbols include.list # -generate platforms 8:9:A:B:C:D:E:F:G:H:I:J:K:L:M:N:O:P +generate platforms 8:9:A:B:C:D:E:F:G:H:I:J:K:L:M:N:O:P:Q platform version 8 files java.activation-8.sym.txt:java.base-8.sym.txt:java.compiler-8.sym.txt:java.corba-8.sym.txt:java.datatransfer-8.sym.txt:java.desktop-8.sym.txt:java.instrument-8.sym.txt:java.logging-8.sym.txt:java.management-8.sym.txt:java.management.rmi-8.sym.txt:java.naming-8.sym.txt:java.prefs-8.sym.txt:java.rmi-8.sym.txt:java.scripting-8.sym.txt:java.security.jgss-8.sym.txt:java.security.sasl-8.sym.txt:java.sql-8.sym.txt:java.sql.rowset-8.sym.txt:java.transaction-8.sym.txt:java.xml-8.sym.txt:java.xml.bind-8.sym.txt:java.xml.crypto-8.sym.txt:java.xml.ws-8.sym.txt:java.xml.ws.annotation-8.sym.txt:jdk.httpserver-8.sym.txt:jdk.management-8.sym.txt:jdk.net-8.sym.txt:jdk.scripting.nashorn-8.sym.txt:jdk.sctp-8.sym.txt:jdk.security.auth-8.sym.txt:jdk.security.jgss-8.sym.txt platform version 9 base 8 files java.activation-9.sym.txt:java.base-9.sym.txt:java.compiler-9.sym.txt:java.corba-9.sym.txt:java.datatransfer-9.sym.txt:java.desktop-9.sym.txt:java.instrument-9.sym.txt:java.logging-9.sym.txt:java.management-9.sym.txt:java.management.rmi-9.sym.txt:java.naming-9.sym.txt:java.prefs-9.sym.txt:java.rmi-9.sym.txt:java.scripting-9.sym.txt:java.se-9.sym.txt:java.se.ee-9.sym.txt:java.security.jgss-9.sym.txt:java.security.sasl-9.sym.txt:java.smartcardio-9.sym.txt:java.sql-9.sym.txt:java.sql.rowset-9.sym.txt:java.transaction-9.sym.txt:java.xml-9.sym.txt:java.xml.bind-9.sym.txt:java.xml.crypto-9.sym.txt:java.xml.ws-9.sym.txt:java.xml.ws.annotation-9.sym.txt:jdk.accessibility-9.sym.txt:jdk.attach-9.sym.txt:jdk.charsets-9.sym.txt:jdk.compiler-9.sym.txt:jdk.crypto.cryptoki-9.sym.txt:jdk.crypto.ec-9.sym.txt:jdk.dynalink-9.sym.txt:jdk.editpad-9.sym.txt:jdk.hotspot.agent-9.sym.txt:jdk.httpserver-9.sym.txt:jdk.incubator.httpclient-9.sym.txt:jdk.jartool-9.sym.txt:jdk.javadoc-9.sym.txt:jdk.jcmd-9.sym.txt:jdk.jconsole-9.sym.txt:jdk.jdeps-9.sym.txt:jdk.jdi-9.sym.txt:jdk.jdwp.agent-9.sym.txt:jdk.jlink-9.sym.txt:jdk.jshell-9.sym.txt:jdk.jsobject-9.sym.txt:jdk.jstatd-9.sym.txt:jdk.localedata-9.sym.txt:jdk.management-9.sym.txt:jdk.management.agent-9.sym.txt:jdk.naming.dns-9.sym.txt:jdk.naming.rmi-9.sym.txt:jdk.net-9.sym.txt:jdk.pack-9.sym.txt:jdk.policytool-9.sym.txt:jdk.rmic-9.sym.txt:jdk.scripting.nashorn-9.sym.txt:jdk.sctp-9.sym.txt:jdk.security.auth-9.sym.txt:jdk.security.jgss-9.sym.txt:jdk.unsupported-9.sym.txt:jdk.xml.dom-9.sym.txt:jdk.zipfs-9.sym.txt platform version A base 9 files java.activation-A.sym.txt:java.base-A.sym.txt:java.compiler-A.sym.txt:java.corba-A.sym.txt:java.datatransfer-A.sym.txt:java.desktop-A.sym.txt:java.instrument-A.sym.txt:java.logging-A.sym.txt:java.management-A.sym.txt:java.management.rmi-A.sym.txt:java.naming-A.sym.txt:java.prefs-A.sym.txt:java.rmi-A.sym.txt:java.scripting-A.sym.txt:java.se-A.sym.txt:java.se.ee-A.sym.txt:java.security.jgss-A.sym.txt:java.security.sasl-A.sym.txt:java.smartcardio-A.sym.txt:java.sql-A.sym.txt:java.sql.rowset-A.sym.txt:java.transaction-A.sym.txt:java.xml-A.sym.txt:java.xml.bind-A.sym.txt:java.xml.crypto-A.sym.txt:java.xml.ws-A.sym.txt:java.xml.ws.annotation-A.sym.txt:jdk.accessibility-A.sym.txt:jdk.attach-A.sym.txt:jdk.charsets-A.sym.txt:jdk.compiler-A.sym.txt:jdk.crypto.cryptoki-A.sym.txt:jdk.crypto.ec-A.sym.txt:jdk.dynalink-A.sym.txt:jdk.editpad-A.sym.txt:jdk.hotspot.agent-A.sym.txt:jdk.httpserver-A.sym.txt:jdk.incubator.httpclient-A.sym.txt:jdk.jartool-A.sym.txt:jdk.javadoc-A.sym.txt:jdk.jcmd-A.sym.txt:jdk.jconsole-A.sym.txt:jdk.jdeps-A.sym.txt:jdk.jdi-A.sym.txt:jdk.jdwp.agent-A.sym.txt:jdk.jlink-A.sym.txt:jdk.jshell-A.sym.txt:jdk.jsobject-A.sym.txt:jdk.jstatd-A.sym.txt:jdk.localedata-A.sym.txt:jdk.management-A.sym.txt:jdk.management.agent-A.sym.txt:jdk.naming.dns-A.sym.txt:jdk.naming.rmi-A.sym.txt:jdk.net-A.sym.txt:jdk.pack-A.sym.txt:jdk.policytool-A.sym.txt:jdk.rmic-A.sym.txt:jdk.scripting.nashorn-A.sym.txt:jdk.sctp-A.sym.txt:jdk.security.auth-A.sym.txt:jdk.security.jgss-A.sym.txt:jdk.unsupported-A.sym.txt:jdk.xml.dom-A.sym.txt:jdk.zipfs-A.sym.txt @@ -48,3 +48,4 @@ platform version M base L files java.base-M.sym.txt:java.compiler-M.sym.txt:java platform version N base M files java.base-N.sym.txt:java.compiler-N.sym.txt:java.desktop-N.sym.txt:java.management-N.sym.txt:java.management.rmi-N.sym.txt:jdk.compiler-N.sym.txt:jdk.httpserver-N.sym.txt:jdk.incubator.foreign-N.sym.txt:jdk.javadoc-N.sym.txt:jdk.jshell-N.sym.txt:jdk.localedata-N.sym.txt:jdk.unsupported-N.sym.txt platform version O base N files java.base-O.sym.txt:java.compiler-O.sym.txt:java.datatransfer-O.sym.txt:java.desktop-O.sym.txt:java.instrument-O.sym.txt:java.logging-O.sym.txt:java.management-O.sym.txt:java.management.rmi-O.sym.txt:java.naming-O.sym.txt:java.net.http-O.sym.txt:java.prefs-O.sym.txt:java.rmi-O.sym.txt:java.scripting-O.sym.txt:java.se-O.sym.txt:java.security.jgss-O.sym.txt:java.security.sasl-O.sym.txt:java.smartcardio-O.sym.txt:java.sql-O.sym.txt:java.sql.rowset-O.sym.txt:java.transaction.xa-O.sym.txt:java.xml-O.sym.txt:java.xml.crypto-O.sym.txt:jdk.accessibility-O.sym.txt:jdk.attach-O.sym.txt:jdk.charsets-O.sym.txt:jdk.compiler-O.sym.txt:jdk.crypto.cryptoki-O.sym.txt:jdk.dynalink-O.sym.txt:jdk.editpad-O.sym.txt:jdk.hotspot.agent-O.sym.txt:jdk.httpserver-O.sym.txt:jdk.incubator.foreign-O.sym.txt:jdk.incubator.vector-O.sym.txt:jdk.jartool-O.sym.txt:jdk.javadoc-O.sym.txt:jdk.jcmd-O.sym.txt:jdk.jconsole-O.sym.txt:jdk.jdeps-O.sym.txt:jdk.jdi-O.sym.txt:jdk.jdwp.agent-O.sym.txt:jdk.jfr-O.sym.txt:jdk.jlink-O.sym.txt:jdk.jpackage-O.sym.txt:jdk.jshell-O.sym.txt:jdk.jsobject-O.sym.txt:jdk.jstatd-O.sym.txt:jdk.localedata-O.sym.txt:jdk.management-O.sym.txt:jdk.management.agent-O.sym.txt:jdk.management.jfr-O.sym.txt:jdk.naming.dns-O.sym.txt:jdk.naming.rmi-O.sym.txt:jdk.net-O.sym.txt:jdk.nio.mapmode-O.sym.txt:jdk.sctp-O.sym.txt:jdk.security.auth-O.sym.txt:jdk.security.jgss-O.sym.txt:jdk.unsupported-O.sym.txt:jdk.xml.dom-O.sym.txt:jdk.zipfs-O.sym.txt platform version P base O files java.base-P.sym.txt:java.compiler-P.sym.txt:java.desktop-P.sym.txt:java.logging-P.sym.txt:java.management-P.sym.txt:java.net.http-P.sym.txt:java.security.jgss-P.sym.txt:java.xml.crypto-P.sym.txt:jdk.attach-P.sym.txt:jdk.compiler-P.sym.txt:jdk.incubator.foreign-P.sym.txt:jdk.incubator.vector-P.sym.txt:jdk.jdi-P.sym.txt:jdk.jfr-P.sym.txt:jdk.jpackage-P.sym.txt:jdk.jshell-P.sym.txt:jdk.net-P.sym.txt:jdk.security.jgss-P.sym.txt +platform version Q base P files java.base-Q.sym.txt:java.compiler-Q.sym.txt:java.desktop-Q.sym.txt:java.management-Q.sym.txt:java.net.http-Q.sym.txt:jdk.httpserver-Q.sym.txt:jdk.incubator.vector-Q.sym.txt:jdk.jartool-Q.sym.txt:jdk.jdeps-Q.sym.txt:jdk.jfr-Q.sym.txt:jdk.jlink-Q.sym.txt:jdk.jshell-Q.sym.txt:jdk.jsobject-Q.sym.txt:jdk.localedata-Q.sym.txt diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 72a248408ac..c838cbc56e6 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -817,3 +817,4 @@ java/awt/Cursor/CursorDragTest/ListDragCursor.java 7177297 macosx-all # jdk_since_checks tools/sincechecker/modules/jdk.management.jfr/JdkManagementJfrCheckSince.java 8354921 generic-all +tools/sincechecker/modules/java.base/JavaBaseCheckSince.java 8372801 generic-all diff --git a/test/langtools/tools/javac/api/TestGetSourceVersions.java b/test/langtools/tools/javac/api/TestGetSourceVersions.java index 4df60355aad..61147bc458d 100644 --- a/test/langtools/tools/javac/api/TestGetSourceVersions.java +++ b/test/langtools/tools/javac/api/TestGetSourceVersions.java @@ -24,7 +24,7 @@ /* * @test * @bug 6395981 6458819 7025784 8028543 8028544 8193291 8193292 8193292 8205393 8245585 8245585 8245585 8286034 - * 8296150 8306585 8319414 8330183 8342982 8355748 + * 8296150 8306585 8319414 8330183 8342982 8355748 8370893 * @summary JavaCompilerTool and Tool must specify version of JLS and JVMS * @author Peter von der Ahé * @modules java.compiler @@ -37,7 +37,7 @@ * RELEASE_8 RELEASE_9 RELEASE_10 RELEASE_11 RELEASE_12 * RELEASE_13 RELEASE_14 RELEASE_15 RELEASE_16 RELEASE_17 * RELEASE_18 RELEASE_19 RELEASE_20 RELEASE_21 RELEASE_22 - * RELEASE_23 RELEASE_24 RELEASE_25 RELEASE_26 + * RELEASE_23 RELEASE_24 RELEASE_25 RELEASE_26 RELEASE_27 */ import java.util.EnumSet; diff --git a/test/langtools/tools/javac/classfiles/ClassVersionChecker.java b/test/langtools/tools/javac/classfiles/ClassVersionChecker.java index 6afa7ad9e30..8cf30373e29 100644 --- a/test/langtools/tools/javac/classfiles/ClassVersionChecker.java +++ b/test/langtools/tools/javac/classfiles/ClassVersionChecker.java @@ -24,7 +24,7 @@ /* * @test * @bug 7157626 8001112 8188870 8173382 8193290 8205619 8245586 8257453 8306586 8330184 - * 8342983 8355751 + * 8342983 8355751 8370894 * @summary Test major version for all legal combinations for -source and -target * @author sgoel * @@ -62,6 +62,7 @@ public class ClassVersionChecker { TWENTY_FOUR("24", 68), TWENTY_FIVE("25", 69), TWENTY_SIX("26", 70), + TWENTY_SEVEN("27", 71), ; // Reduce code churn when appending new constants private Version(String release, int classFileVer) { diff --git a/test/langtools/tools/javac/lib/JavacTestingAbstractProcessor.java b/test/langtools/tools/javac/lib/JavacTestingAbstractProcessor.java index e181ef8bf63..70a1e028839 100644 --- a/test/langtools/tools/javac/lib/JavacTestingAbstractProcessor.java +++ b/test/langtools/tools/javac/lib/JavacTestingAbstractProcessor.java @@ -113,7 +113,7 @@ public abstract class JavacTestingAbstractProcessor extends AbstractProcessor { * corresponding platform visitor type. */ - @SupportedSourceVersion(RELEASE_26) + @SupportedSourceVersion(RELEASE_27) @SuppressWarnings("preview") public static abstract class AbstractAnnotationValueVisitor extends AbstractAnnotationValueVisitorPreview { @@ -125,7 +125,7 @@ public abstract class JavacTestingAbstractProcessor extends AbstractProcessor { } } - @SupportedSourceVersion(RELEASE_26) + @SupportedSourceVersion(RELEASE_27) @SuppressWarnings("preview") public static abstract class AbstractElementVisitor extends AbstractElementVisitorPreview { /** @@ -136,7 +136,7 @@ public abstract class JavacTestingAbstractProcessor extends AbstractProcessor { } } - @SupportedSourceVersion(RELEASE_26) + @SupportedSourceVersion(RELEASE_27) @SuppressWarnings("preview") public static abstract class AbstractTypeVisitor extends AbstractTypeVisitorPreview { /** @@ -147,7 +147,7 @@ public abstract class JavacTestingAbstractProcessor extends AbstractProcessor { } } - @SupportedSourceVersion(RELEASE_26) + @SupportedSourceVersion(RELEASE_27) @SuppressWarnings("preview") public static class ElementKindVisitor extends ElementKindVisitorPreview { /** @@ -169,7 +169,7 @@ public abstract class JavacTestingAbstractProcessor extends AbstractProcessor { } } - @SupportedSourceVersion(RELEASE_26) + @SupportedSourceVersion(RELEASE_27) @SuppressWarnings("preview") public static class ElementScanner extends ElementScannerPreview { /** @@ -189,7 +189,7 @@ public abstract class JavacTestingAbstractProcessor extends AbstractProcessor { } } - @SupportedSourceVersion(RELEASE_26) + @SupportedSourceVersion(RELEASE_27) @SuppressWarnings("preview") public static class SimpleAnnotationValueVisitor extends SimpleAnnotationValueVisitorPreview { /** @@ -211,7 +211,7 @@ public abstract class JavacTestingAbstractProcessor extends AbstractProcessor { } } - @SupportedSourceVersion(RELEASE_26) + @SupportedSourceVersion(RELEASE_27) @SuppressWarnings("preview") public static class SimpleElementVisitor extends SimpleElementVisitorPreview { /** @@ -233,7 +233,7 @@ public abstract class JavacTestingAbstractProcessor extends AbstractProcessor { } } - @SupportedSourceVersion(RELEASE_26) + @SupportedSourceVersion(RELEASE_27) @SuppressWarnings("preview") public static class SimpleTypeVisitor extends SimpleTypeVisitorPreview { /** @@ -255,7 +255,7 @@ public abstract class JavacTestingAbstractProcessor extends AbstractProcessor { } } - @SupportedSourceVersion(RELEASE_26) + @SupportedSourceVersion(RELEASE_27) @SuppressWarnings("preview") public static class TypeKindVisitor extends TypeKindVisitorPreview { /** diff --git a/test/langtools/tools/javac/preview/classReaderTest/Client.nopreview.out b/test/langtools/tools/javac/preview/classReaderTest/Client.nopreview.out index 8c455009ae5..f46b53f80db 100644 --- a/test/langtools/tools/javac/preview/classReaderTest/Client.nopreview.out +++ b/test/langtools/tools/javac/preview/classReaderTest/Client.nopreview.out @@ -1,2 +1,2 @@ -- compiler.err.preview.feature.disabled.classfile: Bar.class, 26 +- compiler.err.preview.feature.disabled.classfile: Bar.class, 27 1 error diff --git a/test/langtools/tools/javac/preview/classReaderTest/Client.preview.out b/test/langtools/tools/javac/preview/classReaderTest/Client.preview.out index 26ff05b085a..7ae297ee2fb 100644 --- a/test/langtools/tools/javac/preview/classReaderTest/Client.preview.out +++ b/test/langtools/tools/javac/preview/classReaderTest/Client.preview.out @@ -1,4 +1,4 @@ -- compiler.warn.preview.feature.use.classfile: Bar.class, 26 +- compiler.warn.preview.feature.use.classfile: Bar.class, 27 - compiler.err.warnings.and.werror 1 error 1 warning diff --git a/test/langtools/tools/javac/versions/Versions.java b/test/langtools/tools/javac/versions/Versions.java index 43fcb0353d0..e83f7b8c308 100644 --- a/test/langtools/tools/javac/versions/Versions.java +++ b/test/langtools/tools/javac/versions/Versions.java @@ -26,7 +26,7 @@ * @bug 4981566 5028634 5094412 6304984 7025786 7025789 8001112 8028545 * 8000961 8030610 8028546 8188870 8173382 8173382 8193290 8205619 8028563 * 8245147 8245586 8257453 8286035 8306586 8320806 8306586 8319414 8330183 - * 8342982 8355748 8356108 + * 8342982 8355748 8356108 8370893 * @summary Check interpretation of -target and -source options * @modules java.compiler * jdk.compiler @@ -73,9 +73,9 @@ public class Versions { public static final Set VALID_SOURCES = Set.of("1.8", "1.9", "1.10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", - "23", "24", "25", "26"); + "23", "24", "25", "26", "27"); - public static final String LATEST_MAJOR_VERSION = "70.0"; + public static final String LATEST_MAJOR_VERSION = "71.0"; static enum SourceTarget { EIGHT(true, "52.0", "8"), @@ -97,6 +97,7 @@ public class Versions { TWENTY_FOUR(false,"68.0", "24"), TWENTY_FIVE(false,"69.0", "25"), TWENTY_SIX(false, "70.0", "26"), + TWENTY_SEVEN(false, "71.0", "27"), ; // Reduce code churn when appending new constants private final boolean dotOne; From c7aa10339aa40d37dc52e6dcec102f8dca114634 Mon Sep 17 00:00:00 2001 From: Justin Lu Date: Thu, 4 Dec 2025 18:34:51 +0000 Subject: [PATCH 178/706] 8372844: Improve usage of test/jdk/java/text/testlib/TestUtils.java locale methods Reviewed-by: naoto --- .../text/Format/DateFormat/Bug4407042.java | 27 ++-- .../text/Format/DateFormat/Bug4845901.java | 17 ++- .../text/Format/DateFormat/Bug6530336.java | 134 ++++++++---------- .../DateFormat/DateFormatRegression.java | 7 +- .../MessageFormat/MessageRegression.java | 9 +- .../Format/NumberFormat/NumberRegression.java | 7 +- .../java/util/Calendar/CalendarLimitTest.java | 9 +- .../util/Calendar/CalendarRegression.java | 52 +++---- test/jdk/java/util/Calendar/CalendarTest.java | 15 +- test/jdk/java/util/Calendar/bug4409072.java | 9 +- test/jdk/java/util/Locale/LocaleCategory.java | 18 +-- .../util/TimeZone/TimeZoneRegression.java | 13 +- 12 files changed, 136 insertions(+), 181 deletions(-) diff --git a/test/jdk/java/text/Format/DateFormat/Bug4407042.java b/test/jdk/java/text/Format/DateFormat/Bug4407042.java index 1960cb2b151..85825ff8b21 100644 --- a/test/jdk/java/text/Format/DateFormat/Bug4407042.java +++ b/test/jdk/java/text/Format/DateFormat/Bug4407042.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, 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,29 +27,31 @@ * @summary Make sure that cloned SimpleDateFormat objects work * independently in multiple threads. * @library /java/text/testlib - * @run main Bug4407042 10 + * @run junit Bug4407042 */ +import org.junit.jupiter.api.Assumptions; +import org.junit.jupiter.api.Test; + import java.io.*; import java.text.*; import java.util.*; -// Usage: java Bug4407042 [duration] public class Bug4407042 { static final String TIME_STRING = "2000/11/18 00:01:00"; static final long UTC_LONG = 974534460000L; static SimpleDateFormat masterFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); static boolean runrun = true; - static int duration = 100; + static int duration = 10; + @Test void test() { Locale locale = Locale.getDefault(); - if (!TestUtils.usesAsciiDigits(locale) - || !TestUtils.usesGregorianCalendar(locale)) { - System.out.println("Skipping this test because locale is " + locale); - return; - } + Assumptions.assumeTrue(TestUtils.usesAsciiDigits(locale), + locale + " does not use ASCII digits"); + Assumptions.assumeTrue(TestUtils.usesGregorianCalendar(locale), + locale + " does not use a Gregorian calendar"); masterFormat.setTimeZone(TimeZone.getTimeZone("America/Los_Angeles")); DateParseThread d1 = new DateParseThread(); @@ -124,11 +126,4 @@ public class Bug4407042 { } } } - - public static void main (String[] args) { - if (args.length == 1) { - duration = Math.max(10, Integer.parseInt(args[0])); - } - new Bug4407042().test(); - } } diff --git a/test/jdk/java/text/Format/DateFormat/Bug4845901.java b/test/jdk/java/text/Format/DateFormat/Bug4845901.java index 363a3518bf0..754197dbe0d 100644 --- a/test/jdk/java/text/Format/DateFormat/Bug4845901.java +++ b/test/jdk/java/text/Format/DateFormat/Bug4845901.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2025, 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,19 +28,22 @@ * the same time zone abbreviation for standard and daylight saving * time. * @library /java/text/testlib - * @run main Bug4845901 + * @run junit/othervm Bug4845901 */ +import org.junit.jupiter.api.Assumptions; +import org.junit.jupiter.api.Test; + import java.util.*; import java.text.SimpleDateFormat; public class Bug4845901 { - public static void main (String args[]) { + + @Test + void test() { Locale locale = Locale.getDefault(); - if (!TestUtils.usesGregorianCalendar(locale)) { - System.out.println("Skipping this test because locale is " + locale); - return; - } + Assumptions.assumeTrue(TestUtils.usesGregorianCalendar(locale), + locale + " does not use a Gregorian calendar"); TimeZone savedTZ = TimeZone.getDefault(); TimeZone.setDefault(TimeZone.getTimeZone("Australia/Sydney")); diff --git a/test/jdk/java/text/Format/DateFormat/Bug6530336.java b/test/jdk/java/text/Format/DateFormat/Bug6530336.java index 552343cb1ba..880e8b3ae2b 100644 --- a/test/jdk/java/text/Format/DateFormat/Bug6530336.java +++ b/test/jdk/java/text/Format/DateFormat/Bug6530336.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2025, 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,93 +25,73 @@ * @test * @bug 6530336 6537997 8008577 8174269 8333582 * @library /java/text/testlib - * @run main Bug6530336 + * @run junit/othervm Bug6530336 */ +import org.junit.jupiter.api.Assumptions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.FieldSource; + import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import java.util.Locale; import java.util.TimeZone; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; + public class Bug6530336 { - public static void main(String[] args) throws Exception { - Locale defaultLocale = Locale.getDefault(); - TimeZone defaultTimeZone = TimeZone.getDefault(); + private static final Locale[] locales = Locale.getAvailableLocales(); + private static final TimeZone[] timezones = { + TimeZone.getTimeZone("America/New_York"), + TimeZone.getTimeZone("America/Denver"), + }; + private static final TimeZone timezone_LA = TimeZone.getTimeZone("America/Los_Angeles"); + private static final String[] expected = { + "Sun Jul 15 12:00:00 PDT 2007", + "Sun Jul 15 14:00:00 PDT 2007", + }; + private static final Date[] dates = new Date[2]; - boolean err = false; - - try { - Locale locales[] = Locale.getAvailableLocales(); - TimeZone timezone_LA = TimeZone.getTimeZone("America/Los_Angeles"); - TimeZone.setDefault(timezone_LA); - - TimeZone timezones[] = { - TimeZone.getTimeZone("America/New_York"), - TimeZone.getTimeZone("America/Denver"), - }; - - String[] expected = { - "Sun Jul 15 12:00:00 PDT 2007", - "Sun Jul 15 14:00:00 PDT 2007", - }; - - Date[] dates = new Date[2]; - - for (int i = 0; i < locales.length; i++) { - Locale locale = locales[i]; - if (!TestUtils.usesGregorianCalendar(locale)) { - continue; - } - - Locale.setDefault(locale); - - for (int j = 0; j < timezones.length; j++) { - Calendar cal = Calendar.getInstance(timezones[j]); - cal.set(2007, 6, 15, 15, 0, 0); - dates[j] = cal.getTime(); - } - - SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy"); - - for (int j = 0; j < timezones.length; j++) { - sdf.setTimeZone(timezones[j]); - String date = sdf.format(dates[j]); - // CLDR localizes GMT format into for some locales. Ignore those cases - if (date.matches(".*GMT[\\s+-]\\D.*") || - date.contains("UTC") || - date.contains("TMG") || // Interlingue - date.contains("\u07dc\u07ed\u07d5\u07d6") || // N’Ko - date.contains("\ua2e7\ua0c5\ua395\ua3e6\ua12e\ua209") || // Sichuan Yi, Nuosu - date.contains("\u06af\u0631\u06cc\u0646\u06cc\u0686")) { // Central Kurdish - continue; - } - sdf.setTimeZone(timezone_LA); - String date_LA = sdf.parse(date).toString(); - - if (!expected[j].equals(date_LA)) { - System.err.println("Got wrong Pacific time (" + - date_LA + ") for (" + date + ") in " + locale + - " in " + timezones[j] + - ".\nExpected=" + expected[j]); - err = true; - } - } - } - } - catch (Exception e) { - e.printStackTrace(); - err = true; - } - finally { - Locale.setDefault(defaultLocale); - TimeZone.setDefault(defaultTimeZone); - - if (err) { - throw new RuntimeException("Failed."); - } - } + @BeforeAll + static void setup() { + TimeZone.setDefault(timezone_LA); } + @ParameterizedTest + @FieldSource("locales") + void test(Locale locale) { + Assumptions.assumeTrue(TestUtils.usesGregorianCalendar(locale), + locale + " does not use a Gregorian calendar"); + Locale.setDefault(locale); + + for (int j = 0; j < timezones.length; j++) { + Calendar cal = Calendar.getInstance(timezones[j]); + cal.set(2007, 6, 15, 15, 0, 0); + dates[j] = cal.getTime(); + } + + SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy"); + + for (int j = 0; j < timezones.length; j++) { + sdf.setTimeZone(timezones[j]); + String date = sdf.format(dates[j]); + // CLDR localizes GMT format into for some locales. Ignore those cases + if (date.matches(".*GMT[\\s+-]\\D.*") || + date.contains("UTC") || + date.contains("TMG") || // Interlingue + date.contains("ߜ߭ߕߖ") || // N’Ko + date.contains("ꋧꃅꎕꏦꄮꈉ") || // Sichuan Yi, Nuosu + date.contains("گرینیچ")) { // Central Kurdish + continue; + } + sdf.setTimeZone(timezone_LA); + String date_LA = assertDoesNotThrow(() -> sdf.parse(date).toString()); + assertEquals(expected[j], date_LA, + "Got wrong Pacific time (%s) for (%s) in %s in %s.".formatted(date_LA, date, locale, timezones[j])); + } + } } diff --git a/test/jdk/java/text/Format/DateFormat/DateFormatRegression.java b/test/jdk/java/text/Format/DateFormat/DateFormatRegression.java index dbd12e66f60..2e3fed17ce5 100644 --- a/test/jdk/java/text/Format/DateFormat/DateFormatRegression.java +++ b/test/jdk/java/text/Format/DateFormat/DateFormatRegression.java @@ -25,6 +25,7 @@ import java.text.*; import java.util.*; import java.io.*; +import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.fail; @@ -170,10 +171,8 @@ public class DateFormatRegression { @Test public void Test4059917() { Locale locale = Locale.getDefault(); - if (!TestUtils.usesAsciiDigits(locale)) { - System.out.println("Skipping this test because locale is " + locale); - return; - } + Assumptions.assumeTrue(TestUtils.usesAsciiDigits(locale), + locale + " does not use ASCII digits"); SimpleDateFormat fmt; String myDate; diff --git a/test/jdk/java/text/Format/MessageFormat/MessageRegression.java b/test/jdk/java/text/Format/MessageFormat/MessageRegression.java index e10e4899202..31aa5189ba2 100644 --- a/test/jdk/java/text/Format/MessageFormat/MessageRegression.java +++ b/test/jdk/java/text/Format/MessageFormat/MessageRegression.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, 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 @@ -53,6 +53,7 @@ import java.io.ObjectOutputStream; import java.io.ObjectInputStream; import java.io.Serializable; +import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.fail; @@ -126,10 +127,8 @@ public class MessageRegression { @Test public void Test4031438() { Locale locale = Locale.getDefault(); - if (!TestUtils.usesAsciiDigits(locale)) { - System.out.println("Skipping this test because locale is " + locale); - return; - } + Assumptions.assumeTrue(TestUtils.usesAsciiDigits(locale), + locale + " does not use ASCII digits"); String pattern1 = "Impossible {1} has occurred -- status code is {0} and message is {2}."; String pattern2 = "Double '' Quotes {0} test and quoted '{1}' test plus 'other {2} stuff'."; diff --git a/test/jdk/java/text/Format/NumberFormat/NumberRegression.java b/test/jdk/java/text/Format/NumberFormat/NumberRegression.java index a0a096e6782..90f60151197 100644 --- a/test/jdk/java/text/Format/NumberFormat/NumberRegression.java +++ b/test/jdk/java/text/Format/NumberFormat/NumberRegression.java @@ -58,6 +58,7 @@ import java.math.BigDecimal; import java.io.*; import java.math.BigInteger; +import org.junit.jupiter.api.Assumptions; import sun.util.resources.LocaleData; import org.junit.jupiter.api.Test; @@ -109,10 +110,8 @@ public class NumberRegression { @Test public void Test4088161 (){ Locale locale = Locale.getDefault(); - if (!TestUtils.usesAsciiDigits(locale)) { - System.out.println("Skipping this test because locale is " + locale); - return; - } + Assumptions.assumeTrue(TestUtils.usesAsciiDigits(locale), + locale + " does not use ASCII digits"); DecimalFormat df = new DecimalFormat(); double d = 100; diff --git a/test/jdk/java/util/Calendar/CalendarLimitTest.java b/test/jdk/java/util/Calendar/CalendarLimitTest.java index e8a92f180ec..552aa5f9866 100644 --- a/test/jdk/java/util/Calendar/CalendarLimitTest.java +++ b/test/jdk/java/util/Calendar/CalendarLimitTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, 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,6 +32,7 @@ import java.util.*; import java.text.*; +import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.fail; @@ -130,10 +131,8 @@ public class CalendarLimitTest public void TestCalendarLimit() { Locale locale = Locale.getDefault(); - if (!TestUtils.usesGregorianCalendar(locale)) { - System.out.println("Skipping this test because locale is " + locale); - return; - } + Assumptions.assumeTrue(TestUtils.usesGregorianCalendar(locale), + locale + " does not use a Gregorian calendar"); ORIGIN = julianDayToMillis(JAN_1_1_JULIAN_DAY); Calendar cal = Calendar.getInstance(); diff --git a/test/jdk/java/util/Calendar/CalendarRegression.java b/test/jdk/java/util/Calendar/CalendarRegression.java index 7b0f2025005..6e5148c0c20 100644 --- a/test/jdk/java/util/Calendar/CalendarRegression.java +++ b/test/jdk/java/util/Calendar/CalendarRegression.java @@ -55,6 +55,7 @@ import java.util.function.Predicate; import static java.util.Calendar.*; +import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.fail; @@ -575,10 +576,8 @@ public class CalendarRegression { @Test public void Test4100311() { Locale locale = Locale.getDefault(); - if (!TestUtils.usesGregorianCalendar(locale)) { - System.out.println("Skipping this test because locale is " + locale); - return; - } + Assumptions.assumeTrue(TestUtils.usesGregorianCalendar(locale), + locale + " does not use a Gregorian calendar"); GregorianCalendar cal = (GregorianCalendar) Calendar.getInstance(); cal.set(YEAR, 1997); @@ -593,10 +592,8 @@ public class CalendarRegression { @Test public void Test4103271() { Locale locale = Locale.getDefault(); - if (!TestUtils.usesGregorianCalendar(locale)) { - System.out.println("Skipping this test because locale is " + locale); - return; - } + Assumptions.assumeTrue(TestUtils.usesGregorianCalendar(locale), + locale + " does not use a Gregorian calendar"); SimpleDateFormat sdf = new SimpleDateFormat(); int numYears = 40, startYear = 1997, numDays = 15; @@ -833,10 +830,8 @@ public class CalendarRegression { @Test public void Test4114578() { Locale locale = Locale.getDefault(); - if (!TestUtils.usesGregorianCalendar(locale)) { - System.out.println("Skipping this test because locale is " + locale); - return; - } + Assumptions.assumeTrue(TestUtils.usesGregorianCalendar(locale), + locale + " does not use a Gregorian calendar"); int ONE_HOUR = 60 * 60 * 1000; TimeZone saveZone = TimeZone.getDefault(); @@ -921,10 +916,8 @@ public class CalendarRegression { @Test public void Test4125881() { Locale locale = Locale.getDefault(); - if (!TestUtils.usesGregorianCalendar(locale)) { - System.out.println("Skipping this test because locale is " + locale); - return; - } + Assumptions.assumeTrue(TestUtils.usesGregorianCalendar(locale), + locale + " does not use a Gregorian calendar"); GregorianCalendar cal = (GregorianCalendar) Calendar.getInstance(); DateFormat fmt = new SimpleDateFormat("MMMM d, yyyy G"); @@ -947,10 +940,8 @@ public class CalendarRegression { @Test public void Test4125892() { Locale locale = Locale.getDefault(); - if (!TestUtils.usesGregorianCalendar(locale)) { - System.out.println("Skipping this test because locale is " + locale); - return; - } + Assumptions.assumeTrue(TestUtils.usesGregorianCalendar(locale), + locale + " does not use a Gregorian calendar"); GregorianCalendar cal = (GregorianCalendar) Calendar.getInstance(); DateFormat fmt = new SimpleDateFormat("MMMM d, yyyy G"); @@ -1373,10 +1364,8 @@ public class CalendarRegression { @Test public void Test4173516() { Locale locale = Locale.getDefault(); - if (!TestUtils.usesGregorianCalendar(locale)) { - System.out.println("Skipping this test because locale is " + locale); - return; - } + Assumptions.assumeTrue(TestUtils.usesGregorianCalendar(locale), + locale + " does not use a Gregorian calendar"); int[][] fieldsList = { {1997, FEBRUARY, 1, 10, 45, 15, 900}, @@ -1852,11 +1841,10 @@ public class CalendarRegression { @Test public void Test4685354() { Locale locale = Locale.getDefault(); - if (!TestUtils.usesAsciiDigits(locale) - || !TestUtils.usesGregorianCalendar(locale)) { - System.out.println("Skipping this test because locale is " + locale); - return; - } + Assumptions.assumeTrue(TestUtils.usesAsciiDigits(locale), + locale + " does not use ASCII digits"); + Assumptions.assumeTrue(TestUtils.usesGregorianCalendar(locale), + locale + " does not use a Gregorian calendar"); Calendar calendar = Calendar.getInstance(Locale.US); DateFormat df = new SimpleDateFormat("yyyy/MM/dd", Locale.US); @@ -1961,10 +1949,8 @@ public class CalendarRegression { @Test public void Test4655637() { Locale locale = Locale.getDefault(); - if (!TestUtils.usesGregorianCalendar(locale)) { - System.out.println("Skipping this test because locale is " + locale); - return; - } + Assumptions.assumeTrue(TestUtils.usesGregorianCalendar(locale), + locale + " does not use a Gregorian calendar"); Calendar cal = Calendar.getInstance(); cal.setTime(new Date(1029814211523L)); diff --git a/test/jdk/java/util/Calendar/CalendarTest.java b/test/jdk/java/util/Calendar/CalendarTest.java index 5092c6adec0..0b50b07179d 100644 --- a/test/jdk/java/util/Calendar/CalendarTest.java +++ b/test/jdk/java/util/Calendar/CalendarTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, 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,6 +48,7 @@ import java.util.TimeZone; import static java.util.Calendar.*; +import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.fail; @@ -223,10 +224,8 @@ public class CalendarTest { @Test public void TestGenericAPI() { Locale locale = Locale.getDefault(); - if (!TestUtils.usesGregorianCalendar(locale)) { - System.out.println("Skipping this test because locale is " + locale); - return; - } + Assumptions.assumeTrue(TestUtils.usesGregorianCalendar(locale), + locale + " does not use a Gregorian calendar"); String str; Date when = new Date(90, APRIL, 15); @@ -625,10 +624,8 @@ public class CalendarTest { @Test public void TestGMTvsLocal4064654() { Locale locale = Locale.getDefault(); - if (!TestUtils.usesGregorianCalendar(locale)) { - System.out.println("Skipping this test because locale is " + locale); - return; - } + Assumptions.assumeTrue(TestUtils.usesGregorianCalendar(locale), + locale + " does not use a Gregorian calendar"); // Sample output 1: // % /usr/local/java/jdk1.1.3/solaris/bin/java test 1997 1 1 12 0 0 diff --git a/test/jdk/java/util/Calendar/bug4409072.java b/test/jdk/java/util/Calendar/bug4409072.java index 617550fe1aa..132934daa98 100644 --- a/test/jdk/java/util/Calendar/bug4409072.java +++ b/test/jdk/java/util/Calendar/bug4409072.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, 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,6 +32,7 @@ import java.util.*; import static java.util.Calendar.*; +import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.fail; @@ -44,10 +45,8 @@ public class bug4409072 { @Test public void Test4409072() { Locale locale = Locale.getDefault(); - if (!TestUtils.usesGregorianCalendar(locale)) { - System.out.println("Skipping this test because locale is " + locale); - return; - } + Assumptions.assumeTrue(TestUtils.usesGregorianCalendar(locale), + locale + " does not use a Gregorian calendar"); Locale savedLocale = Locale.getDefault(); TimeZone savedTZ = TimeZone.getDefault(); diff --git a/test/jdk/java/util/Locale/LocaleCategory.java b/test/jdk/java/util/Locale/LocaleCategory.java index ed63203916a..ec4277d43c0 100644 --- a/test/jdk/java/util/Locale/LocaleCategory.java +++ b/test/jdk/java/util/Locale/LocaleCategory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2025, 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,14 +29,17 @@ * @library /java/text/testlib * @build TestUtils LocaleCategory * @comment test user.xxx.display user.xxx.format properties - * @run main/othervm -Duser.language.display=ja + * @run junit/othervm -Duser.language.display=ja * -Duser.language.format=zh LocaleCategory * @comment test user.xxx properties overriding user.xxx.display/format - * @run main/othervm -Duser.language=en + * @run junit/othervm -Duser.language=en * -Duser.language.display=ja * -Duser.language.format=zh LocaleCategory */ +import org.junit.jupiter.api.Assumptions; +import org.junit.jupiter.api.Test; + import java.util.Locale; public class LocaleCategory { @@ -44,12 +47,11 @@ public class LocaleCategory { private static Locale disp = null; private static Locale fmt = null; - public static void main(String[] args) { + @Test + void test() { Locale reservedLocale = Locale.getDefault(); - if (TestUtils.hasSpecialVariant(reservedLocale)) { - System.out.println("Skipping this test because locale is " + reservedLocale); - return; - } + Assumptions.assumeFalse(TestUtils.hasSpecialVariant(reservedLocale), + reservedLocale + " has special variant"); try { Locale.Builder builder = new Locale.Builder(); diff --git a/test/jdk/java/util/TimeZone/TimeZoneRegression.java b/test/jdk/java/util/TimeZone/TimeZoneRegression.java index 241afd3f7cf..c1b1b98369e 100644 --- a/test/jdk/java/util/TimeZone/TimeZoneRegression.java +++ b/test/jdk/java/util/TimeZone/TimeZoneRegression.java @@ -34,6 +34,7 @@ import java.util.*; import java.io.*; import java.text.*; +import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.fail; @@ -164,10 +165,8 @@ public class TimeZoneRegression { @Test public void Test4109314() { Locale locale = Locale.getDefault(); - if (!TestUtils.usesGregorianCalendar(locale)) { - System.out.println("Skipping this test because locale is " + locale); - return; - } + Assumptions.assumeTrue(TestUtils.usesGregorianCalendar(locale), + locale + " does not use a Gregorian calendar"); // test both SimpleTimeZone and ZoneInfo objects. // @since 1.4 @@ -292,10 +291,8 @@ public class TimeZoneRegression { @Test public void Test4126678() { Locale locale = Locale.getDefault(); - if (!TestUtils.usesGregorianCalendar(locale)) { - System.out.println("Skipping this test because locale is " + locale); - return; - } + Assumptions.assumeTrue(TestUtils.usesGregorianCalendar(locale), + locale + " does not use a Gregorian calendar"); // Note: this test depends on the PST time zone. TimeZone initialZone = TimeZone.getDefault(); From b19163b107584118056073dc24a960ca04ca14e4 Mon Sep 17 00:00:00 2001 From: Matthew Donovan Date: Thu, 4 Dec 2025 18:38:57 +0000 Subject: [PATCH 179/706] 8356544: Implement additional tests for ciphersuites disabled with wildcards Reviewed-by: rhalade --- .../DisabledCipherSuitesNotNegotiated.java | 158 ++++++++++++++++++ 1 file changed, 158 insertions(+) create mode 100644 test/jdk/sun/security/ssl/CipherSuite/DisabledCipherSuitesNotNegotiated.java diff --git a/test/jdk/sun/security/ssl/CipherSuite/DisabledCipherSuitesNotNegotiated.java b/test/jdk/sun/security/ssl/CipherSuite/DisabledCipherSuitesNotNegotiated.java new file mode 100644 index 00000000000..229ab03b568 --- /dev/null +++ b/test/jdk/sun/security/ssl/CipherSuite/DisabledCipherSuitesNotNegotiated.java @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2025, 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 8341964 + * @library /test/lib + * @run main/othervm DisabledCipherSuitesNotNegotiated client + * @run main/othervm DisabledCipherSuitesNotNegotiated server + */ + +import java.net.InetAddress; +import java.nio.charset.StandardCharsets; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +import jdk.test.lib.security.SecurityUtils; +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.process.OutputAnalyzer; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLServerSocket; +import javax.net.ssl.SSLServerSocketFactory; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.SSLHandshakeException; + +public class DisabledCipherSuitesNotNegotiated { + private static final String TLS_PROTOCOL = "TLSv1.2"; + private static volatile int serverPort = 0; + private static volatile Exception serverException = null; + + private static final CountDownLatch waitForServer = new CountDownLatch(1); + private static final int WAIT_FOR_SERVER_SECS = 5; + + private static final String DISABLED_CIPHERSUITE = "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"; + private static final String DISABLED_CIPHER_WILDCARD = "TLS_ECDH*WITH_AES_256_GCM_*"; + + private static void runServer(boolean disabledInClient) throws Exception { + SSLContext ctx = SSLContext.getInstance(TLS_PROTOCOL); + ctx.init(null, null, null); + SSLServerSocketFactory factory = ctx.getServerSocketFactory(); + try(SSLServerSocket serverSocket = (SSLServerSocket)factory + .createServerSocket(0, -1, InetAddress.getLoopbackAddress())) { + serverPort = serverSocket.getLocalPort(); + waitForServer.countDown(); + + if (disabledInClient) { + // set cipher suite to disabled ciphersuite + serverSocket.setEnabledCipherSuites(new String[]{DISABLED_CIPHERSUITE}); + } + + try(SSLSocket clientSocket = (SSLSocket) serverSocket.accept()) { + try { + clientSocket.getInputStream().readAllBytes(); + throw new Exception("SERVER: The expected handshake exception was not thrown."); + } catch (SSLHandshakeException exc) { + System.out.println("Server caught expected SSLHandshakeException"); + exc.printStackTrace(System.out); + } + } + } + } + + private static void runClient(boolean disableInClient, int portNumber) throws Exception { + SSLContext ctx = SSLContext.getInstance(TLS_PROTOCOL); + ctx.init(null, null, null); + SSLSocketFactory factory = ctx.getSocketFactory(); + try(SSLSocket socket = (SSLSocket)factory.createSocket("localhost", portNumber)) { + if (!disableInClient) { + socket.setEnabledCipherSuites(new String[]{DISABLED_CIPHERSUITE}); + } + + try { + socket.getOutputStream().write("hello".getBytes(StandardCharsets.UTF_8)); + throw new Exception("CLIENT: The expected handshake exception was not thrown."); + } catch (SSLHandshakeException exc) { + System.out.println("Client caught expected SSLHandshakeException"); + } + } + } + + public static void main(String [] args) throws Exception { + if (args.length == 1) { + // run server-side + final boolean disabledInClient = args[0].equals("client"); + if (!disabledInClient) { + SecurityUtils.addToDisabledTlsAlgs(DISABLED_CIPHER_WILDCARD); + } + try(ExecutorService executorService = Executors.newSingleThreadExecutor()) { + executorService.submit(() -> { + try { + runServer(disabledInClient); + } catch (Exception exc) { + System.out.println("Server Exception:"); + exc.printStackTrace(System.out); + serverException = exc; + throw new RuntimeException(exc); + } + }); + + if (!waitForServer.await(WAIT_FOR_SERVER_SECS, TimeUnit.SECONDS)) { + throw new Exception("Server did not start within " + + WAIT_FOR_SERVER_SECS + " seconds."); + } + + System.out.printf("Server listening on port %d.%nStarting client process...", + serverPort); + + OutputAnalyzer oa = ProcessTools.executeProcess( + ProcessTools.createTestJavaProcessBuilder("DisabledCipherSuitesNotNegotiated", + "" + disabledInClient, "" + serverPort)); + oa.shouldHaveExitValue(0); + System.out.println("Client output:"); + System.out.println(oa.getOutput()); + if (serverException != null) { + throw new Exception ("Server-side threw an unexpected exception: " + + serverException); + } + } + + } else if (args.length == 2) { + // run client-side + boolean disabledInClient = Boolean.parseBoolean(args[0]); + if (disabledInClient) { + SecurityUtils.addToDisabledTlsAlgs(DISABLED_CIPHER_WILDCARD); + } + runClient(Boolean.parseBoolean(args[0]), Integer.parseInt(args[1])); + + } else { + throw new Exception( + "DisabledCipherSuitesNotNegotiated called with invalid arguments"); + } + } + +} From ef7532e7e625628d6181c65116804ebb65f18061 Mon Sep 17 00:00:00 2001 From: Mikhail Yankelevich Date: Thu, 4 Dec 2025 18:41:12 +0000 Subject: [PATCH 180/706] 8367994: test/jdk/sun/security/pkcs11/Signature/ tests pass when they should skip Reviewed-by: rhalade --- .../pkcs11/Signature/InitAgainPSS.java | 17 +++-- .../Signature/KeyAndParamCheckForPSS.java | 36 ++++++--- .../pkcs11/Signature/SigInteropPSS.java | 18 +++-- .../pkcs11/Signature/SigInteropPSS2.java | 19 +++-- .../pkcs11/Signature/SignatureTestPSS.java | 76 ++++++++++++++----- .../pkcs11/Signature/SignatureTestPSS2.java | 47 +++++++++--- .../security/pkcs11/Signature/TestDSA.java | 7 +- 7 files changed, 160 insertions(+), 60 deletions(-) diff --git a/test/jdk/sun/security/pkcs11/Signature/InitAgainPSS.java b/test/jdk/sun/security/pkcs11/Signature/InitAgainPSS.java index a2fa7294977..1acf6c250ef 100644 --- a/test/jdk/sun/security/pkcs11/Signature/InitAgainPSS.java +++ b/test/jdk/sun/security/pkcs11/Signature/InitAgainPSS.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, 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 @@ -20,8 +20,15 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -import java.security.*; -import java.security.spec.*; +import jtreg.SkippedException; + +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; +import java.security.Provider; +import java.security.Signature; +import java.security.spec.MGF1ParameterSpec; +import java.security.spec.PSSParameterSpec; /** * @test @@ -46,9 +53,7 @@ public class InitAgainPSS extends PKCS11Test { try { s1 = Signature.getInstance(sigAlg, p); } catch (NoSuchAlgorithmException e) { - System.out.println("Skip testing " + sigAlg + - " due to no support"); - return; + throw new SkippedException("No support " + sigAlg); } byte[] msg = "hello".getBytes(); diff --git a/test/jdk/sun/security/pkcs11/Signature/KeyAndParamCheckForPSS.java b/test/jdk/sun/security/pkcs11/Signature/KeyAndParamCheckForPSS.java index adf7a08908e..45e26ec3930 100644 --- a/test/jdk/sun/security/pkcs11/Signature/KeyAndParamCheckForPSS.java +++ b/test/jdk/sun/security/pkcs11/Signature/KeyAndParamCheckForPSS.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, 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 @@ -20,9 +20,18 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -import java.security.*; -import java.security.interfaces.*; -import java.security.spec.*; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.KeyPair; +import java.security.PrivateKey; +import java.security.Provider; +import java.security.PublicKey; +import java.security.Signature; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.MGF1ParameterSpec; +import java.security.spec.PSSParameterSpec; +import java.util.ArrayList; +import java.util.List; import jtreg.SkippedException; @@ -43,7 +52,7 @@ public class KeyAndParamCheckForPSS extends PKCS11Test { main(new KeyAndParamCheckForPSS(), args); } - private static boolean skipTest = true; + private static final List skippedAlgs = new ArrayList<>(); @Override public void main(Provider p) throws Exception { @@ -73,8 +82,8 @@ public class KeyAndParamCheckForPSS extends PKCS11Test { runTest(p, 1040, "SHA3-512", "SHA3-384"); runTest(p, 1040, "SHA3-512", "SHA3-512"); - if (skipTest) { - throw new SkippedException("Test Skipped"); + if (!skippedAlgs.isEmpty()) { + throw new SkippedException("Tests Skipped: " + skippedAlgs); } } @@ -84,7 +93,17 @@ public class KeyAndParamCheckForPSS extends PKCS11Test { System.out.println("Testing " + hashAlg + " and MGF1" + mgfHashAlg); PSSUtil.AlgoSupport s = PSSUtil.isHashSupported(p, hashAlg, mgfHashAlg); if (s == PSSUtil.AlgoSupport.NO) { - System.out.println("=> Skip; no support"); + System.out.printf("=> Skip; no support keysize: %d, hash alg: %s, mgf Hash Alg: %s%n", + keySize, + hashAlg, + mgfHashAlg); + skippedAlgs.add( + String.format( + "[keysize: %s, hash alg: %s, mgf Hash Alg: %s]", + keySize, + hashAlg, + mgfHashAlg) + ); return; } @@ -108,7 +127,6 @@ public class KeyAndParamCheckForPSS extends PKCS11Test { sig.setParameter(paramsGood); sig.initSign(priv); // algorithm support confirmed - skipTest = false; } catch (Exception ex) { if (s == PSSUtil.AlgoSupport.MAYBE) { // confirmed to be unsupported; skip the rest of the test diff --git a/test/jdk/sun/security/pkcs11/Signature/SigInteropPSS.java b/test/jdk/sun/security/pkcs11/Signature/SigInteropPSS.java index d5b22400bff..c9efa8fdf76 100644 --- a/test/jdk/sun/security/pkcs11/Signature/SigInteropPSS.java +++ b/test/jdk/sun/security/pkcs11/Signature/SigInteropPSS.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, 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 @@ -21,9 +21,15 @@ * questions. */ -import java.security.*; -import java.security.spec.*; -import java.security.interfaces.*; +import jtreg.SkippedException; + +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; +import java.security.Provider; +import java.security.Signature; +import java.security.spec.MGF1ParameterSpec; +import java.security.spec.PSSParameterSpec; /* * @test @@ -53,9 +59,7 @@ public class SigInteropPSS extends PKCS11Test { try { sigPkcs11 = Signature.getInstance("RSASSA-PSS", p); } catch (NoSuchAlgorithmException e) { - System.out.println("Skip testing RSASSA-PSS" + - " due to no support"); - return; + throw new SkippedException("No support for RSASSA-PSS"); } Signature sigSunRsaSign = diff --git a/test/jdk/sun/security/pkcs11/Signature/SigInteropPSS2.java b/test/jdk/sun/security/pkcs11/Signature/SigInteropPSS2.java index dfe56167848..ca0368841c5 100644 --- a/test/jdk/sun/security/pkcs11/Signature/SigInteropPSS2.java +++ b/test/jdk/sun/security/pkcs11/Signature/SigInteropPSS2.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, 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 @@ -21,9 +21,16 @@ * questions. */ -import java.security.*; -import java.security.spec.*; -import java.security.interfaces.*; +import jtreg.SkippedException; + +import java.security.AlgorithmParameters; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; +import java.security.Provider; +import java.security.Security; +import java.security.Signature; +import java.security.spec.PSSParameterSpec; /* * @test @@ -67,9 +74,7 @@ public class SigInteropPSS2 extends PKCS11Test { try { sigPkcs11 = Signature.getInstance(digest + "withRSASSA-PSS", p); } catch (NoSuchAlgorithmException e) { - System.out.println("Skip testing " + digest + "withRSASSA-PSS" + - " due to no support"); - continue; + throw new SkippedException("No support for " + digest + "withRSASSA-PSS"); } runTest(sigPkcs11, sigSunRsaSign, kp); diff --git a/test/jdk/sun/security/pkcs11/Signature/SignatureTestPSS.java b/test/jdk/sun/security/pkcs11/Signature/SignatureTestPSS.java index c87554a51b1..778a7758562 100644 --- a/test/jdk/sun/security/pkcs11/Signature/SignatureTestPSS.java +++ b/test/jdk/sun/security/pkcs11/Signature/SignatureTestPSS.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, 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 @@ -20,29 +20,55 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -import java.security.*; -import java.security.interfaces.*; -import java.security.spec.*; -import java.util.stream.IntStream; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.KeyPair; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.Provider; +import java.security.PublicKey; +import java.security.Signature; +import java.security.SignatureException; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.MGF1ParameterSpec; +import java.security.spec.PSSParameterSpec; +import java.util.ArrayList; +import java.util.List; + import jtreg.SkippedException; /** - * @test + * @test id=sha * @bug 8080462 8226651 8242332 * @summary Generate a RSASSA-PSS signature and verify it using PKCS11 provider * @library /test/lib .. * @modules jdk.crypto.cryptoki * @run main SignatureTestPSS */ + +/** + * @test id=sha3 + * @bug 8080462 8226651 8242332 + * @summary Generate a RSASSA-PSS signature and verify it using PKCS11 provider + * @library /test/lib .. + * @modules jdk.crypto.cryptoki + * @run main SignatureTestPSS sha3 + */ public class SignatureTestPSS extends PKCS11Test { private static final String SIGALG = "RSASSA-PSS"; private static final int[] KEYSIZES = { 2048, 3072 }; - private static final String[] DIGESTS = { + + private static String[] DIGESTS = null; + + private static final String[] SHA_DIGESTS = { "SHA-224", "SHA-256", "SHA-384" , "SHA-512", - "SHA3-224", "SHA3-256", "SHA3-384" , "SHA3-512", }; + private static final String[] SHA3_DIGESTS = { + "SHA3-224", "SHA3-256", "SHA3-384" , "SHA3-512" + }; + private static final byte[] DATA = generateData(100); /** @@ -55,9 +81,12 @@ public class SignatureTestPSS extends PKCS11Test { */ private static final int UPDATE_TIMES_HUNDRED = 100; - private static boolean skipTest = true; + private static final List skippedAlgs = new ArrayList<>(); public static void main(String[] args) throws Exception { + DIGESTS = (args.length > 0 && "sha3".equals(args[0])) ? + SHA3_DIGESTS : SHA_DIGESTS; + main(new SignatureTestPSS(), args); } @@ -80,6 +109,8 @@ public class SignatureTestPSS extends PKCS11Test { PSSUtil.isHashSupported(p, hash, mgfHash); if (s == PSSUtil.AlgoSupport.NO) { System.out.println(" => Skip; no support"); + skippedAlgs.add("[Hash = " + hash + + ", MGF1 Hash = " + mgfHash + "]"); continue; } checkSignature(p, DATA, pubKey, privKey, hash, mgfHash, s); @@ -87,17 +118,15 @@ public class SignatureTestPSS extends PKCS11Test { }; } - // start testing below - if (skipTest) { - throw new SkippedException("Test Skipped"); + if (!skippedAlgs.isEmpty()) { + throw new SkippedException("Test Skipped :" + skippedAlgs); } } private static void checkSignature(Provider p, byte[] data, PublicKey pub, PrivateKey priv, String hash, String mgfHash, PSSUtil.AlgoSupport s) throws NoSuchAlgorithmException, InvalidKeyException, - SignatureException, NoSuchProviderException, - InvalidAlgorithmParameterException { + SignatureException { // only test RSASSA-PSS signature against the supplied hash/mgfHash // if they are supported; otherwise PKCS11 library will throw @@ -112,14 +141,27 @@ public class SignatureTestPSS extends PKCS11Test { } catch (InvalidAlgorithmParameterException iape) { if (s == PSSUtil.AlgoSupport.MAYBE) { // confirmed to be unsupported; skip the rest of the test - System.out.println(" => Skip; no PSS support"); + System.out.printf(" => Skip; no PSS support public key: %s, private key: %s, " + + "hash: %s, mgf hash: %s, Algo Support: %s%n", + pub, + priv, + hash, + mgfHash, + s); + skippedAlgs.add(String.format( + "[public key: %s, private key: %s, " + + "hash: %s, mgf hash: %s, Algo Support: %s]", + pub, + priv, + hash, + mgfHash, + s) + ); return; } else { throw new RuntimeException("Unexpected Exception", iape); } } - // start testing below - skipTest = false; for (int i = 0; i < UPDATE_TIMES_HUNDRED; i++) { sig.update(data); diff --git a/test/jdk/sun/security/pkcs11/Signature/SignatureTestPSS2.java b/test/jdk/sun/security/pkcs11/Signature/SignatureTestPSS2.java index 516b17972e5..ac6c13523a2 100644 --- a/test/jdk/sun/security/pkcs11/Signature/SignatureTestPSS2.java +++ b/test/jdk/sun/security/pkcs11/Signature/SignatureTestPSS2.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, 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 @@ -20,13 +20,23 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -import java.security.*; -import java.security.interfaces.*; -import java.security.spec.*; +import jtreg.SkippedException; + +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.PrivateKey; +import java.security.Provider; +import java.security.PublicKey; +import java.security.Signature; +import java.security.SignatureException; import java.util.stream.IntStream; /** - * @test + * @test id=sha * @bug 8244154 8242332 * @summary Generate a withRSASSA-PSS signature and verify it using * PKCS11 provider @@ -34,13 +44,28 @@ import java.util.stream.IntStream; * @modules jdk.crypto.cryptoki * @run main SignatureTestPSS2 */ + +/** + * @test id=sha3 + * @bug 8244154 8242332 + * @summary Generate a withRSASSA-PSS signature and verify it using + * PKCS11 provider + * @library /test/lib .. + * @modules jdk.crypto.cryptoki + * @run main SignatureTestPSS2 sha3 + */ public class SignatureTestPSS2 extends PKCS11Test { // PKCS11 does not support RSASSA-PSS keys yet private static final String KEYALG = "RSA"; - private static final String[] SIGALGS = { + + private static String[] SIGALGS = null; + + private static final String[] SHA_SIGALGS = { "SHA224withRSASSA-PSS", "SHA256withRSASSA-PSS", - "SHA384withRSASSA-PSS", "SHA512withRSASSA-PSS", + "SHA384withRSASSA-PSS", "SHA512withRSASSA-PSS" + }; + private static final String[] SHA3_SIGALGS = { "SHA3-224withRSASSA-PSS", "SHA3-256withRSASSA-PSS", "SHA3-384withRSASSA-PSS", "SHA3-512withRSASSA-PSS" }; @@ -53,6 +78,8 @@ public class SignatureTestPSS2 extends PKCS11Test { private static final int UPDATE_TIMES = 2; public static void main(String[] args) throws Exception { + SIGALGS = (args.length > 0 && "sha3".equals(args[0])) ? SHA3_SIGALGS : SHA_SIGALGS; + main(new SignatureTestPSS2(), args); } @@ -63,9 +90,7 @@ public class SignatureTestPSS2 extends PKCS11Test { try { sig = Signature.getInstance(sa, p); } catch (NoSuchAlgorithmException e) { - System.out.println("Skip testing " + sa + - " due to no support"); - return; + throw new SkippedException("No support for " + sa); } for (int i : KEYSIZES) { runTest(sig, i); @@ -94,7 +119,7 @@ public class SignatureTestPSS2 extends PKCS11Test { SignatureException | NoSuchProviderException ex) { throw new RuntimeException(ex); } catch (InvalidAlgorithmParameterException ex2) { - System.out.println("Skip test due to " + ex2); + throw new SkippedException(ex2.toString()); } } diff --git a/test/jdk/sun/security/pkcs11/Signature/TestDSA.java b/test/jdk/sun/security/pkcs11/Signature/TestDSA.java index e7b937d6190..0a086bd2ed0 100644 --- a/test/jdk/sun/security/pkcs11/Signature/TestDSA.java +++ b/test/jdk/sun/security/pkcs11/Signature/TestDSA.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, 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,6 +32,8 @@ * @run main/othervm TestDSA */ +import jtreg.SkippedException; + import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.StringReader; @@ -122,8 +124,7 @@ public class TestDSA extends PKCS11Test { System.out.println("Testing provider " + provider + "..."); if (provider.getService("Signature", "SHA1withDSA") == null) { - System.out.println("DSA not supported, skipping"); - return; + throw new SkippedException("DSA not supported"); } KeyFactory kf = KeyFactory.getInstance("DSA", provider); From 8e653d394e45180e16714124ed6584f912eb5cba Mon Sep 17 00:00:00 2001 From: Phil Race Date: Thu, 4 Dec 2025 20:17:02 +0000 Subject: [PATCH 181/706] 8373099: Problem list intermittently failing test sun/awt/image/bug8038000.java Reviewed-by: dholmes --- test/jdk/ProblemList.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index c838cbc56e6..814fd2caae9 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -500,6 +500,7 @@ java/awt/GraphicsDevice/DisplayModes/UnknownRefrshRateTest.java 8286436 macosx-a java/awt/image/multiresolution/MultiresolutionIconTest.java 8291979 linux-x64,windows-all java/awt/event/SequencedEvent/MultipleContextsFunctionalTest.java 8305061 macosx-x64 sun/java2d/DirectX/OnScreenRenderingResizeTest/OnScreenRenderingResizeTest.java 8301177 linux-x64 +sun/awt/image/bug8038000.java 8373065 generic-all # Several tests which fail on some hidpi systems/macosx12-aarch64 system java/awt/Window/8159168/SetShapeTest.java 8274106 macosx-aarch64 From 5ec5a6ea6c8e887b4e21f81e382f57129bffbab8 Mon Sep 17 00:00:00 2001 From: Ben Taylor Date: Thu, 4 Dec 2025 21:37:09 +0000 Subject: [PATCH 182/706] 8373054: Shenandoah: Remove unnecessary BarrierSetNMethod::arm in shenandoahCodeRoots Reviewed-by: wkemper, ysr, shade --- src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.cpp b/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.cpp index ec39e0c0ccb..07d339eb32e 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.cpp @@ -144,13 +144,12 @@ public: { ShenandoahReentrantLocker locker(nm_data->lock()); - // Heal oops and disarm + // Heal oops if (_bs->is_armed(nm)) { ShenandoahEvacOOMScope oom_evac_scope; ShenandoahNMethod::heal_nmethod_metadata(nm_data); - // Code cache unloading needs to know about on-stack nmethods. Arm the nmethods to get - // mark_as_maybe_on_stack() callbacks when they are used again. - _bs->arm(nm); + // Must remain armed to complete remaining work in nmethod entry barrier + assert(_bs->is_armed(nm), "Should remain armed"); } } From c8b30da7ef48edb3d43e07d2c1b8622d8123c3a9 Mon Sep 17 00:00:00 2001 From: Ben Taylor Date: Thu, 4 Dec 2025 22:11:48 +0000 Subject: [PATCH 183/706] 8373039: Remove Incorrect Asserts in shenandoahScanRemembered Reviewed-by: wkemper, ysr, xpeng --- .../gc/shenandoah/shenandoahScanRemembered.cpp | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.cpp b/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.cpp index 44064dbd1a9..a3c96a7d53b 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.cpp @@ -335,7 +335,6 @@ HeapWord* ShenandoahCardCluster::first_object_start(const size_t card_index, con if (ctx->is_marked(p)) { oop obj = cast_to_oop(p); assert(oopDesc::is_oop(obj), "Should be an object"); - assert(Klass::is_valid(obj->klass()), "Not a valid klass ptr"); assert(p + obj->size() > left, "This object should span start of card"); assert(p < right, "Result must precede right"); return p; @@ -362,15 +361,15 @@ HeapWord* ShenandoahCardCluster::first_object_start(const size_t card_index, con // Recall that we already dealt with the co-initial object case above assert(p < left, "obj should start before left"); - // While it is safe to ask an object its size in the loop that - // follows, the (ifdef'd out) loop should never be needed. + // While it is safe to ask an object its size in the block that + // follows, the (ifdef'd out) block should never be needed. // 1. we ask this question only for regions in the old generation, and those // that are not humongous regions // 2. there is no direct allocation ever by mutators in old generation // regions walked by this code. Only GC will ever allocate in old regions, // and then too only during promotion/evacuation phases. Thus there is no danger // of races between reading from and writing to the object start array, - // or of asking partially initialized objects their size (in the loop below). + // or of asking partially initialized objects their size (in the ifdef below). // Furthermore, humongous regions (and their dirty cards) are never processed // by this code. // 3. only GC asks this question during phases when it is not concurrently @@ -382,15 +381,6 @@ HeapWord* ShenandoahCardCluster::first_object_start(const size_t card_index, con #ifdef ASSERT oop obj = cast_to_oop(p); assert(oopDesc::is_oop(obj), "Should be an object"); - while (p + obj->size() < left) { - p += obj->size(); - obj = cast_to_oop(p); - assert(oopDesc::is_oop(obj), "Should be an object"); - assert(Klass::is_valid(obj->klass()), "Not a valid klass ptr"); - // Check assumptions in previous block comment if this assert fires - fatal("Should never need forward walk in block start"); - } - assert(p <= left, "p should start at or before left end of card"); assert(p + obj->size() > left, "obj should end after left end of card"); #endif // ASSERT return p; From 6db1c4f5b93a1b7f7d9da36745dc433c9985a169 Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Thu, 4 Dec 2025 22:34:42 +0000 Subject: [PATCH 184/706] 8371409: Wrong lock ordering between FullGCALot_lock and ThreadsLockThrottle_lock/MethodCompileQueue_lock Reviewed-by: rehn, pchilanomate --- src/hotspot/share/memory/universe.cpp | 4 ++-- src/hotspot/share/runtime/mutexLocker.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/memory/universe.cpp b/src/hotspot/share/memory/universe.cpp index 4d2897be5eb..cfbab1b8afb 100644 --- a/src/hotspot/share/memory/universe.cpp +++ b/src/hotspot/share/memory/universe.cpp @@ -544,7 +544,7 @@ void Universe::genesis(TRAPS) { // Only modify the global variable inside the mutex. // If we had a race to here, the other dummy_array instances // and their elements just get dropped on the floor, which is fine. - MutexLocker ml(THREAD, FullGCALot_lock); + MutexLocker ml(THREAD, FullGCALot_lock, Mutex::_no_safepoint_check_flag); if (_fullgc_alot_dummy_array.is_empty()) { _fullgc_alot_dummy_array = OopHandle(vm_global(), dummy_array()); } @@ -1458,7 +1458,7 @@ uintptr_t Universe::verify_mark_bits() { #ifdef ASSERT // Release dummy object(s) at bottom of heap bool Universe::release_fullgc_alot_dummy() { - MutexLocker ml(FullGCALot_lock); + MutexLocker ml(FullGCALot_lock, Mutex::_no_safepoint_check_flag); objArrayOop fullgc_alot_dummy_array = (objArrayOop)_fullgc_alot_dummy_array.resolve(); if (fullgc_alot_dummy_array != nullptr) { if (_fullgc_alot_dummy_next >= fullgc_alot_dummy_array->length()) { diff --git a/src/hotspot/share/runtime/mutexLocker.cpp b/src/hotspot/share/runtime/mutexLocker.cpp index 5d7e310fb11..b102e6424f1 100644 --- a/src/hotspot/share/runtime/mutexLocker.cpp +++ b/src/hotspot/share/runtime/mutexLocker.cpp @@ -244,7 +244,7 @@ void mutex_init() { MUTEX_DEFN(SymbolArena_lock , PaddedMutex , nosafepoint); MUTEX_DEFN(ExceptionCache_lock , PaddedMutex , safepoint); #ifndef PRODUCT - MUTEX_DEFN(FullGCALot_lock , PaddedMutex , safepoint); // a lock to make FullGCALot MT safe + MUTEX_DEFN(FullGCALot_lock , PaddedMutex , nosafepoint); // a lock to make FullGCALot MT safe #endif MUTEX_DEFN(BeforeExit_lock , PaddedMonitor, safepoint); From 13e32bf1667a3be8492d1e4e3a273951202acd9c Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Thu, 4 Dec 2025 22:39:58 +0000 Subject: [PATCH 185/706] 8372098: Move AccessFlags to InstanceKlass Reviewed-by: liach, vlivanov, dlong, sspitsyn --- src/hotspot/share/ci/ciInstanceKlass.hpp | 4 ++++ src/hotspot/share/ci/ciKlass.cpp | 9 -------- src/hotspot/share/ci/ciKlass.hpp | 3 --- .../share/classfile/defaultMethods.cpp | 2 +- src/hotspot/share/classfile/javaClasses.cpp | 8 +++---- .../share/classfile/systemDictionary.cpp | 7 +++--- src/hotspot/share/jvmci/vmStructs_jvmci.cpp | 2 +- src/hotspot/share/oops/arrayKlass.cpp | 3 ++- src/hotspot/share/oops/fieldInfo.hpp | 1 + src/hotspot/share/oops/instanceKlass.cpp | 11 ++++++++++ src/hotspot/share/oops/instanceKlass.hpp | 20 ++++++++++++++++- src/hotspot/share/oops/klass.cpp | 11 ---------- src/hotspot/share/oops/klass.hpp | 22 +++++-------------- src/hotspot/share/opto/compile.cpp | 8 +++++-- src/hotspot/share/opto/library_call.cpp | 14 +++++++----- src/hotspot/share/opto/memnode.cpp | 8 ++++--- src/hotspot/share/runtime/vmStructs.cpp | 2 +- src/hotspot/share/utilities/accessFlags.hpp | 2 +- .../sun/jvm/hotspot/oops/InstanceKlass.java | 17 ++++++++++++-- .../classes/sun/jvm/hotspot/oops/Klass.java | 16 +------------- .../sun/jvm/hotspot/oops/ObjectHeap.java | 6 ++--- .../runtime/ConcurrentLocksPrinter.java | 4 ++-- .../jvm/hotspot/tools/ClassLoaderStats.java | 4 ++-- .../HotSpotResolvedObjectTypeImpl.java | 10 ++++++--- .../jdk/vm/ci/hotspot/HotSpotVMConfig.java | 2 +- 25 files changed, 106 insertions(+), 90 deletions(-) diff --git a/src/hotspot/share/ci/ciInstanceKlass.hpp b/src/hotspot/share/ci/ciInstanceKlass.hpp index 1f887771f54..a1b2d8dd12d 100644 --- a/src/hotspot/share/ci/ciInstanceKlass.hpp +++ b/src/hotspot/share/ci/ciInstanceKlass.hpp @@ -149,6 +149,10 @@ public: assert(is_loaded(), "must be loaded"); return _flags; } + + // Fetch Klass::access_flags. + jint access_flags() { return flags().as_int(); } + bool has_finalizer() { assert(is_loaded(), "must be loaded"); return _has_finalizer; } diff --git a/src/hotspot/share/ci/ciKlass.cpp b/src/hotspot/share/ci/ciKlass.cpp index f3e49634d29..0a0379af97e 100644 --- a/src/hotspot/share/ci/ciKlass.cpp +++ b/src/hotspot/share/ci/ciKlass.cpp @@ -216,15 +216,6 @@ jint ciKlass::modifier_flags() { ) } -// ------------------------------------------------------------------ -// ciKlass::access_flags -jint ciKlass::access_flags() { - assert(is_loaded(), "not loaded"); - GUARDED_VM_ENTRY( - return get_Klass()->access_flags().as_unsigned_short(); - ) -} - // ------------------------------------------------------------------ // ciKlass::misc_flags klass_flags_t ciKlass::misc_flags() { diff --git a/src/hotspot/share/ci/ciKlass.hpp b/src/hotspot/share/ci/ciKlass.hpp index 8d03b910de5..f95602b9717 100644 --- a/src/hotspot/share/ci/ciKlass.hpp +++ b/src/hotspot/share/ci/ciKlass.hpp @@ -122,9 +122,6 @@ public: // Fetch modifier flags. jint modifier_flags(); - // Fetch Klass::access_flags. - jint access_flags(); - // Fetch Klass::misc_flags. klass_flags_t misc_flags(); diff --git a/src/hotspot/share/classfile/defaultMethods.cpp b/src/hotspot/share/classfile/defaultMethods.cpp index e5cb5d8f354..2588ebd60ca 100644 --- a/src/hotspot/share/classfile/defaultMethods.cpp +++ b/src/hotspot/share/classfile/defaultMethods.cpp @@ -439,7 +439,7 @@ class MethodFamily : public ResourceObj { StreamIndentor si(str, indent * 2); str->print("Selected method: "); print_method(str, _selected_target); - Klass* method_holder = _selected_target->method_holder(); + InstanceKlass* method_holder = _selected_target->method_holder(); if (!method_holder->is_interface()) { str->print(" : in superclass"); } diff --git a/src/hotspot/share/classfile/javaClasses.cpp b/src/hotspot/share/classfile/javaClasses.cpp index 614a0199beb..77a94c8afa5 100644 --- a/src/hotspot/share/classfile/javaClasses.cpp +++ b/src/hotspot/share/classfile/javaClasses.cpp @@ -1091,10 +1091,6 @@ void java_lang_Class::allocate_mirror(Klass* k, bool is_scratch, Handle protecti // Set the modifiers flag. u2 computed_modifiers = k->compute_modifier_flags(); set_modifiers(mirror(), computed_modifiers); - // Set the raw access_flags, this is used by reflection instead of modifier flags. - // The Java code for array classes gets the access flags from the element type. - assert(!k->is_array_klass() || k->access_flags().as_unsigned_short() == 0, "access flags are not set for arrays"); - set_raw_access_flags(mirror(), k->access_flags().as_unsigned_short()); InstanceMirrorKlass* mk = InstanceMirrorKlass::cast(mirror->klass()); assert(oop_size(mirror()) == mk->instance_size(k), "should have been set"); @@ -1103,6 +1099,8 @@ void java_lang_Class::allocate_mirror(Klass* k, bool is_scratch, Handle protecti // It might also have a component mirror. This mirror must already exist. if (k->is_array_klass()) { + // The Java code for array classes gets the access flags from the element type. + set_raw_access_flags(mirror(), 0); if (k->is_typeArray_klass()) { BasicType type = TypeArrayKlass::cast(k)->element_type(); if (is_scratch) { @@ -1129,6 +1127,8 @@ void java_lang_Class::allocate_mirror(Klass* k, bool is_scratch, Handle protecti // and java_mirror in this klass. } else { assert(k->is_instance_klass(), "Must be"); + // Set the raw access_flags, this is used by reflection instead of modifier flags. + set_raw_access_flags(mirror(), InstanceKlass::cast(k)->access_flags().as_unsigned_short()); initialize_mirror_fields(InstanceKlass::cast(k), mirror, protection_domain, classData, THREAD); if (HAS_PENDING_EXCEPTION) { // If any of the fields throws an exception like OOM remove the klass field diff --git a/src/hotspot/share/classfile/systemDictionary.cpp b/src/hotspot/share/classfile/systemDictionary.cpp index c873347a197..e03d198eb9f 100644 --- a/src/hotspot/share/classfile/systemDictionary.cpp +++ b/src/hotspot/share/classfile/systemDictionary.cpp @@ -2172,9 +2172,10 @@ static bool is_always_visible_class(oop mirror) { return true; // primitive array } assert(klass->is_instance_klass(), "%s", klass->external_name()); - return klass->is_public() && - (InstanceKlass::cast(klass)->is_same_class_package(vmClasses::Object_klass()) || // java.lang - InstanceKlass::cast(klass)->is_same_class_package(vmClasses::MethodHandle_klass())); // java.lang.invoke + InstanceKlass* ik = InstanceKlass::cast(klass); + return ik->is_public() && + (ik->is_same_class_package(vmClasses::Object_klass()) || // java.lang + ik->is_same_class_package(vmClasses::MethodHandle_klass())); // java.lang.invoke } // Find or construct the Java mirror (java.lang.Class instance) for diff --git a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp index 77e98db9156..91482e825cd 100644 --- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp +++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp @@ -223,6 +223,7 @@ volatile_nonstatic_field(InstanceKlass, _init_state, InstanceKlass::ClassState) \ volatile_nonstatic_field(InstanceKlass, _init_thread, JavaThread*) \ nonstatic_field(InstanceKlass, _misc_flags._flags, u2) \ + nonstatic_field(InstanceKlass, _access_flags, AccessFlags) \ nonstatic_field(InstanceKlass, _annotations, Annotations*) \ \ volatile_nonstatic_field(JavaFrameAnchor, _last_Java_sp, intptr_t*) \ @@ -282,7 +283,6 @@ nonstatic_field(Klass, _name, Symbol*) \ volatile_nonstatic_field(Klass, _next_sibling, Klass*) \ nonstatic_field(Klass, _java_mirror, OopHandle) \ - nonstatic_field(Klass, _access_flags, AccessFlags) \ nonstatic_field(Klass, _class_loader_data, ClassLoaderData*) \ nonstatic_field(Klass, _secondary_supers_bitmap, uintx) \ nonstatic_field(Klass, _hash_slot, uint8_t) \ diff --git a/src/hotspot/share/oops/arrayKlass.cpp b/src/hotspot/share/oops/arrayKlass.cpp index cd929a3bfe1..30a2bc5102a 100644 --- a/src/hotspot/share/oops/arrayKlass.cpp +++ b/src/hotspot/share/oops/arrayKlass.cpp @@ -99,7 +99,8 @@ ArrayKlass::ArrayKlass(Symbol* name, KlassKind kind) : set_name(name); set_super(Universe::is_bootstrapping() ? nullptr : vmClasses::Object_klass()); set_layout_helper(Klass::_lh_neutral_value); - set_is_cloneable(); // All arrays are considered to be cloneable (See JLS 20.1.5) + // All arrays are considered to be cloneable (See JLS 20.1.5) + set_is_cloneable_fast(); JFR_ONLY(INIT_ID(this);) log_array_class_load(this); } diff --git a/src/hotspot/share/oops/fieldInfo.hpp b/src/hotspot/share/oops/fieldInfo.hpp index a98895da9cf..b6d9c4d34e5 100644 --- a/src/hotspot/share/oops/fieldInfo.hpp +++ b/src/hotspot/share/oops/fieldInfo.hpp @@ -27,6 +27,7 @@ #include "memory/allocation.hpp" #include "oops/typeArrayOop.hpp" +#include "utilities/accessFlags.hpp" #include "utilities/unsigned5.hpp" #include "utilities/vmEnums.hpp" diff --git a/src/hotspot/share/oops/instanceKlass.cpp b/src/hotspot/share/oops/instanceKlass.cpp index 24358f662bc..e74bc80d893 100644 --- a/src/hotspot/share/oops/instanceKlass.cpp +++ b/src/hotspot/share/oops/instanceKlass.cpp @@ -552,6 +552,17 @@ InstanceKlass::InstanceKlass(const ClassFileParser& parser, KlassKind kind, Refe assert(size_helper() == parser.layout_size(), "incorrect size_helper?"); } +void InstanceKlass::set_is_cloneable() { + if (name() == vmSymbols::java_lang_invoke_MemberName()) { + assert(is_final(), "no subclasses allowed"); + // MemberName cloning should not be intrinsified and always happen in JVM_Clone. + } else if (reference_type() != REF_NONE) { + // Reference cloning should not be intrinsified and always happen in JVM_Clone. + } else { + set_is_cloneable_fast(); + } +} + void InstanceKlass::deallocate_methods(ClassLoaderData* loader_data, Array* methods) { if (methods != nullptr && methods != Universe::the_empty_method_array() && diff --git a/src/hotspot/share/oops/instanceKlass.hpp b/src/hotspot/share/oops/instanceKlass.hpp index 8bb9741af9f..a03e6c05b54 100644 --- a/src/hotspot/share/oops/instanceKlass.hpp +++ b/src/hotspot/share/oops/instanceKlass.hpp @@ -229,7 +229,9 @@ class InstanceKlass: public Klass { // _idnum_allocated_count. volatile ClassState _init_state; // state of class - u1 _reference_type; // reference type + u1 _reference_type; // reference type + + AccessFlags _access_flags; // Access flags. The class/interface distinction is stored here. // State is set either at parse time or while executing, atomically to not disturb other state InstanceKlassFlags _misc_flags; @@ -305,6 +307,22 @@ class InstanceKlass: public Klass { // Sets finalization state static void set_finalization_enabled(bool val) { _finalization_enabled = val; } + // Access flags + AccessFlags access_flags() const { return _access_flags; } + void set_access_flags(AccessFlags flags) { _access_flags = flags; } + + bool is_public() const { return _access_flags.is_public(); } + bool is_final() const { return _access_flags.is_final(); } + bool is_interface() const { return _access_flags.is_interface(); } + bool is_abstract() const { return _access_flags.is_abstract(); } + bool is_super() const { return _access_flags.is_super(); } + bool is_synthetic() const { return _access_flags.is_synthetic(); } + void set_is_synthetic() { _access_flags.set_is_synthetic(); } + + static ByteSize access_flags_offset() { return byte_offset_of(InstanceKlass, _access_flags); } + + void set_is_cloneable(); + // Quick checks for the loader that defined this class (without switching on this->class_loader()) bool defined_by_boot_loader() const { return _misc_flags.defined_by_boot_loader(); } bool defined_by_platform_loader() const { return _misc_flags.defined_by_platform_loader(); } diff --git a/src/hotspot/share/oops/klass.cpp b/src/hotspot/share/oops/klass.cpp index 772541cdd10..001e9eba790 100644 --- a/src/hotspot/share/oops/klass.cpp +++ b/src/hotspot/share/oops/klass.cpp @@ -72,17 +72,6 @@ bool Klass::is_cloneable() const { is_subtype_of(vmClasses::Cloneable_klass()); } -void Klass::set_is_cloneable() { - if (name() == vmSymbols::java_lang_invoke_MemberName()) { - assert(is_final(), "no subclasses allowed"); - // MemberName cloning should not be intrinsified and always happen in JVM_Clone. - } else if (is_instance_klass() && InstanceKlass::cast(this)->reference_type() != REF_NONE) { - // Reference cloning should not be intrinsified and always happen in JVM_Clone. - } else { - _misc_flags.set_is_cloneable_fast(true); - } -} - uint8_t Klass::compute_hash_slot(Symbol* n) { uint hash_code; // Special cases for the two superclasses of all Array instances. diff --git a/src/hotspot/share/oops/klass.hpp b/src/hotspot/share/oops/klass.hpp index 5ac393d7614..25fb900e7d6 100644 --- a/src/hotspot/share/oops/klass.hpp +++ b/src/hotspot/share/oops/klass.hpp @@ -30,7 +30,6 @@ #include "oops/metadata.hpp" #include "oops/oop.hpp" #include "oops/oopHandle.hpp" -#include "utilities/accessFlags.hpp" #include "utilities/macros.hpp" #if INCLUDE_JFR #include "jfr/support/jfrTraceIdExtension.hpp" @@ -120,9 +119,8 @@ class Klass : public Metadata { // - Various type checking in the JVM const KlassKind _kind; - AccessFlags _access_flags; // Access flags. The class/interface distinction is stored here. - // Some flags created by the JVM, not in the class file itself, - // are in _misc_flags below. + // Some flags created by the JVM, not in the class file itself, + // are in _misc_flags below. KlassFlags _misc_flags; // The fields _super_check_offset, _secondary_super_cache, _secondary_supers @@ -453,7 +451,6 @@ protected: static ByteSize java_mirror_offset() { return byte_offset_of(Klass, _java_mirror); } static ByteSize class_loader_data_offset() { return byte_offset_of(Klass, _class_loader_data); } static ByteSize layout_helper_offset() { return byte_offset_of(Klass, _layout_helper); } - static ByteSize access_flags_offset() { return byte_offset_of(Klass, _access_flags); } #if INCLUDE_JVMCI static ByteSize subklass_offset() { return byte_offset_of(Klass, _subklass); } static ByteSize next_sibling_offset() { return byte_offset_of(Klass, _next_sibling); } @@ -707,17 +704,10 @@ public: bool is_typeArray_klass() const { return assert_same_query( _kind == TypeArrayKlassKind, is_typeArray_klass_slow()); } #undef assert_same_query - // Access flags - AccessFlags access_flags() const { return _access_flags; } - void set_access_flags(AccessFlags flags) { _access_flags = flags; } - bool is_public() const { return _access_flags.is_public(); } - bool is_final() const { return _access_flags.is_final(); } - bool is_interface() const { return _access_flags.is_interface(); } - bool is_abstract() const { return _access_flags.is_abstract(); } - bool is_super() const { return _access_flags.is_super(); } - bool is_synthetic() const { return _access_flags.is_synthetic(); } - void set_is_synthetic() { _access_flags.set_is_synthetic(); } + virtual bool is_interface() const { return false; } + virtual bool is_abstract() const { return false; } + bool has_finalizer() const { return _misc_flags.has_finalizer(); } void set_has_finalizer() { _misc_flags.set_has_finalizer(true); } bool is_hidden() const { return _misc_flags.is_hidden_class(); } @@ -730,7 +720,7 @@ public: inline bool is_non_strong_hidden() const; bool is_cloneable() const; - void set_is_cloneable(); + void set_is_cloneable_fast() { _misc_flags.set_is_cloneable_fast(true); } inline markWord prototype_header() const; inline void set_prototype_header(markWord header); diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index a89b5b00a25..bf7feeed0a2 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -1726,8 +1726,6 @@ Compile::AliasType* Compile::find_alias_type(const TypePtr* adr_type, bool no_cr } if (flat->offset() == in_bytes(Klass::super_check_offset_offset())) alias_type(idx)->set_rewritable(false); - if (flat->offset() == in_bytes(Klass::access_flags_offset())) - alias_type(idx)->set_rewritable(false); if (flat->offset() == in_bytes(Klass::misc_flags_offset())) alias_type(idx)->set_rewritable(false); if (flat->offset() == in_bytes(Klass::java_mirror_offset())) @@ -1735,6 +1733,12 @@ Compile::AliasType* Compile::find_alias_type(const TypePtr* adr_type, bool no_cr if (flat->offset() == in_bytes(Klass::secondary_super_cache_offset())) alias_type(idx)->set_rewritable(false); } + + if (flat->isa_instklassptr()) { + if (flat->offset() == in_bytes(InstanceKlass::access_flags_offset())) { + alias_type(idx)->set_rewritable(false); + } + } // %%% (We would like to finalize JavaThread::threadObj_offset(), // but the base pointer type is not distinctive enough to identify // references into JavaThread.) diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index 6d4a9104580..113530c8835 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -4020,7 +4020,7 @@ Node* LibraryCallKit::generate_klass_flags_guard(Node* kls, int modifier_mask, i } Node* LibraryCallKit::generate_interface_guard(Node* kls, RegionNode* region) { return generate_klass_flags_guard(kls, JVM_ACC_INTERFACE, 0, region, - Klass::access_flags_offset(), TypeInt::CHAR, T_CHAR); + InstanceKlass::access_flags_offset(), TypeInt::CHAR, T_CHAR); } // Use this for testing if Klass is_hidden, has_finalizer, and is_cloneable_fast. @@ -4132,12 +4132,16 @@ bool LibraryCallKit::inline_native_Class_query(vmIntrinsics::ID id) { // Arrays store an intermediate super as _super, but must report Object. // Other types can report the actual _super. // (To verify this code sequence, check the asserts in JVM_IsInterface.) - if (generate_interface_guard(kls, region) != nullptr) - // A guard was added. If the guard is taken, it was an interface. - phi->add_req(null()); - if (generate_array_guard(kls, region) != nullptr) + if (generate_array_guard(kls, region) != nullptr) { // A guard was added. If the guard is taken, it was an array. phi->add_req(makecon(TypeInstPtr::make(env()->Object_klass()->java_mirror()))); + } + // Check for interface after array since this checks AccessFlags offset into InstanceKlass. + // In other words, we are accessing subtype-specific information, so we need to determine the subtype first. + if (generate_interface_guard(kls, region) != nullptr) { + // A guard was added. If the guard is taken, it was an interface. + phi->add_req(null()); + } // If we fall through, it's a plain class. Get its _super. p = basic_plus_adr(kls, in_bytes(Klass::super_offset())); kls = _gvn.transform(LoadKlassNode::make(_gvn, immutable_memory(), p, TypeRawPtr::BOTTOM, TypeInstKlassPtr::OBJECT_OR_NULL)); diff --git a/src/hotspot/share/opto/memnode.cpp b/src/hotspot/share/opto/memnode.cpp index 61300ab4fcb..19ff90df5ed 100644 --- a/src/hotspot/share/opto/memnode.cpp +++ b/src/hotspot/share/opto/memnode.cpp @@ -1979,10 +1979,12 @@ LoadNode::load_array_final_field(const TypeKlassPtr *tkls, ciKlass* klass) const { assert(!UseCompactObjectHeaders || tkls->offset() != in_bytes(Klass::prototype_header_offset()), "must not happen"); - if (tkls->offset() == in_bytes(Klass::access_flags_offset())) { - // The field is Klass::_access_flags. Return its (constant) value. + + if (tkls->isa_instklassptr() && tkls->offset() == in_bytes(InstanceKlass::access_flags_offset())) { + // The field is InstanceKlass::_access_flags. Return its (constant) value. assert(Opcode() == Op_LoadUS, "must load an unsigned short from _access_flags"); - return TypeInt::make(klass->access_flags()); + ciInstanceKlass* iklass = tkls->is_instklassptr()->instance_klass(); + return TypeInt::make(iklass->access_flags()); } if (tkls->offset() == in_bytes(Klass::misc_flags_offset())) { // The field is Klass::_misc_flags. Return its (constant) value. diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp index 25a99c2d758..50748fd7e45 100644 --- a/src/hotspot/share/runtime/vmStructs.cpp +++ b/src/hotspot/share/runtime/vmStructs.cpp @@ -216,6 +216,7 @@ nonstatic_field(InstanceKlass, _annotations, Annotations*) \ nonstatic_field(InstanceKlass, _method_ordering, Array*) \ nonstatic_field(InstanceKlass, _default_vtable_indices, Array*) \ + nonstatic_field(InstanceKlass, _access_flags, AccessFlags) \ nonstatic_field(Klass, _super_check_offset, juint) \ nonstatic_field(Klass, _secondary_super_cache, Klass*) \ nonstatic_field(Klass, _secondary_supers, Array*) \ @@ -225,7 +226,6 @@ volatile_nonstatic_field(Klass, _subklass, Klass*) \ nonstatic_field(Klass, _layout_helper, jint) \ nonstatic_field(Klass, _name, Symbol*) \ - nonstatic_field(Klass, _access_flags, AccessFlags) \ volatile_nonstatic_field(Klass, _next_sibling, Klass*) \ nonstatic_field(Klass, _next_link, Klass*) \ nonstatic_field(Klass, _vtable_len, int) \ diff --git a/src/hotspot/share/utilities/accessFlags.hpp b/src/hotspot/share/utilities/accessFlags.hpp index a752c09cb42..54bbaeb2c13 100644 --- a/src/hotspot/share/utilities/accessFlags.hpp +++ b/src/hotspot/share/utilities/accessFlags.hpp @@ -67,7 +67,7 @@ class AccessFlags { void set_flags(u2 flags) { _flags = flags; } private: - friend class Klass; + friend class InstanceKlass; friend class ClassFileParser; // the functions below should only be called on the _access_flags inst var directly, // otherwise they are just changing a copy of the flags diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java index 0cd743372d5..785bb85e640 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java @@ -62,6 +62,16 @@ public class InstanceKlass extends Klass { private static int CLASS_STATE_FULLY_INITIALIZED; private static int CLASS_STATE_INITIALIZATION_ERROR; + public long getAccessFlags() { return accessFlags.getValue(this); } + // Convenience routine + public AccessFlags getAccessFlagsObj() { return new AccessFlags(getAccessFlags()); } + + public boolean isPublic() { return getAccessFlagsObj().isPublic(); } + public boolean isFinal() { return getAccessFlagsObj().isFinal(); } + public boolean isInterface() { return getAccessFlagsObj().isInterface(); } + public boolean isAbstract() { return getAccessFlagsObj().isAbstract(); } + public boolean isSuper() { return getAccessFlagsObj().isSuper(); } + public boolean isSynthetic() { return getAccessFlagsObj().isSynthetic(); } private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { Type type = db.lookupType("InstanceKlass"); @@ -88,6 +98,7 @@ public class InstanceKlass extends Klass { breakpoints = type.getAddressField("_breakpoints"); } headerSize = type.getSize(); + accessFlags = new CIntField(type.getCIntegerField("_access_flags"), 0); // read internal field flags constants FIELD_FLAG_IS_INITIALIZED = db.lookupIntConstant("FieldInfo::FieldFlags::_ff_initialized"); @@ -150,6 +161,7 @@ public class InstanceKlass extends Klass { private static CIntField initState; private static CIntField itableLen; private static CIntField nestHostIndex; + private static CIntField accessFlags; private static AddressField breakpoints; // type safe enum for ClassState from instanceKlass.hpp @@ -499,7 +511,7 @@ public class InstanceKlass extends Klass { } } - public boolean implementsInterface(Klass k) { + public boolean implementsInterface(InstanceKlass k) { if (Assert.ASSERTS_ENABLED) { Assert.that(k.isInterface(), "should not reach here"); } @@ -511,7 +523,7 @@ public class InstanceKlass extends Klass { return false; } - boolean computeSubtypeOf(Klass k) { + boolean computeSubtypeOf(InstanceKlass k) { if (k.isInterface()) { return implementsInterface(k); } else { @@ -535,6 +547,7 @@ public class InstanceKlass extends Klass { visitor.doCInt(nonstaticOopMapSize, true); visitor.doCInt(initState, true); visitor.doCInt(itableLen, true); + visitor.doCInt(accessFlags, true); } /* diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Klass.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Klass.java index 1b8a9d0ef69..561c4683d29 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Klass.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Klass.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, 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 @@ -57,7 +57,6 @@ public class Klass extends Metadata implements ClassConstants { superField = new MetadataField(type.getAddressField("_super"), 0); layoutHelper = new IntField(type.getJIntField("_layout_helper"), 0); name = type.getAddressField("_name"); - accessFlags = new CIntField(type.getCIntegerField("_access_flags"), 0); try { traceIDField = type.getField("_trace_id"); } catch(Exception e) { @@ -95,7 +94,6 @@ public class Klass extends Metadata implements ClassConstants { private static MetadataField superField; private static IntField layoutHelper; private static AddressField name; - private static CIntField accessFlags; private static MetadataField subklass; private static MetadataField nextSibling; private static MetadataField nextLink; @@ -117,9 +115,6 @@ public class Klass extends Metadata implements ClassConstants { public Klass getJavaSuper() { return null; } public int getLayoutHelper() { return layoutHelper.getValue(this); } public Symbol getName() { return getSymbol(name); } - public long getAccessFlags() { return accessFlags.getValue(this); } - // Convenience routine - public AccessFlags getAccessFlagsObj(){ return new AccessFlags(getAccessFlags()); } public Klass getSubklassKlass() { return (Klass) subklass.getValue(this); } public Klass getNextSiblingKlass() { return (Klass) nextSibling.getValue(this); } public Klass getNextLinkKlass() { return (Klass) nextLink.getValue(this); } @@ -175,7 +170,6 @@ public class Klass extends Metadata implements ClassConstants { visitor.doMetadata(superField, true); visitor.doInt(layoutHelper, true); // visitor.doOop(name, true); - visitor.doCInt(accessFlags, true); visitor.doMetadata(subklass, true); visitor.doMetadata(nextSibling, true); visitor.doCInt(vtableLen, true); @@ -205,12 +199,4 @@ public class Klass extends Metadata implements ClassConstants { // The subclasses override this to produce the correct form, eg // Ljava/lang/String; For ArrayKlasses getName itself is the signature. public String signature() { return getName().asString(); } - - // Convenience routines - public boolean isPublic() { return getAccessFlagsObj().isPublic(); } - public boolean isFinal() { return getAccessFlagsObj().isFinal(); } - public boolean isInterface() { return getAccessFlagsObj().isInterface(); } - public boolean isAbstract() { return getAccessFlagsObj().isAbstract(); } - public boolean isSuper() { return getAccessFlagsObj().isSuper(); } - public boolean isSynthetic() { return getAccessFlagsObj().isSynthetic(); } } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ObjectHeap.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ObjectHeap.java index a4cdb671959..c71cb3156ea 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ObjectHeap.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ObjectHeap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, 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 @@ -107,7 +107,7 @@ public class ObjectHeap { /** iterate objects of given Klass. param 'includeSubtypes' tells whether to * include objects of subtypes or not */ - public void iterateObjectsOfKlass(HeapVisitor visitor, final Klass k, boolean includeSubtypes) { + public void iterateObjectsOfKlass(HeapVisitor visitor, final InstanceKlass k, boolean includeSubtypes) { if (includeSubtypes) { if (k.isFinal()) { // do the simpler "exact" klass loop @@ -124,7 +124,7 @@ public class ObjectHeap { } /** iterate objects of given Klass (objects of subtypes included) */ - public void iterateObjectsOfKlass(HeapVisitor visitor, final Klass k) { + public void iterateObjectsOfKlass(HeapVisitor visitor, final InstanceKlass k) { iterateObjectsOfKlass(visitor, k, true); } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ConcurrentLocksPrinter.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ConcurrentLocksPrinter.java index fa28a96e333..c4abb3e946d 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ConcurrentLocksPrinter.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ConcurrentLocksPrinter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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,7 +64,7 @@ public class ConcurrentLocksPrinter { private void fillLocks() { VM vm = VM.getVM(); SystemDictionary sysDict = vm.getSystemDictionary(); - Klass absOwnSyncKlass = sysDict.getAbstractOwnableSynchronizerKlass(); + InstanceKlass absOwnSyncKlass = sysDict.getAbstractOwnableSynchronizerKlass(); ObjectHeap heap = vm.getObjectHeap(); // may be not loaded at all if (absOwnSyncKlass != null) { diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/ClassLoaderStats.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/ClassLoaderStats.java index b7c470e3477..0e65a41c571 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/ClassLoaderStats.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/ClassLoaderStats.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, 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,7 +90,7 @@ public class ClassLoaderStats extends Tool { VM vm = VM.getVM(); ObjectHeap heap = vm.getObjectHeap(); - Klass classLoaderKlass = vm.getSystemDictionary().getClassLoaderKlass(); + InstanceKlass classLoaderKlass = vm.getSystemDictionary().getClassLoaderKlass(); try { heap.iterateObjectsOfKlass(new DefaultHeapVisitor() { public boolean doObj(Oop oop) { diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java index 46e53411dee..6074b2b32dc 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2025, 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 @@ -165,8 +165,12 @@ final class HotSpotResolvedObjectTypeImpl extends HotSpotResolvedJavaType implem } public int getAccessFlags() { - HotSpotVMConfig config = config(); - return UNSAFE.getInt(getKlassPointer() + config.klassAccessFlagsOffset); + if (isArray()) { + return 0; // Array Metadata doesn't set access_flags + } else { + HotSpotVMConfig config = config(); + return UNSAFE.getInt(getKlassPointer() + config.instanceKlassAccessFlagsOffset); + } } public int getMiscFlags() { diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java index e4e23c6d8b8..c058f785715 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java @@ -84,7 +84,6 @@ class HotSpotVMConfig extends HotSpotVMConfigAccess { */ final int javaMirrorOffset = getFieldOffset("Klass::_java_mirror", Integer.class, "OopHandle"); - final int klassAccessFlagsOffset = getFieldOffset("Klass::_access_flags", Integer.class, "AccessFlags"); final int klassLayoutHelperOffset = getFieldOffset("Klass::_layout_helper", Integer.class, "jint"); final int klassLayoutHelperNeutralValue = getConstant("Klass::_lh_neutral_value", Integer.class); @@ -93,6 +92,7 @@ class HotSpotVMConfig extends HotSpotVMConfigAccess { final int vtableEntrySize = getFieldValue("CompilerToVM::Data::sizeof_vtableEntry", Integer.class, "int"); final int vtableEntryMethodOffset = getFieldOffset("vtableEntry::_method", Integer.class, "Method*"); + final int instanceKlassAccessFlagsOffset = getFieldOffset("InstanceKlass::_access_flags", Integer.class, "AccessFlags"); final int instanceKlassInitStateOffset = getFieldOffset("InstanceKlass::_init_state", Integer.class, "InstanceKlass::ClassState"); final int instanceKlassConstantsOffset = getFieldOffset("InstanceKlass::_constants", Integer.class, "ConstantPool*"); final int instanceKlassFieldInfoStreamOffset = getFieldOffset("InstanceKlass::_fieldinfo_stream", Integer.class, "Array*"); From 15f25389435288881644f7aeab48fd2eae410999 Mon Sep 17 00:00:00 2001 From: Xiaolong Peng Date: Thu, 4 Dec 2025 23:56:20 +0000 Subject: [PATCH 186/706] 8373056: Shenandoah: Remove unnecessary use of ShenandoahAllocRequest.type() Reviewed-by: wkemper, kdnilsen --- .../gc/shenandoah/shenandoahAllocRequest.hpp | 11 ++-- .../share/gc/shenandoah/shenandoahFreeSet.cpp | 12 ++-- .../share/gc/shenandoah/shenandoahHeap.cpp | 14 ++++- .../gc/shenandoah/shenandoahHeapRegion.hpp | 2 +- .../shenandoahHeapRegion.inline.hpp | 30 ++++------ .../gc/shenandoah/shenandoahOldGeneration.cpp | 56 ++++++++----------- 6 files changed, 58 insertions(+), 67 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahAllocRequest.hpp b/src/hotspot/share/gc/shenandoah/shenandoahAllocRequest.hpp index 05ecfb254a2..c667048ad47 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahAllocRequest.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahAllocRequest.hpp @@ -83,16 +83,15 @@ public: return "PLAB"; default: ShouldNotReachHere(); - return ""; } } private: // When ShenandoahElasticTLAB is enabled, the request cannot be made smaller than _min_size. - size_t _min_size; + size_t const _min_size; // The size of the request in words. - size_t _requested_size; + size_t const _requested_size; // The allocation may be increased for padding or decreased to fit in the remaining space of a region. size_t _actual_size; @@ -104,7 +103,7 @@ private: size_t _waste; // This is the type of the request. - Type _alloc_type; + Type const _alloc_type; #ifdef ASSERT // Check that this is set before being read. @@ -209,6 +208,10 @@ public: return (_alloc_type & bit_old_alloc) == 0; } + inline bool is_cds() const { + return _alloc_type == _alloc_cds; + } + inline ShenandoahAffiliation affiliation() const { return (_alloc_type & bit_old_alloc) == 0 ? YOUNG_GENERATION : OLD_GENERATION ; } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp index 6a6cad68fd9..eb05bf24028 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp @@ -1369,7 +1369,7 @@ template HeapWord* ShenandoahFreeSet::allocate_from_regions(Iter& iterator, ShenandoahAllocRequest &req, bool &in_new_region) { for (idx_t idx = iterator.current(); iterator.has_next(); idx = iterator.next()) { ShenandoahHeapRegion* r = _heap->get_region(idx); - size_t min_size = (req.type() == ShenandoahAllocRequest::_alloc_tlab) ? req.min_size() : req.size(); + size_t min_size = req.is_lab_alloc() ? req.min_size() : req.size(); if (alloc_capacity(r) >= min_size * HeapWordSize) { HeapWord* result = try_allocate_in(r, req, in_new_region); if (result != nullptr) { @@ -1501,7 +1501,7 @@ HeapWord* ShenandoahFreeSet::try_allocate_in(ShenandoahHeapRegion* r, Shenandoah if (in_new_region) { log_debug(gc, free)("Using new region (%zu) for %s (" PTR_FORMAT ").", - r->index(), ShenandoahAllocRequest::alloc_type_to_string(req.type()), p2i(&req)); + r->index(), req.type_string(), p2i(&req)); assert(!r->is_affiliated(), "New region %zu should be unaffiliated", r->index()); r->set_affiliation(req.affiliation()); if (r->is_old()) { @@ -1520,7 +1520,7 @@ HeapWord* ShenandoahFreeSet::try_allocate_in(ShenandoahHeapRegion* r, Shenandoah assert(ctx->is_bitmap_range_within_region_clear(ctx->top_bitmap(r), r->end()), "Bitmap above top_bitmap() must be clear"); #endif log_debug(gc, free)("Using new region (%zu) for %s (" PTR_FORMAT ").", - r->index(), ShenandoahAllocRequest::alloc_type_to_string(req.type()), p2i(&req)); + r->index(), req.type_string(), p2i(&req)); } else { assert(r->is_affiliated(), "Region %zu that is not new should be affiliated", r->index()); if (r->affiliation() != req.affiliation()) { @@ -1534,8 +1534,8 @@ HeapWord* ShenandoahFreeSet::try_allocate_in(ShenandoahHeapRegion* r, Shenandoah if (req.is_lab_alloc()) { size_t adjusted_size = req.size(); size_t free = r->free(); // free represents bytes available within region r - if (req.type() == ShenandoahAllocRequest::_alloc_plab) { - // This is a PLAB allocation + if (req.is_old()) { + // This is a PLAB allocation(lab alloc in old gen) assert(_heap->mode()->is_generational(), "PLABs are only for generational mode"); assert(_partitions.in_free_set(ShenandoahFreeSetPartitionId::OldCollector, r->index()), "PLABS must be allocated in old_collector_free regions"); @@ -1596,8 +1596,6 @@ HeapWord* ShenandoahFreeSet::try_allocate_in(ShenandoahHeapRegion* r, Shenandoah r->set_update_watermark(r->top()); if (r->is_old()) { _partitions.increase_used(ShenandoahFreeSetPartitionId::OldCollector, (req.actual_size() + req.waste()) * HeapWordSize); - assert(req.type() != ShenandoahAllocRequest::_alloc_gclab, "old-gen allocations use PLAB or shared allocation"); - // for plabs, we'll sort the difference between evac and promotion usage when we retire the plab } else { _partitions.increase_used(ShenandoahFreeSetPartitionId::Collector, (req.actual_size() + req.waste()) * HeapWordSize); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp index 6d569e9b4ce..3bf53f800a2 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp @@ -985,7 +985,7 @@ HeapWord* ShenandoahHeap::allocate_memory(ShenandoahAllocRequest& req) { assert (req.is_lab_alloc() || (requested == actual), "Only LAB allocations are elastic: %s, requested = %zu, actual = %zu", - ShenandoahAllocRequest::alloc_type_to_string(req.type()), requested, actual); + req.type_string(), requested, actual); } return result; @@ -1014,8 +1014,9 @@ HeapWord* ShenandoahHeap::allocate_memory_under_lock(ShenandoahAllocRequest& req // Record the plab configuration for this result and register the object. if (result != nullptr && req.is_old()) { - old_generation()->configure_plab_for_current_thread(req); - if (!req.is_lab_alloc()) { + if (req.is_lab_alloc()) { + old_generation()->configure_plab_for_current_thread(req); + } else { // Register the newly allocated object while we're holding the global lock since there's no synchronization // built in to the implementation of register_object(). There are potential races when multiple independent // threads are allocating objects, some of which might span the same card region. For example, consider @@ -1035,6 +1036,13 @@ HeapWord* ShenandoahHeap::allocate_memory_under_lock(ShenandoahAllocRequest& req // last-start representing object b while first-start represents object c. This is why we need to require all // register_object() invocations to be "mutually exclusive" with respect to each card's memory range. old_generation()->card_scan()->register_object(result); + + if (req.is_promotion()) { + // Shared promotion. + const size_t actual_size = req.actual_size() * HeapWordSize; + log_debug(gc, plab)("Expend shared promotion of %zu bytes", actual_size); + old_generation()->expend_promoted(actual_size); + } } } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp index 32382f5e594..2ed5614c698 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp @@ -447,7 +447,7 @@ public: return (bottom() <= p) && (p < top()); } - inline void adjust_alloc_metadata(ShenandoahAllocRequest::Type type, size_t); + inline void adjust_alloc_metadata(const ShenandoahAllocRequest &req, size_t); void reset_alloc_metadata(); size_t get_shared_allocs() const; size_t get_tlab_allocs() const; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.inline.hpp index 4feeed815da..69673eb7a60 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.inline.hpp @@ -71,7 +71,7 @@ HeapWord* ShenandoahHeapRegion::allocate_aligned(size_t size, ShenandoahAllocReq } make_regular_allocation(req.affiliation()); - adjust_alloc_metadata(req.type(), size); + adjust_alloc_metadata(req, size); HeapWord* new_top = aligned_obj + size; assert(new_top <= end(), "PLAB cannot span end of heap region"); @@ -111,7 +111,7 @@ HeapWord* ShenandoahHeapRegion::allocate(size_t size, const ShenandoahAllocReque HeapWord* obj = top(); if (pointer_delta(end(), obj) >= size) { make_regular_allocation(req.affiliation()); - adjust_alloc_metadata(req.type(), size); + adjust_alloc_metadata(req, size); HeapWord* new_top = obj + size; set_top(new_top); @@ -125,26 +125,16 @@ HeapWord* ShenandoahHeapRegion::allocate(size_t size, const ShenandoahAllocReque } } -inline void ShenandoahHeapRegion::adjust_alloc_metadata(ShenandoahAllocRequest::Type type, size_t size) { - switch (type) { - case ShenandoahAllocRequest::_alloc_shared: - case ShenandoahAllocRequest::_alloc_shared_gc: - case ShenandoahAllocRequest::_alloc_shared_gc_old: - case ShenandoahAllocRequest::_alloc_shared_gc_promotion: - case ShenandoahAllocRequest::_alloc_cds: - // Counted implicitly by tlab/gclab allocs - break; - case ShenandoahAllocRequest::_alloc_tlab: +inline void ShenandoahHeapRegion::adjust_alloc_metadata(const ShenandoahAllocRequest &req, size_t size) { + // Only need to update alloc metadata for lab alloc, shared alloc is counted implicitly by tlab/gclab allocs + if (req.is_lab_alloc()) { + if (req.is_mutator_alloc()) { _tlab_allocs += size; - break; - case ShenandoahAllocRequest::_alloc_gclab: - _gclab_allocs += size; - break; - case ShenandoahAllocRequest::_alloc_plab: + } else if (req.is_old()) { _plab_allocs += size; - break; - default: - ShouldNotReachHere(); + } else { + _gclab_allocs += size; + } } } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp b/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp index 838326c0288..6a0f986cde5 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp @@ -168,7 +168,7 @@ size_t ShenandoahOldGeneration::get_promoted_expended() const { } bool ShenandoahOldGeneration::can_allocate(const ShenandoahAllocRequest &req) const { - assert(req.type() != ShenandoahAllocRequest::_alloc_gclab, "GCLAB pertains only to young-gen memory"); + assert(req.is_old(), "Must be old allocation request"); const size_t requested_bytes = req.size() * HeapWordSize; // The promotion reserve may also be used for evacuations. If we can promote this object, @@ -180,7 +180,7 @@ bool ShenandoahOldGeneration::can_allocate(const ShenandoahAllocRequest &req) co return true; } - if (req.type() == ShenandoahAllocRequest::_alloc_plab) { + if (req.is_lab_alloc()) { // The promotion reserve cannot accommodate this plab request. Check if we still have room for // evacuations. Note that we cannot really know how much of the plab will be used for evacuations, // so here we only check that some evacuation reserve still exists. @@ -195,37 +195,29 @@ bool ShenandoahOldGeneration::can_allocate(const ShenandoahAllocRequest &req) co void ShenandoahOldGeneration::configure_plab_for_current_thread(const ShenandoahAllocRequest &req) { - // Note: Even when a mutator is performing a promotion outside a LAB, we use a 'shared_gc' request. - if (req.is_gc_alloc()) { - const size_t actual_size = req.actual_size() * HeapWordSize; - if (req.type() == ShenandoahAllocRequest::_alloc_plab) { - // We've created a new plab. Now we configure it whether it will be used for promotions - // and evacuations - or just evacuations. - Thread* thread = Thread::current(); - ShenandoahThreadLocalData::reset_plab_promoted(thread); + assert(req.is_gc_alloc() && req.is_old() && req.is_lab_alloc(), "Must be a plab alloc request"); + const size_t actual_size = req.actual_size() * HeapWordSize; + // We've created a new plab. Now we configure it whether it will be used for promotions + // and evacuations - or just evacuations. + Thread* thread = Thread::current(); + ShenandoahThreadLocalData::reset_plab_promoted(thread); - // The actual size of the allocation may be larger than the requested bytes (due to alignment on card boundaries). - // If this puts us over our promotion budget, we need to disable future PLAB promotions for this thread. - if (can_promote(actual_size)) { - // Assume the entirety of this PLAB will be used for promotion. This prevents promotion from overreach. - // When we retire this plab, we'll unexpend what we don't really use. - log_debug(gc, plab)("Thread can promote using PLAB of %zu bytes. Expended: %zu, available: %zu", - actual_size, get_promoted_expended(), get_promoted_reserve()); - expend_promoted(actual_size); - ShenandoahThreadLocalData::enable_plab_promotions(thread); - ShenandoahThreadLocalData::set_plab_actual_size(thread, actual_size); - } else { - // Disable promotions in this thread because entirety of this PLAB must be available to hold old-gen evacuations. - ShenandoahThreadLocalData::disable_plab_promotions(thread); - ShenandoahThreadLocalData::set_plab_actual_size(thread, 0); - log_debug(gc, plab)("Thread cannot promote using PLAB of %zu bytes. Expended: %zu, available: %zu, mixed evacuations? %s", - actual_size, get_promoted_expended(), get_promoted_reserve(), BOOL_TO_STR(ShenandoahHeap::heap()->collection_set()->has_old_regions())); - } - } else if (req.is_promotion()) { - // Shared promotion. - log_debug(gc, plab)("Expend shared promotion of %zu bytes", actual_size); - expend_promoted(actual_size); - } + // The actual size of the allocation may be larger than the requested bytes (due to alignment on card boundaries). + // If this puts us over our promotion budget, we need to disable future PLAB promotions for this thread. + if (can_promote(actual_size)) { + // Assume the entirety of this PLAB will be used for promotion. This prevents promotion from overreach. + // When we retire this plab, we'll unexpend what we don't really use. + log_debug(gc, plab)("Thread can promote using PLAB of %zu bytes. Expended: %zu, available: %zu", + actual_size, get_promoted_expended(), get_promoted_reserve()); + expend_promoted(actual_size); + ShenandoahThreadLocalData::enable_plab_promotions(thread); + ShenandoahThreadLocalData::set_plab_actual_size(thread, actual_size); + } else { + // Disable promotions in this thread because entirety of this PLAB must be available to hold old-gen evacuations. + ShenandoahThreadLocalData::disable_plab_promotions(thread); + ShenandoahThreadLocalData::set_plab_actual_size(thread, 0); + log_debug(gc, plab)("Thread cannot promote using PLAB of %zu bytes. Expended: %zu, available: %zu, mixed evacuations? %s", + actual_size, get_promoted_expended(), get_promoted_reserve(), BOOL_TO_STR(ShenandoahHeap::heap()->collection_set()->has_old_regions())); } } From 7e91d34f3e83b4c39d6ce5de34373d7d74d54512 Mon Sep 17 00:00:00 2001 From: Anjian Wen Date: Fri, 5 Dec 2025 02:51:13 +0000 Subject: [PATCH 187/706] 8365732: RISC-V: implement AES CTR intrinsics Reviewed-by: fyang, mli --- src/hotspot/cpu/riscv/stubGenerator_riscv.cpp | 229 +++++++++++++++++- src/hotspot/cpu/riscv/vm_version_riscv.cpp | 18 +- 2 files changed, 238 insertions(+), 9 deletions(-) diff --git a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp index dff9a3d508e..d0cbe8ea347 100644 --- a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp +++ b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp @@ -2493,8 +2493,8 @@ class StubGenerator: public StubCodeGenerator { __ vsetivli(x0, 4, Assembler::e32, Assembler::m1); __ vle32_v(res, from); - __ mv(t2, 52); - __ blt(keylen, t2, L_aes128); + __ mv(t2, 52); // key length could be only {11, 13, 15} * 4 = {44, 52, 60} + __ bltu(keylen, t2, L_aes128); __ beq(keylen, t2, L_aes192); // Else we fallthrough to the biggest case (256-bit key size) @@ -2572,8 +2572,8 @@ class StubGenerator: public StubCodeGenerator { __ vsetivli(x0, 4, Assembler::e32, Assembler::m1); __ vle32_v(res, from); - __ mv(t2, 52); - __ blt(keylen, t2, L_aes128); + __ mv(t2, 52); // key length could be only {11, 13, 15} * 4 = {44, 52, 60} + __ bltu(keylen, t2, L_aes128); __ beq(keylen, t2, L_aes192); // Else we fallthrough to the biggest case (256-bit key size) @@ -2606,6 +2606,223 @@ class StubGenerator: public StubCodeGenerator { return start; } + // Load big-endian 128-bit from memory. + void be_load_counter_128(Register counter_hi, Register counter_lo, Register counter) { + __ ld(counter_lo, Address(counter, 8)); // Load 128-bits from counter + __ ld(counter_hi, Address(counter)); + __ rev8(counter_lo, counter_lo); // Convert big-endian to little-endian + __ rev8(counter_hi, counter_hi); + } + + // Little-endian 128-bit + 64-bit -> 128-bit addition. + void add_counter_128(Register counter_hi, Register counter_lo) { + assert_different_registers(counter_hi, counter_lo, t0); + __ addi(counter_lo, counter_lo, 1); + __ seqz(t0, counter_lo); // Check for result overflow + __ add(counter_hi, counter_hi, t0); // Add 1 if overflow otherwise 0 + } + + // Store big-endian 128-bit to memory. + void be_store_counter_128(Register counter_hi, Register counter_lo, Register counter) { + assert_different_registers(counter_hi, counter_lo, t0, t1); + __ rev8(t0, counter_lo); // Convert little-endian to big-endian + __ rev8(t1, counter_hi); + __ sd(t0, Address(counter, 8)); // Store 128-bits to counter + __ sd(t1, Address(counter)); + } + + void counterMode_AESCrypt(int round, Register in, Register out, Register key, Register counter, + Register input_len, Register saved_encrypted_ctr, Register used_ptr) { + // Algorithm: + // + // generate_aes_loadkeys(); + // load_counter_128(counter_hi, counter_lo, counter); + // + // L_next: + // if (used >= BLOCK_SIZE) goto L_main_loop; + // + // L_encrypt_next: + // *out = *in ^ saved_encrypted_ctr[used]); + // out++; in++; used++; len--; + // if (len == 0) goto L_exit; + // goto L_next; + // + // L_main_loop: + // if (len == 0) goto L_exit; + // saved_encrypted_ctr = generate_aes_encrypt(counter); + // + // add_counter_128(counter_hi, counter_lo); + // be_store_counter_128(counter_hi, counter_lo, counter); + // used = 0; + // + // if(len < BLOCK_SIZE) goto L_encrypt_next; + // + // v_in = load_16Byte(in); + // v_out = load_16Byte(out); + // v_saved_encrypted_ctr = load_16Byte(saved_encrypted_ctr); + // v_out = v_in ^ v_saved_encrypted_ctr; + // out += BLOCK_SIZE; + // in += BLOCK_SIZE; + // len -= BLOCK_SIZE; + // used = BLOCK_SIZE; + // goto L_main_loop; + // + // + // L_exit: + // store(used); + // result = input_len + // return result; + + const Register used = x28; + const Register len = x29; + const Register counter_hi = x30; + const Register counter_lo = x31; + const Register block_size = t2; + + const unsigned int BLOCK_SIZE = 16; + + VectorRegister working_vregs[] = { + v1, v2, v3, v4, v5, v6, v7, v8, + v9, v10, v11, v12, v13, v14, v15 + }; + + __ vsetivli(x0, 4, Assembler::e32, Assembler::m1); + + __ lwu(used, Address(used_ptr)); + __ mv(len, input_len); + __ mv(block_size, BLOCK_SIZE); + + // load keys to working_vregs according to round + generate_aes_loadkeys(key, working_vregs, round); + + // 128-bit big-endian load + be_load_counter_128(counter_hi, counter_lo, counter); + + Label L_next, L_encrypt_next, L_main_loop, L_exit; + // Check the last saved_encrypted_ctr used value, we fall through + // to L_encrypt_next when the used value lower than block_size + __ bind(L_next); + __ bgeu(used, block_size, L_main_loop); + + // There is still data left fewer than block_size after L_main_loop + // or last used, we encrypt them one by one. + __ bind(L_encrypt_next); + __ add(t0, saved_encrypted_ctr, used); + __ lbu(t1, Address(t0)); + __ lbu(t0, Address(in)); + __ xorr(t1, t1, t0); + __ sb(t1, Address(out)); + __ addi(in, in, 1); + __ addi(out, out, 1); + __ addi(used, used, 1); + __ subi(len, len, 1); + __ beqz(len, L_exit); + __ j(L_next); + + // We will calculate the next saved_encrypted_ctr and encrypt the blocks of data + // one by one until there is less than a full block remaining if len not zero + __ bind(L_main_loop); + __ beqz(len, L_exit); + __ vle32_v(v16, counter); + + // encrypt counter according to round + generate_aes_encrypt(v16, working_vregs, round); + + __ vse32_v(v16, saved_encrypted_ctr); + + // 128-bit little-endian increment + add_counter_128(counter_hi, counter_lo); + // 128-bit big-endian store + be_store_counter_128(counter_hi, counter_lo, counter); + + __ mv(used, 0); + // Check if we have a full block_size + __ bltu(len, block_size, L_encrypt_next); + + // We have one full block to encrypt at least + __ vle32_v(v17, in); + __ vxor_vv(v16, v16, v17); + __ vse32_v(v16, out); + __ add(out, out, block_size); + __ add(in, in, block_size); + __ sub(len, len, block_size); + __ mv(used, block_size); + __ j(L_main_loop); + + __ bind(L_exit); + __ sw(used, Address(used_ptr)); + __ mv(x10, input_len); + __ leave(); + __ ret(); + }; + + // CTR AES crypt. + // Arguments: + // + // Inputs: + // c_rarg0 - source byte array address + // c_rarg1 - destination byte array address + // c_rarg2 - K (key) in little endian int array + // c_rarg3 - counter vector byte array address + // c_rarg4 - input length + // c_rarg5 - saved encryptedCounter start + // c_rarg6 - saved used length + // + // Output: + // x10 - input length + // + address generate_counterMode_AESCrypt() { + assert(UseZvkn, "need AES instructions (Zvkned extension) support"); + assert(UseAESCTRIntrinsics, "need AES instructions (Zvkned extension) support"); + assert(UseZbb, "need basic bit manipulation (Zbb extension) support"); + + __ align(CodeEntryAlignment); + StubId stub_id = StubId::stubgen_counterMode_AESCrypt_id; + StubCodeMark mark(this, stub_id); + + const Register in = c_rarg0; + const Register out = c_rarg1; + const Register key = c_rarg2; + const Register counter = c_rarg3; + const Register input_len = c_rarg4; + const Register saved_encrypted_ctr = c_rarg5; + const Register used_len_ptr = c_rarg6; + + const Register keylen = c_rarg7; // temporary register + + const address start = __ pc(); + __ enter(); + + Label L_exit; + __ beqz(input_len, L_exit); + + Label L_aes128, L_aes192; + // Compute #rounds for AES based on the length of the key array + __ lwu(keylen, Address(key, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT))); + __ mv(t0, 52); // key length could be only {11, 13, 15} * 4 = {44, 52, 60} + __ bltu(keylen, t0, L_aes128); + __ beq(keylen, t0, L_aes192); + // Else we fallthrough to the biggest case (256-bit key size) + + // Note: the following function performs crypt with key += 15*16 + counterMode_AESCrypt(15, in, out, key, counter, input_len, saved_encrypted_ctr, used_len_ptr); + + // Note: the following function performs crypt with key += 13*16 + __ bind(L_aes192); + counterMode_AESCrypt(13, in, out, key, counter, input_len, saved_encrypted_ctr, used_len_ptr); + + // Note: the following function performs crypt with key += 11*16 + __ bind(L_aes128); + counterMode_AESCrypt(11, in, out, key, counter, input_len, saved_encrypted_ctr, used_len_ptr); + + __ bind(L_exit); + __ mv(x10, input_len); + __ leave(); + __ ret(); + + return start; + } + // code for comparing 8 characters of strings with Latin1 and Utf16 encoding void compare_string_8_x_LU(Register tmpL, Register tmpU, Register strL, Register strU, Label& DIFF) { @@ -6826,6 +7043,10 @@ static const int64_t right_3_bits = right_n_bits(3); StubRoutines::_aescrypt_decryptBlock = generate_aescrypt_decryptBlock(); } + if (UseAESCTRIntrinsics) { + StubRoutines::_counterMode_AESCrypt = generate_counterMode_AESCrypt(); + } + if (UsePoly1305Intrinsics) { StubRoutines::_poly1305_processBlocks = generate_poly1305_processBlocks(); } diff --git a/src/hotspot/cpu/riscv/vm_version_riscv.cpp b/src/hotspot/cpu/riscv/vm_version_riscv.cpp index 6f4babc872f..75605f25759 100644 --- a/src/hotspot/cpu/riscv/vm_version_riscv.cpp +++ b/src/hotspot/cpu/riscv/vm_version_riscv.cpp @@ -434,6 +434,15 @@ void VM_Version::c2_initialize() { warning("UseAESIntrinsics enabled, but UseAES not, enabling"); UseAES = true; } + + if (FLAG_IS_DEFAULT(UseAESCTRIntrinsics) && UseZbb) { + FLAG_SET_DEFAULT(UseAESCTRIntrinsics, true); + } + + if (UseAESCTRIntrinsics && !UseZbb) { + warning("Cannot enable UseAESCTRIntrinsics on cpu without UseZbb support."); + FLAG_SET_DEFAULT(UseAESCTRIntrinsics, false); + } } else { if (UseAES) { warning("AES instructions are not available on this CPU"); @@ -443,11 +452,10 @@ void VM_Version::c2_initialize() { warning("AES intrinsics are not available on this CPU"); FLAG_SET_DEFAULT(UseAESIntrinsics, false); } - } - - if (UseAESCTRIntrinsics) { - warning("AES/CTR intrinsics are not available on this CPU"); - FLAG_SET_DEFAULT(UseAESCTRIntrinsics, false); + if (UseAESCTRIntrinsics) { + warning("Cannot enable UseAESCTRIntrinsics on cpu without UseZvkn support."); + FLAG_SET_DEFAULT(UseAESCTRIntrinsics, false); + } } } From 674cc3eeca77f1f2a6d937b1df5c5cd8a13c2d31 Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Fri, 5 Dec 2025 03:30:31 +0000 Subject: [PATCH 188/706] 8042054: JTree.updateUI uses out-of-date item size information Reviewed-by: dnguyen, serb --- .../share/classes/javax/swing/JTree.java | 6 +- .../javax/swing/JTree/JTreeUpdateTest.java | 96 +++++++++++++++++++ 2 files changed, 99 insertions(+), 3 deletions(-) create mode 100644 test/jdk/javax/swing/JTree/JTreeUpdateTest.java diff --git a/src/java.desktop/share/classes/javax/swing/JTree.java b/src/java.desktop/share/classes/javax/swing/JTree.java index c081b3cfff8..622c55e2ede 100644 --- a/src/java.desktop/share/classes/javax/swing/JTree.java +++ b/src/java.desktop/share/classes/javax/swing/JTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, 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 @@ -777,10 +777,10 @@ public class JTree extends JComponent implements Scrollable, Accessible updateInProgress = true; try { - setUI((TreeUI)UIManager.getUI(this)); - SwingUtilities.updateRendererOrEditorUI(getCellRenderer()); SwingUtilities.updateRendererOrEditorUI(getCellEditor()); + + setUI((TreeUI)UIManager.getUI(this)); } finally { updateInProgress = false; } diff --git a/test/jdk/javax/swing/JTree/JTreeUpdateTest.java b/test/jdk/javax/swing/JTree/JTreeUpdateTest.java new file mode 100644 index 00000000000..6b0a4f03c29 --- /dev/null +++ b/test/jdk/javax/swing/JTree/JTreeUpdateTest.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2025, 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 8042054 + * @summary JTree.updateUI should use updated item size information + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual JTreeUpdateTest + */ + +import java.awt.BorderLayout; +import java.awt.Dimension; +import javax.swing.BorderFactory; +import javax.swing.JFrame; +import javax.swing.JTree; +import javax.swing.SwingUtilities; +import javax.swing.tree.DefaultTreeCellRenderer; +import javax.swing.UIManager; + +public class JTreeUpdateTest { + + static final String INSTRUCTIONS = """ + A frame with two identical JTrees is shown. + If the left JTree's text is abbreviated and JTree items + are cramped with little space between rows then press Fail. + If the left JTree is identical with right JTree, press Pass. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("JTreeUpdateTest Test instructions") + .instructions(INSTRUCTIONS) + .columns(30) + .testUI(JTreeUpdateTest::createUI) + .build() + .awaitAndCheck(); + } + + private static JFrame createUI() { + setLaf("javax.swing.plaf.metal.MetalLookAndFeel"); + + final JFrame frame = new JFrame("JTreeUpdateTest"); + + final JTree tree = new JTree(); + tree.setPreferredSize(new Dimension(200, 200)); + tree.setCellRenderer(new DefaultTreeCellRenderer()); + tree.setBorder(BorderFactory.createTitledBorder("updateUI() called once")); + frame.add(tree); + + final JTree tree2 = new JTree(); + tree2.setPreferredSize(new Dimension(200, 200)); + tree2.setCellRenderer(new DefaultTreeCellRenderer()); + tree2.setBorder(BorderFactory.createTitledBorder("updateUI() called twice")); + frame.add(tree2, BorderLayout.EAST); + + frame.pack(); + frame.setLocationRelativeTo(null); + + SwingUtilities.invokeLater(() -> { + setLaf("javax.swing.plaf.nimbus.NimbusLookAndFeel"); + SwingUtilities.updateComponentTreeUI(frame); + SwingUtilities.updateComponentTreeUI(tree2); + }); + return frame; + } + + private static void setLaf(String className) { + try { + UIManager.setLookAndFeel(className); + } catch (Exception e) { + throw new RuntimeException(e); + } + } +} From c09167df60f44642492ec20f133713388f4802ad Mon Sep 17 00:00:00 2001 From: Erik Joelsson Date: Fri, 5 Dec 2025 14:01:36 +0000 Subject: [PATCH 189/706] 8373113: Fix whitespace in RunTests.gmk Reviewed-by: tbell --- make/RunTests.gmk | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/make/RunTests.gmk b/make/RunTests.gmk index 1f50b97531b..946b1332edc 100644 --- a/make/RunTests.gmk +++ b/make/RunTests.gmk @@ -873,7 +873,7 @@ define SetupRunJtregTestBody $1_JTREG_BASIC_OPTIONS += -testThreadFactoryPath:$$(JTREG_TEST_THREAD_FACTORY_JAR) $1_JTREG_BASIC_OPTIONS += -testThreadFactory:$$(JTREG_TEST_THREAD_FACTORY) $1_JTREG_BASIC_OPTIONS += $$(addprefix $$(JTREG_PROBLEM_LIST_PREFIX), $$(wildcard \ - $$(addprefix $$($1_TEST_ROOT)/, ProblemList-$$(JTREG_TEST_THREAD_FACTORY).txt) \ + $$(addprefix $$($1_TEST_ROOT)/, ProblemList-$$(JTREG_TEST_THREAD_FACTORY).txt) \ )) endif @@ -881,8 +881,8 @@ define SetupRunJtregTestBody AGENT := $$(LIBRARY_PREFIX)JvmtiStressAgent$$(SHARED_LIBRARY_SUFFIX)=$$(JTREG_JVMTI_STRESS_AGENT) $1_JTREG_BASIC_OPTIONS += -javaoption:'-agentpath:$(TEST_IMAGE_DIR)/hotspot/jtreg/native/$$(AGENT)' $1_JTREG_BASIC_OPTIONS += $$(addprefix $$(JTREG_PROBLEM_LIST_PREFIX), $$(wildcard \ - $$(addprefix $$($1_TEST_ROOT)/, ProblemList-jvmti-stress-agent.txt) \ - )) + $$(addprefix $$($1_TEST_ROOT)/, ProblemList-jvmti-stress-agent.txt) \ + )) endif @@ -1092,7 +1092,7 @@ define SetupRunJtregTestBody $$(call MakeDir, $$($1_TEST_RESULTS_DIR) $$($1_TEST_SUPPORT_DIR) \ $$($1_TEST_TMP_DIR)) $$(call ExecuteWithLog, $$($1_TEST_SUPPORT_DIR)/jtreg, \ - $$(COV_ENVIRONMENT) $$($1_COMMAND_LINE) \ + $$(COV_ENVIRONMENT) $$($1_COMMAND_LINE) \ ) $1_RESULT_FILE := $$($1_TEST_RESULTS_DIR)/text/stats.txt @@ -1102,11 +1102,11 @@ define SetupRunJtregTestBody $$(call LogWarn, Test report is stored in $$(strip \ $$(subst $$(TOPDIR)/, , $$($1_TEST_RESULTS_DIR)))) - # Read jtreg documentation to learn on the test stats categories: - # https://github.com/openjdk/jtreg/blob/master/src/share/doc/javatest/regtest/faq.md#what-do-all-those-numbers-in-the-test-results-line-mean - # In jtreg, "skipped:" category accounts for tests that threw jtreg.SkippedException at runtime. - # At the same time these tests contribute to "passed:" tests. - # In here we don't want that and so we substract number of "skipped:" from "passed:". + # Read jtreg documentation to learn on the test stats categories: + # https://github.com/openjdk/jtreg/blob/master/src/share/doc/javatest/regtest/faq.md#what-do-all-those-numbers-in-the-test-results-line-mean + # In jtreg, "skipped:" category accounts for tests that threw jtreg.SkippedException at runtime. + # At the same time these tests contribute to "passed:" tests. + # In here we don't want that and so we substract number of "skipped:" from "passed:". $$(if $$(wildcard $$($1_RESULT_FILE)), \ $$(eval $1_PASSED_AND_RUNTIME_SKIPPED := $$(shell $$(AWK) '{ gsub(/[,;]/, ""); \ From ee0b8a72c64f7ac5058dbe5b2062cb35b6195484 Mon Sep 17 00:00:00 2001 From: Chris Plummer Date: Fri, 5 Dec 2025 15:39:49 +0000 Subject: [PATCH 190/706] 8373102: com/sun/jdi/MethodInvokeWithTraceOnTest.java can fail with ObjectCollectedException when run with a small heap Reviewed-by: amenkov, sspitsyn --- .../com/sun/tools/jdi/EventSetImpl.java | 20 ++++++++++++++++--- test/jdk/ProblemList.txt | 1 - 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/jdk.jdi/share/classes/com/sun/tools/jdi/EventSetImpl.java b/src/jdk.jdi/share/classes/com/sun/tools/jdi/EventSetImpl.java index 19e8b45c491..9a13eb3dca5 100644 --- a/src/jdk.jdi/share/classes/com/sun/tools/jdi/EventSetImpl.java +++ b/src/jdk.jdi/share/classes/com/sun/tools/jdi/EventSetImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, 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 com.sun.jdi.InternalException; import com.sun.jdi.Locatable; import com.sun.jdi.Location; import com.sun.jdi.Method; +import com.sun.jdi.ObjectCollectedException; import com.sun.jdi.ObjectReference; import com.sun.jdi.ReferenceType; import com.sun.jdi.ThreadReference; @@ -206,6 +207,19 @@ public class EventSetImpl extends ArrayList implements EventSet { } + /* Safely fetch the thread name in case there is an ObjectCollectedException. + * This can happen when dealing with SUSPEND_NONE events. + */ + private static String getThreadName(ThreadReference thread) { + String name; + try { + name = thread.name(); + } catch (ObjectCollectedException oce) { + name = ""; + } + return name; + } + abstract class ThreadedEventImpl extends EventImpl { private ThreadReference thread; @@ -220,7 +234,7 @@ public class EventSetImpl extends ArrayList implements EventSet { } public String toString() { - return eventName() + " in thread " + thread.name(); + return eventName() + " in thread " + getThreadName(thread); } } @@ -249,7 +263,7 @@ public class EventSetImpl extends ArrayList implements EventSet { public String toString() { return eventName() + "@" + ((location() == null) ? " null" : location().toString()) + - " in thread " + thread().name(); + " in thread " + getThreadName(thread()); } } diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 814fd2caae9..0076b1cf891 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -716,7 +716,6 @@ javax/swing/plaf/synth/7158712/bug7158712.java 8324782 macosx-all # jdk_jdi com/sun/jdi/InvokeHangTest.java 8218463 linux-all -com/sun/jdi/MethodInvokeWithTraceOnTest.java 8373022 generic-all ############################################################################ From 4d696d0d0ed523e3c99c68214586673913b1c7b5 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Fri, 5 Dec 2025 15:46:07 +0000 Subject: [PATCH 191/706] 8373086: Make isexceeded001.java more robust Reviewed-by: jsikstro, tschatzl --- test/hotspot/jtreg/ProblemList.txt | 6 ------ .../isUsageThresholdExceeded/isexceeded001.java | 3 ++- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index 6c3d907961d..ddc6e55dc05 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -187,9 +187,3 @@ vmTestbase/nsk/jdwp/ThreadReference/ForceEarlyReturn/forceEarlyReturn001/forceEa vmTestbase/nsk/monitoring/ThreadMXBean/ThreadInfo/Multi/Multi005/TestDescription.java 8076494 windows-x64 vmTestbase/nsk/monitoring/ThreadMXBean/findMonitorDeadlockedThreads/find006/TestDescription.java 8310144 macosx-aarch64 - -vmTestbase/nsk/monitoring/MemoryPoolMBean/isUsageThresholdExceeded/isexceeded001/TestDescription.java 8373022 generic-all -vmTestbase/nsk/monitoring/MemoryPoolMBean/isUsageThresholdExceeded/isexceeded002/TestDescription.java 8373022 generic-all -vmTestbase/nsk/monitoring/MemoryPoolMBean/isUsageThresholdExceeded/isexceeded003/TestDescription.java 8373022 generic-all -vmTestbase/nsk/monitoring/MemoryPoolMBean/isUsageThresholdExceeded/isexceeded004/TestDescription.java 8373022 generic-all -vmTestbase/nsk/monitoring/MemoryPoolMBean/isUsageThresholdExceeded/isexceeded005/TestDescription.java 8373022 generic-all diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/MemoryPoolMBean/isUsageThresholdExceeded/isexceeded001.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/MemoryPoolMBean/isUsageThresholdExceeded/isexceeded001.java index a684c03e67a..5fbb4d2444e 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/MemoryPoolMBean/isUsageThresholdExceeded/isexceeded001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/MemoryPoolMBean/isUsageThresholdExceeded/isexceeded001.java @@ -92,7 +92,8 @@ public class isexceeded001 { // but cannot assume this affects the pool we are testing. b = new byte[INCREMENT]; - isExceeded = monitor.isUsageThresholdExceeded(pool); + // Ensure the observation of isExceeded is sticky to match peakUsage. + isExceeded = isExceeded || monitor.isUsageThresholdExceeded(pool); log.display(" Allocated heap. isExceeded = " + isExceeded); // Fetch usage information: use peak usage in comparisons below, in case usage went up and then down. From 520c092a658559a5d65f06a51061db3aae09931e Mon Sep 17 00:00:00 2001 From: Neha Joshi Date: Fri, 5 Dec 2025 16:46:26 +0000 Subject: [PATCH 192/706] 8362658: sun/security/ssl/SSLEngineImpl/* tests duplicate jvm flags Co-authored-by: Lei Zhu Reviewed-by: myankelevich, rhalade --- test/jdk/ProblemList-jvmti-stress-agent.txt | 16 ---------------- .../ssl/SSLEngineImpl/SSLEngineKeyLimit.java | 5 +---- .../ssl/SSLSessionImpl/MultiNSTClient.java | 4 +--- .../MultiNSTNoSessionCreation.java | 3 +-- .../ssl/SSLSessionImpl/MultiNSTParallel.java | 4 +--- .../ssl/SSLSessionImpl/MultiNSTSequence.java | 4 +--- .../ResumptionUpdateBoundValues.java | 3 +-- .../ssl/SSLSocketImpl/SSLSocketKeyLimit.java | 4 +--- 8 files changed, 7 insertions(+), 36 deletions(-) diff --git a/test/jdk/ProblemList-jvmti-stress-agent.txt b/test/jdk/ProblemList-jvmti-stress-agent.txt index 4a6e80a9402..09be19c3d94 100644 --- a/test/jdk/ProblemList-jvmti-stress-agent.txt +++ b/test/jdk/ProblemList-jvmti-stress-agent.txt @@ -21,22 +21,6 @@ # questions. # -############################################################################# -# -# List of quarantined tests failing with jvmti stress agent in any mode. -# -############################################################################# - - -sun/security/ssl/SSLEngineImpl/SSLEngineKeyLimit.java 8362658 generic-all -sun/security/ssl/SSLSessionImpl/MultiNSTClient.java 8362658 generic-all -sun/security/ssl/SSLSessionImpl/MultiNSTNoSessionCreation.java 8362658 generic-all -sun/security/ssl/SSLSessionImpl/MultiNSTParallel.java 8362658 generic-all -sun/security/ssl/SSLSessionImpl/MultiNSTSequence.java 8362658 generic-all -sun/security/ssl/SSLSessionImpl/ResumptionUpdateBoundValues.java 8362658 generic-all -sun/security/ssl/SSLSocketImpl/SSLSocketKeyLimit.java 8362658 generic-all - - # List of tests incompatible with jvmti stress agent or requiring more investigation com/sun/jdi/EATests.java#id0 0000000 generic-all diff --git a/test/jdk/sun/security/ssl/SSLEngineImpl/SSLEngineKeyLimit.java b/test/jdk/sun/security/ssl/SSLEngineImpl/SSLEngineKeyLimit.java index 65311e97701..5a704ef4d1f 100644 --- a/test/jdk/sun/security/ssl/SSLEngineImpl/SSLEngineKeyLimit.java +++ b/test/jdk/sun/security/ssl/SSLEngineImpl/SSLEngineKeyLimit.java @@ -60,7 +60,6 @@ import java.util.Arrays; import jdk.test.lib.process.ProcessTools; import jdk.test.lib.process.OutputAnalyzer; -import jdk.test.lib.Utils; public class SSLEngineKeyLimit extends SSLContextTemplate { @@ -119,9 +118,7 @@ public class SSLEngineKeyLimit extends SSLContextTemplate { System.getProperty("test.java.opts")); ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( - Utils.addTestJavaOpts("SSLEngineKeyLimit", "p", args[1], - args[2])); - + "SSLEngineKeyLimit", "p", args[1], args[2]); OutputAnalyzer output = ProcessTools.executeProcess(pb); try { output.shouldContain(String.format( diff --git a/test/jdk/sun/security/ssl/SSLSessionImpl/MultiNSTClient.java b/test/jdk/sun/security/ssl/SSLSessionImpl/MultiNSTClient.java index d6cdbf2e015..1c9c259c38d 100644 --- a/test/jdk/sun/security/ssl/SSLSessionImpl/MultiNSTClient.java +++ b/test/jdk/sun/security/ssl/SSLSessionImpl/MultiNSTClient.java @@ -37,7 +37,6 @@ * @run main/othervm MultiNSTClient -Djdk.tls.client.protocols=TLSv1.2 -Djdk.tls.server.enableSessionTicketExtension=true -Djdk.tls.client.enableSessionTicketExtension=true */ -import jdk.test.lib.Utils; import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.process.ProcessTools; @@ -77,8 +76,7 @@ public class MultiNSTClient { System.out.println("test.java.opts: " + System.getProperty("test.java.opts")); - ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( - Utils.addTestJavaOpts("MultiNSTClient", "p")); + ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder("MultiNSTClient", "p"); OutputAnalyzer output = ProcessTools.executeProcess(pb); boolean pass = true; diff --git a/test/jdk/sun/security/ssl/SSLSessionImpl/MultiNSTNoSessionCreation.java b/test/jdk/sun/security/ssl/SSLSessionImpl/MultiNSTNoSessionCreation.java index 41f6ec0ada4..a851a5d72bb 100644 --- a/test/jdk/sun/security/ssl/SSLSessionImpl/MultiNSTNoSessionCreation.java +++ b/test/jdk/sun/security/ssl/SSLSessionImpl/MultiNSTNoSessionCreation.java @@ -31,7 +31,6 @@ * @run main/othervm MultiNSTNoSessionCreation -Djdk.tls.client.protocols=TLSv1.2 -Djdk.tls.server.newSessionTicketCount=0 */ -import jdk.test.lib.Utils; import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.process.ProcessTools; @@ -61,7 +60,7 @@ public class MultiNSTNoSessionCreation { System.getProperty("test.java.opts")); ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( - Utils.addTestJavaOpts("MultiNSTNoSessionCreation", "p")); + "MultiNSTNoSessionCreation", "p"); OutputAnalyzer output = ProcessTools.executeProcess(pb); try { diff --git a/test/jdk/sun/security/ssl/SSLSessionImpl/MultiNSTParallel.java b/test/jdk/sun/security/ssl/SSLSessionImpl/MultiNSTParallel.java index 32ee7db7b4b..a2609130e0b 100644 --- a/test/jdk/sun/security/ssl/SSLSessionImpl/MultiNSTParallel.java +++ b/test/jdk/sun/security/ssl/SSLSessionImpl/MultiNSTParallel.java @@ -30,7 +30,6 @@ * @run main/othervm MultiNSTParallel 10 -Djdk.tls.client.protocols=TLSv1.3 */ -import jdk.test.lib.Utils; import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.process.ProcessTools; @@ -116,8 +115,7 @@ public class MultiNSTParallel { System.out.println("test.java.opts: " + System.getProperty("test.java.opts")); - ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( - Utils.addTestJavaOpts("MultiNSTParallel", "p")); + ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder("MultiNSTParallel", "p"); OutputAnalyzer output = ProcessTools.executeProcess(pb); try { diff --git a/test/jdk/sun/security/ssl/SSLSessionImpl/MultiNSTSequence.java b/test/jdk/sun/security/ssl/SSLSessionImpl/MultiNSTSequence.java index 125b006055b..b63ebc5ec1e 100644 --- a/test/jdk/sun/security/ssl/SSLSessionImpl/MultiNSTSequence.java +++ b/test/jdk/sun/security/ssl/SSLSessionImpl/MultiNSTSequence.java @@ -30,7 +30,6 @@ * @run main/othervm MultiNSTSequence -Djdk.tls.server.newSessionTicketCount=2 */ -import jdk.test.lib.Utils; import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.process.ProcessTools; @@ -69,8 +68,7 @@ public class MultiNSTSequence { System.out.println("test.java.opts: " + System.getProperty("test.java.opts")); - ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( - Utils.addTestJavaOpts("MultiNSTSequence", "p")); + ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder("MultiNSTSequence", "p"); OutputAnalyzer output = ProcessTools.executeProcess(pb); boolean pass = true; diff --git a/test/jdk/sun/security/ssl/SSLSessionImpl/ResumptionUpdateBoundValues.java b/test/jdk/sun/security/ssl/SSLSessionImpl/ResumptionUpdateBoundValues.java index 87db7eed296..2784875d426 100644 --- a/test/jdk/sun/security/ssl/SSLSessionImpl/ResumptionUpdateBoundValues.java +++ b/test/jdk/sun/security/ssl/SSLSessionImpl/ResumptionUpdateBoundValues.java @@ -45,7 +45,6 @@ import javax.net.ssl.SSLSocketFactory; import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.process.ProcessTools; -import jdk.test.lib.Utils; public class ResumptionUpdateBoundValues extends SSLContextTemplate { @@ -188,7 +187,7 @@ public class ResumptionUpdateBoundValues extends SSLContextTemplate { System.getProperty("test.java.opts")); ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( - Utils.addTestJavaOpts("ResumptionUpdateBoundValues", "p")); + "ResumptionUpdateBoundValues", "p"); OutputAnalyzer output = ProcessTools.executeProcess(pb); try { diff --git a/test/jdk/sun/security/ssl/SSLSocketImpl/SSLSocketKeyLimit.java b/test/jdk/sun/security/ssl/SSLSocketImpl/SSLSocketKeyLimit.java index fc26b60e4d4..7ce4d97a7a2 100644 --- a/test/jdk/sun/security/ssl/SSLSocketImpl/SSLSocketKeyLimit.java +++ b/test/jdk/sun/security/ssl/SSLSocketImpl/SSLSocketKeyLimit.java @@ -68,7 +68,6 @@ import java.util.Arrays; import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.process.ProcessTools; -import jdk.test.lib.Utils; import jdk.test.lib.hexdump.HexPrinter; public class SSLSocketKeyLimit { @@ -135,8 +134,7 @@ public class SSLSocketKeyLimit { System.getProperty("test.java.opts")); ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( - Utils.addTestJavaOpts("SSLSocketKeyLimit", "p", args[1], - args[2])); + "SSLSocketKeyLimit", "p", args[1], args[2]); OutputAnalyzer output = ProcessTools.executeProcess(pb); try { From a20b7eb943c19f9852bfaaec1fbbff647f1f5273 Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Fri, 5 Dec 2025 17:35:30 +0000 Subject: [PATCH 193/706] 8373125: Add defensive screening of modifiers for Field and Parameter toString() results Reviewed-by: alanb, liach --- .../classes/java/lang/reflect/Field.java | 4 +- .../classes/java/lang/reflect/Parameter.java | 2 +- .../lang/reflect/Modifier/toStringTest.java | 63 ++++++++++++++----- 3 files changed, 52 insertions(+), 17 deletions(-) diff --git a/src/java.base/share/classes/java/lang/reflect/Field.java b/src/java.base/share/classes/java/lang/reflect/Field.java index 663e3453343..a4f0afa0199 100644 --- a/src/java.base/share/classes/java/lang/reflect/Field.java +++ b/src/java.base/share/classes/java/lang/reflect/Field.java @@ -367,7 +367,7 @@ class Field extends AccessibleObject implements Member { * @jls 8.3.1 Field Modifiers */ public String toString() { - int mod = getModifiers(); + int mod = getModifiers() & Modifier.fieldModifiers(); return (((mod == 0) ? "" : (Modifier.toString(mod) + " ")) + getType().getTypeName() + " " + getDeclaringClass().getTypeName() + "." @@ -400,7 +400,7 @@ class Field extends AccessibleObject implements Member { * @jls 8.3.1 Field Modifiers */ public String toGenericString() { - int mod = getModifiers(); + int mod = getModifiers() & Modifier.fieldModifiers(); Type fieldType = getGenericType(); return (((mod == 0) ? "" : (Modifier.toString(mod) + " ")) + fieldType.getTypeName() + " " diff --git a/src/java.base/share/classes/java/lang/reflect/Parameter.java b/src/java.base/share/classes/java/lang/reflect/Parameter.java index d4a53e193a9..8ecf8060615 100644 --- a/src/java.base/share/classes/java/lang/reflect/Parameter.java +++ b/src/java.base/share/classes/java/lang/reflect/Parameter.java @@ -126,7 +126,7 @@ public final class Parameter implements AnnotatedElement { final Type type = getParameterizedType(); final String typename = type.getTypeName(); - sb.append(Modifier.toString(getModifiers())); + sb.append(Modifier.toString(getModifiers() & Modifier.parameterModifiers() )); if(0 != modifiers) sb.append(' '); diff --git a/test/jdk/java/lang/reflect/Modifier/toStringTest.java b/test/jdk/java/lang/reflect/Modifier/toStringTest.java index 85bceb48339..f36d83f1ad8 100644 --- a/test/jdk/java/lang/reflect/Modifier/toStringTest.java +++ b/test/jdk/java/lang/reflect/Modifier/toStringTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, 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 @@ -23,36 +23,71 @@ /** * @test - * @bug 4394937 8051382 + * @bug 4394937 8051382 8373125 * @summary tests the toString method of reflect.Modifier */ import java.lang.reflect.Modifier; +import static java.lang.reflect.Modifier.*; public class toStringTest { static void testString(int test, String expected) { - if(!Modifier.toString(test).equals(expected)) - throw new RuntimeException(test + - " yields incorrect toString result"); + String result = Modifier.toString(test); + if(!expected.equals(result)) { + System.err.println("For input 0x" + Integer.toHexString(test)); + System.err.println("expected:\t" + expected + "\ngot\t\t" + result); + + throw new RuntimeException(); + } } - public static void main(String [] argv) { - int allMods = Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE | - Modifier.ABSTRACT | Modifier.STATIC | Modifier.FINAL | - Modifier.TRANSIENT | Modifier.VOLATILE | Modifier.SYNCHRONIZED | - Modifier.NATIVE | Modifier.STRICT | Modifier.INTERFACE; + public static void main(String... argv) { + int allMods = PUBLIC | PROTECTED | PRIVATE | + ABSTRACT | STATIC | FINAL | + TRANSIENT | VOLATILE | SYNCHRONIZED | + NATIVE | STRICT | INTERFACE; String allModsString = "public protected private abstract static " + "final transient volatile synchronized native strictfp interface"; - /* zero should have an empty string */ + final int ALL_ONES = ~0; + + // zero should have an empty string testString(0, ""); - /* test to make sure all modifiers print out in the proper order */ + // test to make sure all modifiers print out in the proper order testString(allMods, allModsString); - /* verify no extraneous modifiers are printed */ - testString(~0, allModsString); + // verify no extraneous modifiers are printed + testString(ALL_ONES, allModsString); + + ModifierKindCase[] kindModifiers = { + new ModifierKindCase(classModifiers(), + "public protected private abstract " + + "static final strictfp"), + + new ModifierKindCase(constructorModifiers(),"public protected private"), + + new ModifierKindCase(fieldModifiers(), + "public protected private " + + "static final transient volatile"), + + new ModifierKindCase(interfaceModifiers(), + "public protected private " + + "abstract static strictfp"), + + new ModifierKindCase(methodModifiers(), + "public protected private abstract " + + "static final synchronized native strictfp"), + + new ModifierKindCase(parameterModifiers(), "final"), + }; + + for (var modKindCase : kindModifiers) { + testString(ALL_ONES & modKindCase.mask(), modKindCase.expected()); + } } + + private record ModifierKindCase(int mask, String expected){} } From 43787890291d71de61b28b8a4e3bf9aaba46757a Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Fri, 5 Dec 2025 19:17:45 +0000 Subject: [PATCH 194/706] 8373145: [BACKOUT] Remove ThreadLocalAllocBuffer::_reserve_for_allocation_prefetch Reviewed-by: mdoerr, kvn --- src/hotspot/cpu/ppc/ppc.ad | 29 +++++++++++++++++++ .../gc/shared/threadLocalAllocBuffer.cpp | 28 +++++++++++++++++- .../gc/shared/threadLocalAllocBuffer.hpp | 1 + src/hotspot/share/opto/macro.cpp | 3 +- src/hotspot/share/runtime/vmStructs.cpp | 1 + .../runtime/ThreadLocalAllocBuffer.java | 3 +- .../classes/sun/jvm/hotspot/runtime/VM.java | 7 +++++ 7 files changed, 69 insertions(+), 3 deletions(-) diff --git a/src/hotspot/cpu/ppc/ppc.ad b/src/hotspot/cpu/ppc/ppc.ad index aa00609094e..2a0a9149bb3 100644 --- a/src/hotspot/cpu/ppc/ppc.ad +++ b/src/hotspot/cpu/ppc/ppc.ad @@ -6335,8 +6335,36 @@ instruct loadConD_Ex(regD dst, immD src) %{ // Prefetch instructions. // Must be safe to execute with invalid address (cannot fault). +// Special prefetch versions which use the dcbz instruction. +instruct prefetch_alloc_zero(indirectMemory mem, iRegLsrc src) %{ + match(PrefetchAllocation (AddP mem src)); + predicate(AllocatePrefetchStyle == 3); + ins_cost(MEMORY_REF_COST); + + format %{ "PREFETCH $mem, 2, $src \t// Prefetch write-many with zero" %} + size(4); + ins_encode %{ + __ dcbz($src$$Register, $mem$$base$$Register); + %} + ins_pipe(pipe_class_memory); +%} + +instruct prefetch_alloc_zero_no_offset(indirectMemory mem) %{ + match(PrefetchAllocation mem); + predicate(AllocatePrefetchStyle == 3); + ins_cost(MEMORY_REF_COST); + + format %{ "PREFETCH $mem, 2 \t// Prefetch write-many with zero" %} + size(4); + ins_encode %{ + __ dcbz($mem$$base$$Register); + %} + ins_pipe(pipe_class_memory); +%} + instruct prefetch_alloc(indirectMemory mem, iRegLsrc src) %{ match(PrefetchAllocation (AddP mem src)); + predicate(AllocatePrefetchStyle != 3); ins_cost(MEMORY_REF_COST); format %{ "PREFETCH $mem, 2, $src \t// Prefetch write-many" %} @@ -6349,6 +6377,7 @@ instruct prefetch_alloc(indirectMemory mem, iRegLsrc src) %{ instruct prefetch_alloc_no_offset(indirectMemory mem) %{ match(PrefetchAllocation mem); + predicate(AllocatePrefetchStyle != 3); ins_cost(MEMORY_REF_COST); format %{ "PREFETCH $mem, 2 \t// Prefetch write-many" %} diff --git a/src/hotspot/share/gc/shared/threadLocalAllocBuffer.cpp b/src/hotspot/share/gc/shared/threadLocalAllocBuffer.cpp index 2181e089663..9635ed4d0cb 100644 --- a/src/hotspot/share/gc/shared/threadLocalAllocBuffer.cpp +++ b/src/hotspot/share/gc/shared/threadLocalAllocBuffer.cpp @@ -37,6 +37,7 @@ #include "utilities/copy.hpp" size_t ThreadLocalAllocBuffer::_max_size = 0; +int ThreadLocalAllocBuffer::_reserve_for_allocation_prefetch = 0; unsigned int ThreadLocalAllocBuffer::_target_refills = 0; ThreadLocalAllocBuffer::ThreadLocalAllocBuffer() : @@ -224,6 +225,30 @@ void ThreadLocalAllocBuffer::startup_initialization() { // abort during VM initialization. _target_refills = MAX2(_target_refills, 2U); +#ifdef COMPILER2 + // If the C2 compiler is present, extra space is needed at the end of + // TLABs, otherwise prefetching instructions generated by the C2 + // compiler will fault (due to accessing memory outside of heap). + // The amount of space is the max of the number of lines to + // prefetch for array and for instance allocations. (Extra space must be + // reserved to accommodate both types of allocations.) + // + // Only SPARC-specific BIS instructions are known to fault. (Those + // instructions are generated if AllocatePrefetchStyle==3 and + // AllocatePrefetchInstr==1). To be on the safe side, however, + // extra space is reserved for all combinations of + // AllocatePrefetchStyle and AllocatePrefetchInstr. + // + // If the C2 compiler is not present, no space is reserved. + + // +1 for rounding up to next cache line, +1 to be safe + if (CompilerConfig::is_c2_or_jvmci_compiler_enabled()) { + int lines = MAX2(AllocatePrefetchLines, AllocateInstancePrefetchLines) + 2; + _reserve_for_allocation_prefetch = (AllocatePrefetchDistance + AllocatePrefetchStepSize * lines) / + (int)HeapWordSize; + } +#endif + // During jvm startup, the main thread is initialized // before the heap is initialized. So reinitialize it now. guarantee(Thread::current()->is_Java_thread(), "tlab initialization thread not Java thread"); @@ -429,7 +454,8 @@ void ThreadLocalAllocStats::publish() { } size_t ThreadLocalAllocBuffer::end_reserve() { - return CollectedHeap::lab_alignment_reserve(); + size_t reserve_size = CollectedHeap::lab_alignment_reserve(); + return MAX2(reserve_size, (size_t)_reserve_for_allocation_prefetch); } const HeapWord* ThreadLocalAllocBuffer::start_relaxed() const { diff --git a/src/hotspot/share/gc/shared/threadLocalAllocBuffer.hpp b/src/hotspot/share/gc/shared/threadLocalAllocBuffer.hpp index b64fa8d6ad1..59979646395 100644 --- a/src/hotspot/share/gc/shared/threadLocalAllocBuffer.hpp +++ b/src/hotspot/share/gc/shared/threadLocalAllocBuffer.hpp @@ -58,6 +58,7 @@ private: size_t _allocated_before_last_gc; // total bytes allocated up until the last gc static size_t _max_size; // maximum size of any TLAB + static int _reserve_for_allocation_prefetch; // Reserve at the end of the TLAB static unsigned _target_refills; // expected number of refills between GCs unsigned _number_of_refills; diff --git a/src/hotspot/share/opto/macro.cpp b/src/hotspot/share/opto/macro.cpp index 6f2171bbd75..90602bc2b35 100644 --- a/src/hotspot/share/opto/macro.cpp +++ b/src/hotspot/share/opto/macro.cpp @@ -1914,7 +1914,8 @@ Node* PhaseMacroExpand::prefetch_allocation(Node* i_o, Node*& needgc_false, transform_later(cache_adr); cache_adr = new CastP2XNode(needgc_false, cache_adr); transform_later(cache_adr); - // Address is aligned to execute prefetch to the beginning of cache line size. + // Address is aligned to execute prefetch to the beginning of cache line size + // (it is important when BIS instruction is used on SPARC as prefetch). Node* mask = _igvn.MakeConX(~(intptr_t)(step_size-1)); cache_adr = new AndXNode(cache_adr, mask); transform_later(cache_adr); diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp index 50748fd7e45..4ecc8f9ca01 100644 --- a/src/hotspot/share/runtime/vmStructs.cpp +++ b/src/hotspot/share/runtime/vmStructs.cpp @@ -353,6 +353,7 @@ nonstatic_field(ThreadLocalAllocBuffer, _pf_top, HeapWord*) \ nonstatic_field(ThreadLocalAllocBuffer, _desired_size, size_t) \ nonstatic_field(ThreadLocalAllocBuffer, _refill_waste_limit, size_t) \ + static_field(ThreadLocalAllocBuffer, _reserve_for_allocation_prefetch, int) \ static_field(ThreadLocalAllocBuffer, _target_refills, unsigned) \ nonstatic_field(ThreadLocalAllocBuffer, _number_of_refills, unsigned) \ nonstatic_field(ThreadLocalAllocBuffer, _refill_waste, unsigned) \ diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ThreadLocalAllocBuffer.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ThreadLocalAllocBuffer.java index e23e63806bd..1dc67330d3d 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ThreadLocalAllocBuffer.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ThreadLocalAllocBuffer.java @@ -76,9 +76,10 @@ public class ThreadLocalAllocBuffer extends VMObject { private long endReserve() { long labAlignmentReserve = VM.getVM().getLabAlignmentReserve(); + long reserveForAllocationPrefetch = VM.getVM().getReserveForAllocationPrefetch(); long heapWordSize = VM.getVM().getHeapWordSize(); - return labAlignmentReserve * heapWordSize; + return Math.max(labAlignmentReserve, reserveForAllocationPrefetch) * heapWordSize; } /** Support for iteration over heap -- not sure how this will diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VM.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VM.java index 1607563150a..dc27a4fc59e 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VM.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VM.java @@ -123,6 +123,7 @@ public class VM { private int invocationEntryBCI; private ReversePtrs revPtrs; private VMRegImpl vmregImpl; + private int reserveForAllocationPrefetch; private int labAlignmentReserve; // System.getProperties from debuggee VM @@ -446,6 +447,8 @@ public class VM { boolType = (CIntegerType) db.lookupType("bool"); Type threadLocalAllocBuffer = db.lookupType("ThreadLocalAllocBuffer"); + CIntegerField reserveForAllocationPrefetchField = threadLocalAllocBuffer.getCIntegerField("_reserve_for_allocation_prefetch"); + reserveForAllocationPrefetch = (int)reserveForAllocationPrefetchField.getCInteger(intType); Type collectedHeap = db.lookupType("CollectedHeap"); CIntegerField labAlignmentReserveField = collectedHeap.getCIntegerField("_lab_alignment_reserve"); @@ -912,6 +915,10 @@ public class VM { return vmInternalInfo; } + public int getReserveForAllocationPrefetch() { + return reserveForAllocationPrefetch; + } + public int getLabAlignmentReserve() { return labAlignmentReserve; } From f3dd8daaa92896be51254e5abf3e0ec5b1ff5173 Mon Sep 17 00:00:00 2001 From: Brent Christian Date: Fri, 5 Dec 2025 19:30:04 +0000 Subject: [PATCH 195/706] 8371748: Remove the (empty) ThreadPoolExecutor.finalize() method Reviewed-by: vklang, jpai, alanb --- .../util/concurrent/ThreadPoolExecutor.java | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/src/java.base/share/classes/java/util/concurrent/ThreadPoolExecutor.java b/src/java.base/share/classes/java/util/concurrent/ThreadPoolExecutor.java index 029e31ef9f6..b45b6eac83e 100644 --- a/src/java.base/share/classes/java/util/concurrent/ThreadPoolExecutor.java +++ b/src/java.base/share/classes/java/util/concurrent/ThreadPoolExecutor.java @@ -1426,23 +1426,6 @@ public class ThreadPoolExecutor extends AbstractExecutorService { } } - // Override without "throws Throwable" for compatibility with subclasses - // whose finalize method invokes super.finalize() (as is recommended). - // Before JDK 11, finalize() had a non-empty method body. - - /** - * @implNote Previous versions of this class had a finalize method - * that shut down this executor, but in this version, finalize - * does nothing. - * - * @deprecated Finalization has been deprecated for removal. See - * {@link java.lang.Object#finalize} for background information and details - * about migration options. - */ - @Deprecated(since="9", forRemoval=true) - @SuppressWarnings("removal") - protected void finalize() {} - /** * Sets the thread factory used to create new threads. * From be8cbfa6129d19403c9871c22721b902856f1886 Mon Sep 17 00:00:00 2001 From: Chris Plummer Date: Fri, 5 Dec 2025 20:37:10 +0000 Subject: [PATCH 196/706] 8362083: JDI VirtualMachine/dispose/dispose001 failed with FATAL ERROR in native method: JDWP cannot set thread local storage, jvmtiError=JVMTI_ERROR_WRONG_PHASE(112) Reviewed-by: lmesnik, sspitsyn, amenkov --- src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c b/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c index 734dd5eb7dc..8a02f3f9ee9 100644 --- a/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c +++ b/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c @@ -170,6 +170,10 @@ setThreadLocalStorage(jthread thread, ThreadNode *node) return; } } + if (error == JVMTI_ERROR_WRONG_PHASE && gdata->vmDead && isVThread(thread)) { + // Just return. This can happen with vthreads when the vm is exiting. + return; + } if (error != JVMTI_ERROR_NONE) { // The jthread object must be valid, so this must be a fatal error. EXIT_ERROR(error, "cannot set thread local storage"); From 2596608ba1bb1b271dfa062bf732a5095e22fffd Mon Sep 17 00:00:00 2001 From: Leonid Mesnik Date: Fri, 5 Dec 2025 21:20:20 +0000 Subject: [PATCH 197/706] 8370846: Support execution of mlvm testing with test thread factory Reviewed-by: cjplummer --- .../vm/mlvm/share/jdi/JDIBreakpointTest.java | 17 +++++++++++-- .../test/lib/thread/TestThreadFactory.java | 25 ++++++++++++++++--- 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/test/hotspot/jtreg/vmTestbase/vm/mlvm/share/jdi/JDIBreakpointTest.java b/test/hotspot/jtreg/vmTestbase/vm/mlvm/share/jdi/JDIBreakpointTest.java index 29980ac2117..2b3f5a479b6 100644 --- a/test/hotspot/jtreg/vmTestbase/vm/mlvm/share/jdi/JDIBreakpointTest.java +++ b/test/hotspot/jtreg/vmTestbase/vm/mlvm/share/jdi/JDIBreakpointTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2025, 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.util.HashMap; import java.util.List; import java.util.Map; +import jdk.test.lib.thread.TestThreadFactory; import nsk.share.jdi.Binder; import nsk.share.jdi.Debugee; import vm.mlvm.share.Env; @@ -437,10 +438,22 @@ public abstract class JDIBreakpointTest extends MlvmTest { for (StackFrame f : frames) { Location l = f.location(); + String sourcePath; + try { + sourcePath = l.sourcePath(); + } catch (AbsentInformationException aie) { + // Test Thread Factory support has generated methods in MainWrapper class. + if (TestThreadFactory.isTestThreadFactorySet()) { + sourcePath = "unknown"; + } else { + throw aie; + } + } + buf.append(String.format("#%-4d", frameNum)) .append(l.method()) .append("\n source: ") - .append(l.sourcePath()) + .append(sourcePath) .append(":") .append(l.lineNumber()) .append("; bci=") diff --git a/test/lib/jdk/test/lib/thread/TestThreadFactory.java b/test/lib/jdk/test/lib/thread/TestThreadFactory.java index ac5a6b74909..043c96cf284 100644 --- a/test/lib/jdk/test/lib/thread/TestThreadFactory.java +++ b/test/lib/jdk/test/lib/thread/TestThreadFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, 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,8 +32,27 @@ import java.util.concurrent.ThreadFactory; public class TestThreadFactory { - private static ThreadFactory threadFactory = "Virtual".equals(System.getProperty("test.thread.factory")) - ? virtualThreadFactory() : platformThreadFactory(); + public enum TestThreadFactoryType { + NONE, VIRTUAL + } + + private final static TestThreadFactoryType testThreadFactoryType = + "Virtual".equals(System.getProperty("test.thread.factory")) + ? TestThreadFactoryType.VIRTUAL + : TestThreadFactoryType.NONE; + + private final static ThreadFactory threadFactory = + testThreadFactoryType == TestThreadFactoryType.VIRTUAL + ? virtualThreadFactory() + : platformThreadFactory(); + + public static TestThreadFactoryType testThreadFactoryType() { + return testThreadFactoryType; + } + + public static boolean isTestThreadFactorySet() { + return !testThreadFactoryType.equals(TestThreadFactoryType.NONE); + } public static Thread newThread(Runnable task) { return threadFactory.newThread(task); From b0f59f6021a00dc569e08810b34db21553a5b68d Mon Sep 17 00:00:00 2001 From: Leonid Mesnik Date: Sat, 6 Dec 2025 00:02:51 +0000 Subject: [PATCH 198/706] 8373127: Update nsk/monitoring tests to support virtual thread factory testing Reviewed-by: kevinw, amenkov --- .../from/from001/TestDescription.java | 3 +- .../from_c/from_c001/TestDescription.java | 3 +- .../getlockname001/TestDescription.java | 3 +- .../getlockownername001/TestDescription.java | 3 +- .../isinnative001/TestDescription.java | 3 +- .../BaseBehaviorTest.java | 70 +++++++++++++------ .../GetThreadCpuTime/BaseBehaviorTest.java | 42 +++++++---- 7 files changed, 87 insertions(+), 40 deletions(-) diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/MemoryUsage/from/from001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/MemoryUsage/from/from001/TestDescription.java index a066b636bb3..083e91243e8 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/MemoryUsage/from/from001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/MemoryUsage/from/from001/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, 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,6 +43,7 @@ * 5014783 Move ThreadState class from java.lang.management to java.lang * 5024531 Fix MBeans design flaw that restricts to use JMX CompositeData * + * @requires test.thread.factory != "Virtual" * @library /vmTestbase * /test/lib * @run main/othervm nsk.monitoring.MemoryUsage.from.from001 -testMode=server diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadInfo/from_c/from_c001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadInfo/from_c/from_c001/TestDescription.java index 9ff6e066fe1..6483673deef 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadInfo/from_c/from_c001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadInfo/from_c/from_c001/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, 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,6 +43,7 @@ * 5014783 Move ThreadState class from java.lang.management to java.lang * 5024531 Fix MBeans design flaw that restricts to use JMX CompositeData * + * @requires test.thread.factory != "Virtual" * @library /vmTestbase * /test/lib * @run main/othervm nsk.monitoring.ThreadInfo.from_c.from_c001 -testMode=server -MBeanServer=custom diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadInfo/getLockName/getlockname001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadInfo/getLockName/getlockname001/TestDescription.java index 571f121beac..8e956e98929 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadInfo/getLockName/getlockname001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadInfo/getLockName/getlockname001/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, 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,6 +47,7 @@ * Updated according to: * 5024531 Fix MBeans design flaw that restricts to use JMX CompositeData * + * @requires test.thread.factory != "Virtual" * @library /vmTestbase * /test/lib * @run main/othervm nsk.monitoring.ThreadInfo.getLockName.getlockname001 diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadInfo/getLockOwnerName/getlockownername001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadInfo/getLockOwnerName/getlockownername001/TestDescription.java index 1b2e7d90eb2..0cc78a6ad97 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadInfo/getLockOwnerName/getlockownername001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadInfo/getLockOwnerName/getlockownername001/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, 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 @@ -42,6 +42,7 @@ * Updated according to: * 5024531 Fix MBeans design flaw that restricts to use JMX CompositeData * + * @requires test.thread.factory != "Virtual" * @library /vmTestbase * /test/lib * @run main/othervm nsk.monitoring.ThreadInfo.getLockOwnerName.getlockownername001 diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadInfo/isInNative/isinnative001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadInfo/isInNative/isinnative001/TestDescription.java index a411958c852..3cce37baa4d 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadInfo/isInNative/isinnative001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadInfo/isInNative/isinnative001/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, 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,6 +41,7 @@ * Updated according to: * 5024531 Fix MBeans design flaw that restricts to use JMX CompositeData * + * @requires test.thread.factory != "Virtual" * @library /vmTestbase * /test/lib * @run main/othervm nsk.monitoring.ThreadInfo.isInNative.isinnative001 diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadMXBean/GetThreadAllocatedBytes/BaseBehaviorTest.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadMXBean/GetThreadAllocatedBytes/BaseBehaviorTest.java index bc0af5ae1cd..c338d392416 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadMXBean/GetThreadAllocatedBytes/BaseBehaviorTest.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadMXBean/GetThreadAllocatedBytes/BaseBehaviorTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2025, 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 @@ -59,16 +59,30 @@ public class BaseBehaviorTest extends ThreadMXBeanTestBase { + "return -1 if ThreadAllocatedMemoryEnabled is set to false. " + "Received : " + result); threadMXBean.setThreadAllocatedMemoryEnabled(true); - // Expect >= 0 value for current thread + // Expect >= 0 value for current platform thread. result = threadMXBean.getCurrentThreadAllocatedBytes(); - if (result < 0) - throw new TestFailure("Failure! getCurrentThreadAllocatedBytes() should " - + "return >= 0 value for current thread. Received : " + result); - // Expect >= 0 value for current thread from getThreadAllocatedBytes(id) + if (Thread.currentThread().isVirtual()) { + if (result != -1) + throw new TestFailure("Failure! getCurrentThreadAllocatedBytes() should " + + "return -1 for virtual thread. " + + "Received : " + result); + } else { + if (result < 0) + throw new TestFailure("Failure! getCurrentThreadAllocatedBytes() should " + + "return >= 0 value for current thread. Received : " + result); + } + // Expect >= 0 value for current iplatform thread from getThreadAllocatedBytes(id). result = threadMXBean.getThreadAllocatedBytes(Thread.currentThread().getId()); - if (result < 0) - throw new TestFailure("Failure! getThreadAllocatedBytes(id) should " - + "return >= 0 value for current thread. Received : " + result); + if (Thread.currentThread().isVirtual()) { + if (result != -1) + throw new TestFailure("Failure! getThreadAllocatedBytes(id) should " + + "return -1 for virtual thread. " + + "Received : " + result); + } else { + if (result < 0) + throw new TestFailure("Failure! getThreadAllocatedBytes(id) should " + + "return >= 0 value for current thread. Received : " + result); + } MXBeanTestThread thread = new MXBeanTestThread(); long id = thread.getId(); @@ -79,11 +93,11 @@ public class BaseBehaviorTest extends ThreadMXBeanTestBase { result = threadMXBean.getThreadAllocatedBytes(id); if (result != -1) throw new TestFailure("Failure! getThreadAllocatedBytes(long id) should " - + "return -1 for not started threads. Recieved : " + result); + + "return -1 for not started threads. Received : " + result); resultArr = threadMXBean.getThreadAllocatedBytes(idArr); if (resultArr[0] != -1) throw new TestFailure("Failure! getThreadAllocatedBytes(long[] ids) should " - + "return -1 for not started threads. Recieved : " + resultArr[0]); + + "return -1 for not started threads. Received : " + resultArr[0]); BarrierHandler handler = startThreads(thread); try { handler.proceed(); @@ -93,23 +107,37 @@ public class BaseBehaviorTest extends ThreadMXBeanTestBase { if (result != -1) throw new TestFailure("Failure! getThreadAllocatedBytes(long id) should " + "return -1 if ThreadAllocatedMemoryEnabled is set to false. " - + "Recieved : " + result); + + "Received : " + result); resultArr = threadMXBean.getThreadAllocatedBytes(idArr); if (resultArr[0] != -1) throw new TestFailure("Failure! getThreadAllocatedBytes(long[] ids) should " + "return -1 if ThreadAllocatedMemoryEnabled is set to false. " - + "Recieved : " + resultArr[0]); + + "Received : " + resultArr[0]); threadMXBean.setThreadAllocatedMemoryEnabled(true); // Expect >= 0 value for running threads result = threadMXBean.getThreadAllocatedBytes(id); - if (result < 0) - throw new TestFailure("Failure! getThreadAllocatedBytes(long id) should " - + "return > 0 value for RUNNING thread. Recieved : " + result); + if (thread.isVirtual()) { + if (result != -1) + throw new TestFailure("Failure! getThreadAllocatedBytes(long id) should " + + "return -1 for virtual thread. " + + "Received : " + result); + } else { + if (result < 0) + throw new TestFailure("Failure! getThreadAllocatedBytes(long id) should " + + "return > 0 value for RUNNING thread. Received : " + result); + } resultArr = threadMXBean.getThreadAllocatedBytes(idArr); - if (resultArr[0] < 0) - throw new TestFailure("Failure! getThreadAllocatedBytes(long[] ids) should " - + "return > 0 value for RUNNING thread. Recieved : " + resultArr[0]); + if (thread.isVirtual()) { + if (resultArr[0] != -1) + throw new TestFailure("Failure! getThreadAllocatedBytes(long[] ids) should " + + "return -1 for virtual thread. " + + "Received : " + resultArr[0]); + } else { + if (resultArr[0] < 0) + throw new TestFailure("Failure! getThreadAllocatedBytes(long[] ids) should " + + "return > 0 value for RUNNING thread. Received : " + resultArr[0]); + } } finally { // Let thread finish handler.finish(); @@ -121,11 +149,11 @@ public class BaseBehaviorTest extends ThreadMXBeanTestBase { result = threadMXBean.getThreadAllocatedBytes(id); if (result != -1) throw new TestFailure("Failure! getThreadAllocatedBytes(long id) should " - + "return -1 for finished threads. Recieved : " + result); + + "return -1 for finished threads. Received : " + result); resultArr = threadMXBean.getThreadAllocatedBytes(idArr); if (resultArr[0] != -1) throw new TestFailure("Failure! getThreadAllocatedBytes(long[] ids) should " - + "return -1 for finished threads. Recieved : " + resultArr[0]); + + "return -1 for finished threads. Received : " + resultArr[0]); log.info("BaseBehaviorTest passed."); } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadMXBean/GetThreadCpuTime/BaseBehaviorTest.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadMXBean/GetThreadCpuTime/BaseBehaviorTest.java index 5a16a1ba815..d639ba8b825 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadMXBean/GetThreadCpuTime/BaseBehaviorTest.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadMXBean/GetThreadCpuTime/BaseBehaviorTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2025, 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 @@ -57,11 +57,11 @@ public class BaseBehaviorTest extends ThreadMXBeanTestBase { resultArr = threadMXBean.getThreadCpuTime(idArr); if (resultArr[0] != -1) throw new TestFailure("Failure! getThreadCpuTime(long[] ids) should " - + "return -1 for not started threads. Recieved : " + resultArr[0]); + + "return -1 for not started threads. Received : " + resultArr[0]); resultArr = threadMXBean.getThreadUserTime(idArr); if (resultArr[0] != -1) throw new TestFailure("Failure! getThreadUserTime(long[] ids) should " - + "return -1 for not started threads. Recieved : " + resultArr[0]); + + "return -1 for not started threads. Received : " + resultArr[0]); BarrierHandler handler = startThreads(thread); try { handler.proceed(); @@ -71,22 +71,36 @@ public class BaseBehaviorTest extends ThreadMXBeanTestBase { if (resultArr[0] != -1) throw new TestFailure("Failure! getThreadCpuTime(long[] ids) should " + "return -1 if threadCpuTimeEnabled is set to false. " - + "Recieved : " + resultArr[0]); + + "Received : " + resultArr[0]); resultArr = threadMXBean.getThreadUserTime(idArr); if (resultArr[0] != -1) throw new TestFailure("Failure! getThreadUserTime(long[] ids) should " + "return -1 if threadCpuTimeEnabled is set to false. " - + "Recieved : " + resultArr[0]); + + "Received : " + resultArr[0]); threadMXBean.setThreadCpuTimeEnabled(true); - // Expect > 0 value for running threads + // Expect > 0 value for running platform threads and -1 for virtual threads. resultArr = threadMXBean.getThreadCpuTime(idArr); - if (resultArr[0] < 0) - throw new TestFailure("Failure! getThreadCpuTime(long[] ids) should " - + "return > 0 value for RUNNING thread. Recieved : " + resultArr[0]); + if (thread.isVirtual()) { + if (resultArr[0] != -1) + throw new TestFailure("Failure! getThreadCpuTime(long[] ids) should " + + "return -1 for virtual threads." + + "Received : " + resultArr[0]); + } else { + if (resultArr[0] < 0) + throw new TestFailure("Failure! getThreadCpuTime(long[] ids) should " + + "return > 0 value for RUNNING thread. Received : " + resultArr[0]); + } resultArr = threadMXBean.getThreadUserTime(idArr); - if (resultArr[0] < 0) - throw new TestFailure("Failure! getThreadUserTime(long[] ids) should " - + "return > 0 value for RUNNING thread. Recieved : " + resultArr[0]); + if (thread.isVirtual()) { + if (resultArr[0] != -1) + throw new TestFailure("Failure! getThreadUserTime(long[] ids) should " + + "return -1 for virtual threads." + + "Received : " + resultArr[0]); + } else { + if (resultArr[0] < 0) + throw new TestFailure("Failure! getThreadUserTime(long[] ids) should " + + "return > 0 value for RUNNING thread. Received : " + resultArr[0]); + } } finally { // Let thread finish handler.finish(); @@ -98,11 +112,11 @@ public class BaseBehaviorTest extends ThreadMXBeanTestBase { resultArr = threadMXBean.getThreadCpuTime(idArr); if (resultArr[0] != -1) throw new TestFailure("Failure! getThreadCpuTime(long[] ids) should " - + "return -1 for finished threads. Recieved : " + resultArr[0]); + + "return -1 for finished threads. Received : " + resultArr[0]); resultArr = threadMXBean.getThreadUserTime(idArr); if (resultArr[0] != -1) throw new TestFailure("Failure! getThreadUserTime(long[] ids) should " - + "return -1 for finished threads. Recieved : " + resultArr[0]); + + "return -1 for finished threads. Received : " + resultArr[0]); log.info("BaseBehaviorTest passed."); } From 5f083abafc7abfaa46ddd053668cdfbfd2ad8a87 Mon Sep 17 00:00:00 2001 From: Patrick Strawderman Date: Sat, 6 Dec 2025 15:34:14 +0000 Subject: [PATCH 199/706] 8179918: EnumSet spliterator should report SORTED, ORDERED, NONNULL Reviewed-by: vklang --- .../share/classes/java/util/EnumSet.java | 8 +- .../util/EnumSet/EnumSetSpliteratorTest.java | 97 +++++++++++++++++++ 2 files changed, 104 insertions(+), 1 deletion(-) create mode 100644 test/jdk/java/util/EnumSet/EnumSetSpliteratorTest.java diff --git a/src/java.base/share/classes/java/util/EnumSet.java b/src/java.base/share/classes/java/util/EnumSet.java index 55219c98469..e8dee28fa33 100644 --- a/src/java.base/share/classes/java/util/EnumSet.java +++ b/src/java.base/share/classes/java/util/EnumSet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, 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 @@ -501,4 +501,10 @@ public abstract sealed class EnumSet> extends AbstractSet throws java.io.InvalidObjectException { throw new java.io.InvalidObjectException("Proxy required"); } + + @Override + public Spliterator spliterator() { + return Spliterators.spliterator(this, + Spliterator.DISTINCT | Spliterator.SORTED | Spliterator.ORDERED | Spliterator.NONNULL); + } } diff --git a/test/jdk/java/util/EnumSet/EnumSetSpliteratorTest.java b/test/jdk/java/util/EnumSet/EnumSetSpliteratorTest.java new file mode 100644 index 00000000000..eee38846683 --- /dev/null +++ b/test/jdk/java/util/EnumSet/EnumSetSpliteratorTest.java @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2025, 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 + * @run junit EnumSetSpliteratorTest + * @bug 8179918 + * @summary EnumSet spliterator should report SORTED, ORDERED, NONNULL + */ + +import java.util.EnumSet; +import java.util.List; +import java.util.Spliterator; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class EnumSetSpliteratorTest { + + private enum Empty {} + + private enum Small { + a, b, c, d + } + + private enum Large { + e00, e01, e02, e03, e04, e05, e06, e07, + e08, e09, e0A, e0B, e0C, e0D, e0E, e0F, + e10, e11, e12, e13, e14, e15, e16, e17, + e18, e19, e1A, e1B, e1C, e1D, e1E, e1F, + e20, e21, e22, e23, e24, e25, e26, e27, + e28, e29, e2A, e2B, e2C, e2D, e2E, e2F, + e30, e31, e32, e33, e34, e35, e36, e37, + e38, e39, e3A, e3B, e3C, e3D, e3E, e3F, + e40, e41, e42, e43, e44, e45, e46, e47, + e48, e49, e4A, e4B, e4C, e4D, e4E, e4F + } + + @Test + public void testSpliteratorCharacteristics() { + assertSpliteratorCharacteristics(EnumSet.allOf(Empty.class)); + assertSpliteratorCharacteristics(EnumSet.allOf(Small.class)); + assertSpliteratorCharacteristics(EnumSet.allOf(Large.class)); + assertSpliteratorCharacteristics(EnumSet.noneOf(Empty.class)); + assertSpliteratorCharacteristics(EnumSet.noneOf(Small.class)); + assertSpliteratorCharacteristics(EnumSet.noneOf(Large.class)); + assertSpliteratorCharacteristics(EnumSet.of(Small.a, Small.d)); + assertSpliteratorCharacteristics(EnumSet.range(Small.a, Small.c)); + assertSpliteratorCharacteristics(EnumSet.range(Large.e02, Large.e4D)); + assertSpliteratorCharacteristics(EnumSet.complementOf(EnumSet.of(Small.c))); + assertSpliteratorCharacteristics(EnumSet.complementOf(EnumSet.of(Large.e00, Large.e4F))); + } + + @Test + public void testEncounterOrder() { + assertEquals(List.of(Small.values()), EnumSet.allOf(Small.class).stream().toList()); + assertEquals(List.of(Large.values()), EnumSet.allOf(Large.class).stream().toList()); + } + + private static final int EXPECTED_CHARACTERISTICS = ( + Spliterator.DISTINCT | Spliterator.SORTED | Spliterator.ORDERED | + Spliterator.NONNULL | Spliterator.SIZED | Spliterator.SUBSIZED); + + private static void assertSpliteratorCharacteristics(EnumSet enumSet) { + Spliterator spliterator = enumSet.spliterator(); + assertTrue(spliterator.hasCharacteristics(Spliterator.DISTINCT), "Missing DISTINCT"); + assertTrue(spliterator.hasCharacteristics(Spliterator.SORTED), "Missing SORTED"); + assertTrue(spliterator.hasCharacteristics(Spliterator.ORDERED), "Missing ORDERED"); + assertTrue(spliterator.hasCharacteristics(Spliterator.NONNULL), "Missing NONNULL"); + assertTrue(spliterator.hasCharacteristics(Spliterator.SIZED), "Missing SIZED"); + assertTrue(spliterator.hasCharacteristics(Spliterator.SUBSIZED), "Missing SUBSIZED"); + assertEquals(EXPECTED_CHARACTERISTICS, spliterator.characteristics(), "Unexpected characteristics"); + } +} \ No newline at end of file From 7da91533aaf2033cedee6e2a56fb693f26909df5 Mon Sep 17 00:00:00 2001 From: Sergey Chernyshev Date: Mon, 8 Dec 2025 09:06:21 +0000 Subject: [PATCH 200/706] 8369950: TLS connection to IPv6 address fails with BCJSSE due to IllegalArgumentException Co-authored-by: Mikhail Yankelevich Reviewed-by: djelinski, vyazici, dfuchs, myankelevich --- .../net/www/protocol/https/HttpsClient.java | 11 +- .../HttpsURLConnection/SubjectAltNameIP.java | 379 ++++++++++++++++++ 2 files changed, 388 insertions(+), 2 deletions(-) create mode 100644 test/jdk/javax/net/ssl/HttpsURLConnection/SubjectAltNameIP.java diff --git a/src/java.base/share/classes/sun/net/www/protocol/https/HttpsClient.java b/src/java.base/share/classes/sun/net/www/protocol/https/HttpsClient.java index 2f011f5805b..9f1d7b07021 100644 --- a/src/java.base/share/classes/sun/net/www/protocol/https/HttpsClient.java +++ b/src/java.base/share/classes/sun/net/www/protocol/https/HttpsClient.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, 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 @@ -44,6 +44,7 @@ import java.util.Objects; import java.util.StringTokenizer; import javax.net.ssl.*; +import sun.net.util.IPAddressUtil; import sun.net.www.http.HttpClient; import sun.net.www.protocol.http.AuthCacheImpl; import sun.net.www.protocol.http.HttpURLConnection; @@ -471,7 +472,13 @@ final class HttpsClient extends HttpClient SSLParameters parameters = s.getSSLParameters(); parameters.setEndpointIdentificationAlgorithm("HTTPS"); // host has been set previously for SSLSocketImpl - if (!(s instanceof SSLSocketImpl)) { + if (!(s instanceof SSLSocketImpl) && + !IPAddressUtil.isIPv4LiteralAddress(host) && + !(host.charAt(0) == '[' && host.charAt(host.length() - 1) == ']' && + IPAddressUtil.isIPv6LiteralAddress(host.substring(1, host.length() - 1)) + )) { + // Fully qualified DNS hostname of the server, as per section 3, RFC 6066 + // Literal IPv4 and IPv6 addresses are not permitted in "HostName". parameters.setServerNames(List.of(new SNIHostName(host))); } s.setSSLParameters(parameters); diff --git a/test/jdk/javax/net/ssl/HttpsURLConnection/SubjectAltNameIP.java b/test/jdk/javax/net/ssl/HttpsURLConnection/SubjectAltNameIP.java new file mode 100644 index 00000000000..2def2f69d6e --- /dev/null +++ b/test/jdk/javax/net/ssl/HttpsURLConnection/SubjectAltNameIP.java @@ -0,0 +1,379 @@ +/* + * Copyright (c) 2025, 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 8369950 + * @summary Test that the HttpsURLConnection does not set IP address literals for + * SNI hostname during TLS handshake + * @library /test/lib + * @modules java.base/sun.net.util + * @comment Insert -Djavax.net.debug=all into the following lines to enable SSL debugging + * @run main/othervm SubjectAltNameIP 127.0.0.1 + * @run main/othervm SubjectAltNameIP [::1] + */ + +import javax.net.ssl.HandshakeCompletedListener; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLParameters; +import javax.net.ssl.SSLServerSocket; +import javax.net.ssl.SSLServerSocketFactory; +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.SSLSocketFactory; +import java.io.BufferedWriter; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.net.InetAddress; +import java.net.Socket; +import java.net.SocketAddress; +import java.net.URI; +import java.util.concurrent.CountDownLatch; +import java.util.function.Consumer; + +import jdk.test.lib.Asserts; +import jdk.test.lib.net.IPSupport; +import jdk.test.lib.net.SimpleSSLContext; +import jtreg.SkippedException; +import sun.net.util.IPAddressUtil; + +public class SubjectAltNameIP { + + // Is the server ready to serve? + private final CountDownLatch serverReady = new CountDownLatch(1); + + // Use any free port by default. + volatile int serverPort = 0; + + // Stores an exception thrown by server in a separate thread. + volatile Exception serverException = null; + + // SSLSocket object created by HttpsClient internally. + SSLSocket clientSSLSocket = null; + + // The hostname the server socket is bound to. + String hostName; + + static final byte[] requestEnd = new byte[] {'\r', '\n', '\r', '\n' }; + + // Read until the end of the request. + void readOneRequest(InputStream is) throws IOException { + int requestEndCount = 0, r; + while ((r = is.read()) != -1) { + if (r == requestEnd[requestEndCount]) { + requestEndCount++; + if (requestEndCount == 4) { + break; + } + } else { + requestEndCount = 0; + } + } + } + + /* + * Define the server side of the test. + * + * If the server prematurely exits, serverReady will be set to true + * to avoid infinite hangs. + */ + void doServerSide() throws Exception { + SSLServerSocketFactory sslssf = + new SimpleSSLContext().get().getServerSocketFactory(); + SSLServerSocket sslServerSocket = + (SSLServerSocket) sslssf.createServerSocket( + serverPort, 0, + InetAddress.getByName(hostName)); + sslServerSocket.setEnabledProtocols(new String[]{"TLSv1.3"}); + serverPort = sslServerSocket.getLocalPort(); + + /* + * Signal the client, the server is ready to accept connection. + */ + serverReady.countDown(); + + SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept(); + OutputStream sslOS = sslSocket.getOutputStream(); + BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(sslOS)); + bw.write("HTTP/1.1 200 OK\r\n\r\n"); + bw.flush(); + readOneRequest(sslSocket.getInputStream()); + sslSocket.close(); + } + + /* + * Define the client side of the test. + * + * If the server prematurely exits, serverReady will be set to true + * to avoid infinite hangs. + */ + void doClientSide() throws Exception { + + /* + * Wait for server to get started. + */ + serverReady.await(); + if (serverException != null) { + throw new RuntimeException("Server failed to start.", serverException); + } + + SSLSocketFactory sf = new SimpleSSLContext().get().getSocketFactory(); + URI uri = new URI("https://" + hostName + ":" + serverPort + "/index.html"); + HttpsURLConnection conn = (HttpsURLConnection)uri.toURL().openConnection(); + + /* + * Simulate an external JSSE implementation and store the client SSLSocket + * used internally. + */ + conn.setSSLSocketFactory(wrapSocketFactory(sf, + sslSocket -> { + Asserts.assertEquals(null, clientSSLSocket, "clientSSLSocket is"); + clientSSLSocket = sslSocket; + })); + conn.getInputStream(); + + var sniSN = clientSSLSocket.getSSLParameters().getServerNames(); + if (sniSN != null && !sniSN.isEmpty()) { + throw new RuntimeException("SNI server name '" + + sniSN.getFirst() + "' must not be set."); + } + + if (conn.getResponseCode() == -1) { + throw new RuntimeException("getResponseCode() returns -1"); + } + } + + public static void main(String[] args) throws Exception { + + if (IPAddressUtil.isIPv6LiteralAddress(args[0]) && !IPSupport.hasIPv6()) { + throw new SkippedException("Skipping test - IPv6 is not supported"); + } + /* + * Start the tests. + */ + new SubjectAltNameIP(args[0]); + } + + Thread serverThread = null; + + /* + * Primary constructor, used to drive remainder of the test. + * + * Fork off the other side, then do your work. + */ + SubjectAltNameIP(String host) throws Exception { + hostName = host; + startServer(); + doClientSide(); + + /* + * Wait for other side to close down. + */ + serverThread.join(); + + if (serverException != null) + throw serverException; + } + + void startServer() { + serverThread = new Thread(() -> { + try { + doServerSide(); + } catch (Exception e) { + /* + * Our server thread just died. + * + * Store the exception and release the client. + */ + serverException = e; + serverReady.countDown(); + } + }); + serverThread.start(); + } + + /* + * Wraps SSLSocketImpl to simulate a different JSSE implementation + */ + private static SSLSocketFactory wrapSocketFactory(final SSLSocketFactory wrap, final Consumer store) { + return new SSLSocketFactory() { + @Override + public String[] getDefaultCipherSuites() { + return wrap.getDefaultCipherSuites(); + } + @Override + public String[] getSupportedCipherSuites() { + return wrap.getSupportedCipherSuites(); + } + @Override + public Socket createSocket(Socket s, String host, int port, boolean autoClose) + throws IOException { + final SSLSocket so = + (SSLSocket) wrap.createSocket(s, host, port, autoClose); + + // store the underlying SSLSocket for later use + store.accept(so); + + return new SSLSocket() { + @Override + public void connect(SocketAddress endpoint, + int timeout) throws IOException { + so.connect(endpoint, timeout); + } + @Override + public String[] getSupportedCipherSuites() { + return so.getSupportedCipherSuites(); + } + @Override + public String[] getEnabledCipherSuites() { + return so.getEnabledCipherSuites(); + } + @Override + public void setEnabledCipherSuites(String[] suites) { + so.setEnabledCipherSuites(suites); + } + @Override + public String[] getSupportedProtocols() { + return so.getSupportedProtocols(); + } + @Override + public String[] getEnabledProtocols() { + return so.getEnabledProtocols(); + } + @Override + public void setEnabledProtocols(String[] protocols) { + so.setEnabledProtocols(protocols); + } + @Override + public SSLSession getSession() { + return so.getSession(); + } + @Override + public SSLSession getHandshakeSession() { + return so.getHandshakeSession(); + } + @Override + public void addHandshakeCompletedListener(HandshakeCompletedListener listener) { + so.addHandshakeCompletedListener(listener); + } + @Override + public void removeHandshakeCompletedListener(HandshakeCompletedListener listener) { + so.removeHandshakeCompletedListener(listener); + } + @Override + public void startHandshake() throws IOException { + so.startHandshake(); + } + @Override + public void setUseClientMode(boolean mode) { + so.setUseClientMode(mode); + } + @Override + public boolean getUseClientMode() { + return so.getUseClientMode(); + } + @Override + public void setNeedClientAuth(boolean need) { + } + @Override + public boolean getNeedClientAuth() { + return false; + } + @Override + public void setWantClientAuth(boolean want) { + } + @Override + public boolean getWantClientAuth() { + return false; + } + @Override + public void setEnableSessionCreation(boolean flag) { + so.setEnableSessionCreation(flag); + } + @Override + public boolean getEnableSessionCreation() { + return so.getEnableSessionCreation(); + } + @Override + public void close() throws IOException { + so.close(); + } + @Override + public boolean isClosed() { + return so.isClosed(); + } + @Override + public void shutdownInput() throws IOException { + so.shutdownInput(); + } + @Override + public boolean isInputShutdown() { + return so.isInputShutdown(); + } + @Override + public void shutdownOutput() throws IOException { + so.shutdownOutput(); + } + @Override + public boolean isOutputShutdown() { + return so.isOutputShutdown(); + } + @Override + public InputStream getInputStream() throws IOException { + return so.getInputStream(); + } + @Override + public OutputStream getOutputStream() throws IOException { + return so.getOutputStream(); + } + @Override + public SSLParameters getSSLParameters() { + return so.getSSLParameters(); + } + @Override + public void setSSLParameters(SSLParameters params) { + so.setSSLParameters(params); + } + }; + } + @Override + public Socket createSocket(String h, int p) { + return null; + } + @Override + public Socket createSocket(String h, int p, InetAddress ipa, int lp) { + return null; + } + @Override + public Socket createSocket(InetAddress h, int p) { + return null; + } + @Override + public Socket createSocket(InetAddress a, int p, InetAddress l, int lp) { + return null; + } + }; + } +} From 350015088281eb9e6e9e3a9811f38adac5f7a975 Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Mon, 8 Dec 2025 10:04:44 +0000 Subject: [PATCH 201/706] 8373094: javac may fail because of unattributed break in a loop Reviewed-by: vromero --- .../com/sun/tools/javac/comp/Attr.java | 16 +- .../tools/javac/recovery/AttrRecovery.java | 158 +++++++++++++++++- 2 files changed, 167 insertions(+), 7 deletions(-) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java index 3f72ada94e8..cc21113882f 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java @@ -5634,12 +5634,16 @@ public class Attr extends JCTree.Visitor { chk.validateRepeatable(c, repeatable, cbPos); } } else { - // Check that all extended classes and interfaces - // are compatible (i.e. no two define methods with same arguments - // yet different return types). (JLS 8.4.8.3) - chk.checkCompatibleSupertypes(tree.pos(), c.type); - chk.checkDefaultMethodClashes(tree.pos(), c.type); - chk.checkPotentiallyAmbiguousOverloads(tree, c.type); + try { + // Check that all extended classes and interfaces + // are compatible (i.e. no two define methods with same arguments + // yet different return types). (JLS 8.4.8.3) + chk.checkCompatibleSupertypes(tree.pos(), c.type); + chk.checkDefaultMethodClashes(tree.pos(), c.type); + chk.checkPotentiallyAmbiguousOverloads(tree, c.type); + } catch (CompletionFailure cf) { + chk.completionError(tree.pos(), cf); + } } // Check that class does not import the same parameterized interface diff --git a/test/langtools/tools/javac/recovery/AttrRecovery.java b/test/langtools/tools/javac/recovery/AttrRecovery.java index 9a37ce60654..ac1455e71d7 100644 --- a/test/langtools/tools/javac/recovery/AttrRecovery.java +++ b/test/langtools/tools/javac/recovery/AttrRecovery.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8301580 8322159 8333107 8332230 8338678 8351260 8366196 8372336 + * @bug 8301580 8322159 8333107 8332230 8338678 8351260 8366196 8372336 8373094 * @summary Verify error recovery w.r.t. Attr * @library /tools/lib * @modules jdk.compiler/com.sun.tools.javac.api @@ -32,8 +32,11 @@ * @run main AttrRecovery */ +import com.sun.source.tree.IdentifierTree; import com.sun.source.tree.MemberReferenceTree; +import com.sun.source.tree.MemberSelectTree; import com.sun.source.tree.MethodInvocationTree; +import com.sun.source.tree.MethodTree; import com.sun.source.tree.VariableTree; import com.sun.source.util.TaskEvent; import com.sun.source.util.TaskListener; @@ -41,11 +44,13 @@ import com.sun.source.util.TreePathScanner; import com.sun.source.util.Trees; import java.nio.file.Files; import java.nio.file.Path; +import java.util.ArrayList; import java.util.IdentityHashMap; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.stream.Collectors; +import java.util.stream.Stream; import javax.lang.model.element.Element; import javax.lang.model.element.VariableElement; import javax.lang.model.type.DeclaredType; @@ -495,4 +500,155 @@ public class AttrRecovery extends TestRunner { } } } + + @Test //JDK-8373094 + public void testSensibleAttribution() throws Exception { + Path curPath = Path.of("."); + Path lib = curPath.resolve("lib"); + Path classes = lib.resolve("classes"); + Files.createDirectories(classes); + new JavacTask(tb) + .outdir(classes) + .sources(""" + package test; + public class Intermediate extends Base {} + """, + """ + package test; + public class Base { + public void t(Missing m) {} + } + """, + """ + package test; + public class Missing { + } + """) + .run() + .writeAll(); + + Files.delete(classes.resolve("test").resolve("Missing.class")); + + record TestCase(String code, List options, String... expectedErrors) {} + TestCase[] testCases = new TestCase[] { + new TestCase(""" + package test; + public class Test extends Intermediate { + private void test() { + int i = 0; + System.err.println(i); + while (true) { + break; + } + } + } + """, + List.of(), + "Test.java:2:8: compiler.err.cant.access: test.Missing, (compiler.misc.class.file.not.found: test.Missing)", + "1 error"), + new TestCase(""" + package test; + public class Test extends Intermediate { + private void test() { + int i = 0; + System.err.println(i); + while (true) { + break; + } + } + } + """, + List.of("-XDshould-stop.at=FLOW"), + "Test.java:2:8: compiler.err.cant.access: test.Missing, (compiler.misc.class.file.not.found: test.Missing)", + "1 error"), + }; + + for (TestCase tc : testCases) { + List attributes = new ArrayList<>(); + List actual = new JavacTask(tb) + .options(Stream.concat(List.of("-XDrawDiagnostics", "-XDdev").stream(), + tc.options.stream()).toList()) + .classpath(classes) + .sources(tc.code()) + .outdir(curPath) + .callback(task -> { + task.addTaskListener(new TaskListener() { + @Override + public void finished(TaskEvent e) { + if (e.getKind() != TaskEvent.Kind.ANALYZE) { + return ; + } + Trees trees = Trees.instance(task); + new TreePathScanner() { + boolean check; + + @Override + public Void visitMethod(MethodTree node, Void p) { + if (node.getName().contentEquals("test")) { + check = true; + try { + return super.visitMethod(node, p); + } finally { + check = false; + } + } + + return super.visitMethod(node, p); + } + + @Override + public Void visitMethodInvocation(MethodInvocationTree node, Void p) { + if (!node.toString().contains("super")) { + verifyElement(); + } + return super.visitMethodInvocation(node, p); + } + + @Override + public Void visitIdentifier(IdentifierTree node, Void p) { + verifyElement(); + return super.visitIdentifier(node, p); + } + + @Override + public Void visitMemberSelect(MemberSelectTree node, Void p) { + verifyElement(); + return super.visitMemberSelect(node, p); + } + + private void verifyElement() { + if (!check) { + return ; + } + + Element el = trees.getElement(getCurrentPath()); + if (el == null) { + error("Unattributed tree: " + getCurrentPath().getLeaf()); + } else { + attributes.add(el.toString()); + } + } + }.scan(e.getCompilationUnit(), null); + } + }); + }) + .run(Expect.FAIL) + .writeAll() + .getOutputLines(OutputKind.DIRECT); + + List expectedErrors = List.of(tc.expectedErrors); + + if (!Objects.equals(actual, expectedErrors)) { + error("Expected: " + expectedErrors + ", but got: " + actual); + } + + List expectedAttributes = + List.of("println(int)", "println(int)", "err", "java.lang.System", "i"); + + if (!Objects.equals(attributes, expectedAttributes)) { + error("Expected: " + expectedAttributes + ", but got: " + attributes); + } + } + } + } From a6594794839807d56434d6f28fe3d581fb1e36c0 Mon Sep 17 00:00:00 2001 From: Francesco Andreuzzi Date: Mon, 8 Dec 2025 11:45:53 +0000 Subject: [PATCH 202/706] 8367541: Parallel: Make young and old generation fields nonstatic in ParallelScavengeHeap Reviewed-by: ayang --- src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp | 2 -- src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp | 8 ++++---- src/hotspot/share/gc/parallel/psScavenge.hpp | 2 +- src/hotspot/share/gc/parallel/vmStructs_parallelgc.hpp | 4 ++-- 4 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp index 9df3deedf89..b85b16f58b5 100644 --- a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp +++ b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp @@ -58,8 +58,6 @@ #include "utilities/macros.hpp" #include "utilities/vmError.hpp" -PSYoungGen* ParallelScavengeHeap::_young_gen = nullptr; -PSOldGen* ParallelScavengeHeap::_old_gen = nullptr; PSAdaptiveSizePolicy* ParallelScavengeHeap::_size_policy = nullptr; GCPolicyCounters* ParallelScavengeHeap::_gc_policy_counters = nullptr; size_t ParallelScavengeHeap::_desired_page_size = 0; diff --git a/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp b/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp index 5d8ddbcaaed..588ddfa3f0c 100644 --- a/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp +++ b/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp @@ -69,8 +69,8 @@ class ReservedSpace; class ParallelScavengeHeap : public CollectedHeap { friend class VMStructs; private: - static PSYoungGen* _young_gen; - static PSOldGen* _old_gen; + PSYoungGen* _young_gen; + PSOldGen* _old_gen; // Sizing policy for entire heap static PSAdaptiveSizePolicy* _size_policy; @@ -160,8 +160,8 @@ public: GrowableArray memory_managers() override; GrowableArray memory_pools() override; - static PSYoungGen* young_gen() { return _young_gen; } - static PSOldGen* old_gen() { return _old_gen; } + PSYoungGen* young_gen() const { return _young_gen; } + PSOldGen* old_gen() const { return _old_gen; } PSAdaptiveSizePolicy* size_policy() { return _size_policy; } diff --git a/src/hotspot/share/gc/parallel/psScavenge.hpp b/src/hotspot/share/gc/parallel/psScavenge.hpp index af9b91f74bc..df97a1c1ede 100644 --- a/src/hotspot/share/gc/parallel/psScavenge.hpp +++ b/src/hotspot/share/gc/parallel/psScavenge.hpp @@ -115,7 +115,7 @@ class PSScavenge: AllStatic { } static bool is_obj_in_to_space(oop o) { - return ParallelScavengeHeap::young_gen()->to_space()->contains(o); + return ParallelScavengeHeap::heap()->young_gen()->to_space()->contains(o); } }; diff --git a/src/hotspot/share/gc/parallel/vmStructs_parallelgc.hpp b/src/hotspot/share/gc/parallel/vmStructs_parallelgc.hpp index f5e7375fca1..e45bd45400c 100644 --- a/src/hotspot/share/gc/parallel/vmStructs_parallelgc.hpp +++ b/src/hotspot/share/gc/parallel/vmStructs_parallelgc.hpp @@ -64,8 +64,8 @@ nonstatic_field(PSOldGen, _max_gen_size, const size_t) \ \ \ - static_field(ParallelScavengeHeap, _young_gen, PSYoungGen*) \ - static_field(ParallelScavengeHeap, _old_gen, PSOldGen*) \ + nonstatic_field(ParallelScavengeHeap, _young_gen, PSYoungGen*) \ + nonstatic_field(ParallelScavengeHeap, _old_gen, PSOldGen*) \ \ #define VM_TYPES_PARALLELGC(declare_type, \ From b83bf0717eb8926efcf85a32be08f33a41bb48dd Mon Sep 17 00:00:00 2001 From: Qizheng Xing Date: Mon, 8 Dec 2025 13:16:39 +0000 Subject: [PATCH 203/706] 8360192: C2: Make the type of count leading/trailing zero nodes more precise Reviewed-by: qamai, epeter, jbhateja --- src/hotspot/share/opto/countbitsnode.cpp | 149 +++-- .../compiler/c2/gvn/TestCountBitsRange.java | 570 ++++++++++++++++++ .../compiler/lib/ir_framework/IRNode.java | 20 + .../bench/vm/compiler/CountLeadingZeros.java | 74 +++ 4 files changed, 747 insertions(+), 66 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/c2/gvn/TestCountBitsRange.java create mode 100644 test/micro/org/openjdk/bench/vm/compiler/CountLeadingZeros.java diff --git a/src/hotspot/share/opto/countbitsnode.cpp b/src/hotspot/share/opto/countbitsnode.cpp index aac874e94b1..1601b33ea2b 100644 --- a/src/hotspot/share/opto/countbitsnode.cpp +++ b/src/hotspot/share/opto/countbitsnode.cpp @@ -26,97 +26,114 @@ #include "opto/opcodes.hpp" #include "opto/phaseX.hpp" #include "opto/type.hpp" +#include "utilities/count_leading_zeros.hpp" +#include "utilities/count_trailing_zeros.hpp" #include "utilities/population_count.hpp" +static int count_leading_zeros_int(jint i) { + return i == 0 ? BitsPerInt : count_leading_zeros(i); +} + +static int count_leading_zeros_long(jlong l) { + return l == 0 ? BitsPerLong : count_leading_zeros(l); +} + +static int count_trailing_zeros_int(jint i) { + return i == 0 ? BitsPerInt : count_trailing_zeros(i); +} + +static int count_trailing_zeros_long(jlong l) { + return l == 0 ? BitsPerLong : count_trailing_zeros(l); +} + //------------------------------Value------------------------------------------ const Type* CountLeadingZerosINode::Value(PhaseGVN* phase) const { const Type* t = phase->type(in(1)); - if (t == Type::TOP) return Type::TOP; - const TypeInt* ti = t->isa_int(); - if (ti && ti->is_con()) { - jint i = ti->get_con(); - // HD, Figure 5-6 - if (i == 0) - return TypeInt::make(BitsPerInt); - int n = 1; - unsigned int x = i; - if (x >> 16 == 0) { n += 16; x <<= 16; } - if (x >> 24 == 0) { n += 8; x <<= 8; } - if (x >> 28 == 0) { n += 4; x <<= 4; } - if (x >> 30 == 0) { n += 2; x <<= 2; } - n -= x >> 31; - return TypeInt::make(n); + if (t == Type::TOP) { + return Type::TOP; } - return TypeInt::INT; + + // To minimize `count_leading_zeros(x)`, we should make the highest 1 bit in x + // as far to the left as possible. A bit in x can be 1 iff this bit is not + // forced to be 0, i.e. the corresponding bit in `x._bits._zeros` is 0. Thus: + // min(clz(x)) = number of bits to the left of the highest 0 bit in x._bits._zeros + // = count_leading_ones(x._bits._zeros) = clz(~x._bits._zeros) + // + // To maximize `count_leading_zeros(x)`, we should make the leading zeros as + // many as possible. A bit in x can be 0 iff this bit is not forced to be 1, + // i.e. the corresponding bit in `x._bits._ones` is 0. Thus: + // max(clz(x)) = clz(x._bits._ones) + // + // Therefore, the range of `count_leading_zeros(x)` is: + // [clz(~x._bits._zeros), clz(x._bits._ones)] + // + // A more detailed proof using Z3 can be found at: + // https://github.com/openjdk/jdk/pull/25928#discussion_r2256750507 + const TypeInt* ti = t->is_int(); + return TypeInt::make(count_leading_zeros_int(~ti->_bits._zeros), + count_leading_zeros_int(ti->_bits._ones), + ti->_widen); } //------------------------------Value------------------------------------------ const Type* CountLeadingZerosLNode::Value(PhaseGVN* phase) const { const Type* t = phase->type(in(1)); - if (t == Type::TOP) return Type::TOP; - const TypeLong* tl = t->isa_long(); - if (tl && tl->is_con()) { - jlong l = tl->get_con(); - // HD, Figure 5-6 - if (l == 0) - return TypeInt::make(BitsPerLong); - int n = 1; - unsigned int x = (((julong) l) >> 32); - if (x == 0) { n += 32; x = (int) l; } - if (x >> 16 == 0) { n += 16; x <<= 16; } - if (x >> 24 == 0) { n += 8; x <<= 8; } - if (x >> 28 == 0) { n += 4; x <<= 4; } - if (x >> 30 == 0) { n += 2; x <<= 2; } - n -= x >> 31; - return TypeInt::make(n); + if (t == Type::TOP) { + return Type::TOP; } - return TypeInt::INT; + + // The proof of correctness is same as the above comments + // in `CountLeadingZerosINode::Value`. + const TypeLong* tl = t->is_long(); + return TypeInt::make(count_leading_zeros_long(~tl->_bits._zeros), + count_leading_zeros_long(tl->_bits._ones), + tl->_widen); } //------------------------------Value------------------------------------------ const Type* CountTrailingZerosINode::Value(PhaseGVN* phase) const { const Type* t = phase->type(in(1)); - if (t == Type::TOP) return Type::TOP; - const TypeInt* ti = t->isa_int(); - if (ti && ti->is_con()) { - jint i = ti->get_con(); - // HD, Figure 5-14 - int y; - if (i == 0) - return TypeInt::make(BitsPerInt); - int n = 31; - y = i << 16; if (y != 0) { n = n - 16; i = y; } - y = i << 8; if (y != 0) { n = n - 8; i = y; } - y = i << 4; if (y != 0) { n = n - 4; i = y; } - y = i << 2; if (y != 0) { n = n - 2; i = y; } - y = i << 1; if (y != 0) { n = n - 1; } - return TypeInt::make(n); + if (t == Type::TOP) { + return Type::TOP; } - return TypeInt::INT; + + // To minimize `count_trailing_zeros(x)`, we should make the lowest 1 bit in x + // as far to the right as possible. A bit in x can be 1 iff this bit is not + // forced to be 0, i.e. the corresponding bit in `x._bits._zeros` is 0. Thus: + // min(ctz(x)) = number of bits to the right of the lowest 0 bit in x._bits._zeros + // = count_trailing_ones(x._bits._zeros) = ctz(~x._bits._zeros) + // + // To maximize `count_trailing_zeros(x)`, we should make the trailing zeros as + // many as possible. A bit in x can be 0 iff this bit is not forced to be 1, + // i.e. the corresponding bit in `x._bits._ones` is 0. Thus: + // max(ctz(x)) = ctz(x._bits._ones) + // + // Therefore, the range of `count_trailing_zeros(x)` is: + // [ctz(~x._bits._zeros), ctz(x._bits._ones)] + // + // A more detailed proof using Z3 can be found at: + // https://github.com/openjdk/jdk/pull/25928#discussion_r2256750507 + const TypeInt* ti = t->is_int(); + return TypeInt::make(count_trailing_zeros_int(~ti->_bits._zeros), + count_trailing_zeros_int(ti->_bits._ones), + ti->_widen); } //------------------------------Value------------------------------------------ const Type* CountTrailingZerosLNode::Value(PhaseGVN* phase) const { const Type* t = phase->type(in(1)); - if (t == Type::TOP) return Type::TOP; - const TypeLong* tl = t->isa_long(); - if (tl && tl->is_con()) { - jlong l = tl->get_con(); - // HD, Figure 5-14 - int x, y; - if (l == 0) - return TypeInt::make(BitsPerLong); - int n = 63; - y = (int) l; if (y != 0) { n = n - 32; x = y; } else x = (((julong) l) >> 32); - y = x << 16; if (y != 0) { n = n - 16; x = y; } - y = x << 8; if (y != 0) { n = n - 8; x = y; } - y = x << 4; if (y != 0) { n = n - 4; x = y; } - y = x << 2; if (y != 0) { n = n - 2; x = y; } - y = x << 1; if (y != 0) { n = n - 1; } - return TypeInt::make(n); + if (t == Type::TOP) { + return Type::TOP; } - return TypeInt::INT; + + // The proof of correctness is same as the above comments + // in `CountTrailingZerosINode::Value`. + const TypeLong* tl = t->is_long(); + return TypeInt::make(count_trailing_zeros_long(~tl->_bits._zeros), + count_trailing_zeros_long(tl->_bits._ones), + tl->_widen); } + // We use the KnownBits information from the integer types to derive how many one bits // we have at least and at most. // From the definition of KnownBits, we know: diff --git a/test/hotspot/jtreg/compiler/c2/gvn/TestCountBitsRange.java b/test/hotspot/jtreg/compiler/c2/gvn/TestCountBitsRange.java new file mode 100644 index 00000000000..00aa466e822 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/gvn/TestCountBitsRange.java @@ -0,0 +1,570 @@ +/* + * Copyright (c) 2025 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. + */ + +package compiler.c2.gvn; + +import compiler.lib.generators.Generator; +import compiler.lib.generators.Generators; +import compiler.lib.generators.RestrictableGenerator; +import compiler.lib.ir_framework.*; +import java.util.function.Function; +import jdk.test.lib.Asserts; + +/* + * @test + * @bug 8360192 + * @summary Tests that count bits nodes are handled correctly. + * @library /test/lib / + * @run driver compiler.c2.gvn.TestCountBitsRange + */ +public class TestCountBitsRange { + private static final Generator INTS = Generators.G.ints(); + private static final Generator LONGS = Generators.G.longs(); + + private static final RestrictableGenerator INTS_32 = Generators.G.ints().restricted(0, 32); + private static final RestrictableGenerator INTS_64 = Generators.G.ints().restricted(0, 64); + + private static final int LIMITS_32_0 = INTS_32.next(); + private static final int LIMITS_32_1 = INTS_32.next(); + private static final int LIMITS_32_2 = INTS_32.next(); + private static final int LIMITS_32_3 = INTS_32.next(); + private static final int LIMITS_32_4 = INTS_32.next(); + private static final int LIMITS_32_5 = INTS_32.next(); + private static final int LIMITS_32_6 = INTS_32.next(); + private static final int LIMITS_32_7 = INTS_32.next(); + + private static final int LIMITS_64_0 = INTS_64.next(); + private static final int LIMITS_64_1 = INTS_64.next(); + private static final int LIMITS_64_2 = INTS_64.next(); + private static final int LIMITS_64_3 = INTS_64.next(); + private static final int LIMITS_64_4 = INTS_64.next(); + private static final int LIMITS_64_5 = INTS_64.next(); + private static final int LIMITS_64_6 = INTS_64.next(); + private static final int LIMITS_64_7 = INTS_64.next(); + + private static final IntRange RANGE_INT = IntRange.generate(INTS); + private static final LongRange RANGE_LONG = LongRange.generate(LONGS); + + public static void main(String[] args) { + TestFramework.run(); + } + + @Run(test = { + "clzConstInts", "clzCompareInt", "clzDiv8Int", "clzRandLimitInt", + "clzConstLongs", "clzCompareLong", "clzDiv8Long", "clzRandLimitLong", + "ctzConstInts", "ctzCompareInt", "ctzDiv8Int", "ctzRandLimitInt", + "ctzConstLongs", "ctzCompareLong", "ctzDiv8Long", "ctzRandLimitLong", + }) + public void runTest() { + int randInt = INTS.next(); + long randLong = LONGS.next(); + assertResult(randInt, randLong); + } + + @DontCompile + public void assertResult(int randInt, long randLong) { + checkConstResults(clzConstInts(), x -> Integer.numberOfLeadingZeros(x.intValue())); + Asserts.assertEQ(Integer.numberOfLeadingZeros(randInt) < 0 + || Integer.numberOfLeadingZeros(randInt) > 32, + clzCompareInt(randInt)); + Asserts.assertEQ(Integer.numberOfLeadingZeros(randInt) / 8, + clzDiv8Int(randInt)); + Asserts.assertEQ(clzRandLimitInterpretedInt(randInt), clzRandLimitInt(randInt)); + + checkConstResults(clzConstLongs(), x -> Long.numberOfLeadingZeros(x.longValue())); + Asserts.assertEQ(Long.numberOfLeadingZeros(randLong) < 0 + || Long.numberOfLeadingZeros(randLong) > 64, + clzCompareLong(randLong)); + Asserts.assertEQ(Long.numberOfLeadingZeros(randLong) / 8, + clzDiv8Long(randLong)); + Asserts.assertEQ(clzRandLimitInterpretedLong(randLong), clzRandLimitLong(randLong)); + + checkConstResults(ctzConstInts(), x -> Integer.numberOfTrailingZeros(x.intValue())); + Asserts.assertEQ(Integer.numberOfTrailingZeros(randInt) < 0 + || Integer.numberOfTrailingZeros(randInt) > 32, + ctzCompareInt(randInt)); + Asserts.assertEQ(Integer.numberOfTrailingZeros(randInt) / 8, + ctzDiv8Int(randInt)); + Asserts.assertEQ(ctzRandLimitInterpretedInt(randInt), ctzRandLimitInt(randInt)); + + checkConstResults(ctzConstLongs(), x -> Long.numberOfTrailingZeros(x.longValue())); + Asserts.assertEQ(Long.numberOfTrailingZeros(randLong) < 0 + || Long.numberOfTrailingZeros(randLong) > 64, + ctzCompareLong(randLong)); + Asserts.assertEQ(Long.numberOfTrailingZeros(randLong) / 8, + ctzDiv8Long(randLong)); + Asserts.assertEQ(ctzRandLimitInterpretedLong(randLong), ctzRandLimitLong(randLong)); + } + + @DontCompile + public void checkConstResults(int[] results, Function op) { + Asserts.assertEQ(op.apply(Long.valueOf(0)), results[0]); + for (int i = 0; i < results.length - 1; ++i) { + Asserts.assertEQ(op.apply(Long.valueOf(1l << i)), results[i + 1]); + } + } + + // Test CLZ with constant integer inputs. + // All CLZs in this test are expected to be optimized away. + @Test + @IR(failOn = IRNode.COUNT_LEADING_ZEROS_I) + public int[] clzConstInts() { + return new int[] { + Integer.numberOfLeadingZeros(0), + Integer.numberOfLeadingZeros(1 << 0), + Integer.numberOfLeadingZeros(1 << 1), + Integer.numberOfLeadingZeros(1 << 2), + Integer.numberOfLeadingZeros(1 << 3), + Integer.numberOfLeadingZeros(1 << 4), + Integer.numberOfLeadingZeros(1 << 5), + Integer.numberOfLeadingZeros(1 << 6), + Integer.numberOfLeadingZeros(1 << 7), + Integer.numberOfLeadingZeros(1 << 8), + Integer.numberOfLeadingZeros(1 << 9), + Integer.numberOfLeadingZeros(1 << 10), + Integer.numberOfLeadingZeros(1 << 11), + Integer.numberOfLeadingZeros(1 << 12), + Integer.numberOfLeadingZeros(1 << 13), + Integer.numberOfLeadingZeros(1 << 14), + Integer.numberOfLeadingZeros(1 << 15), + Integer.numberOfLeadingZeros(1 << 16), + Integer.numberOfLeadingZeros(1 << 17), + Integer.numberOfLeadingZeros(1 << 18), + Integer.numberOfLeadingZeros(1 << 19), + Integer.numberOfLeadingZeros(1 << 20), + Integer.numberOfLeadingZeros(1 << 21), + Integer.numberOfLeadingZeros(1 << 22), + Integer.numberOfLeadingZeros(1 << 23), + Integer.numberOfLeadingZeros(1 << 24), + Integer.numberOfLeadingZeros(1 << 25), + Integer.numberOfLeadingZeros(1 << 26), + Integer.numberOfLeadingZeros(1 << 27), + Integer.numberOfLeadingZeros(1 << 28), + Integer.numberOfLeadingZeros(1 << 29), + Integer.numberOfLeadingZeros(1 << 30), + Integer.numberOfLeadingZeros(1 << 31), + }; + } + + // Test the range of CLZ with random integer input. + // The result of CLZ should be in range [0, 32], so CLZs in this test are + // expected to be optimized away, and the test should always return false. + @Test + @IR(failOn = IRNode.COUNT_LEADING_ZEROS_I) + public boolean clzCompareInt(int randInt) { + return Integer.numberOfLeadingZeros(randInt) < 0 + || Integer.numberOfLeadingZeros(randInt) > 32; + } + + // Test the combination of CLZ and division by 8. + // The result of CLZ should be positive, so the division by 8 should be + // optimized to a simple right shift without rounding. + @Test + @IR(counts = {IRNode.COUNT_LEADING_ZEROS_I, "1", + IRNode.RSHIFT_I, "1", + IRNode.URSHIFT_I, "0", + IRNode.ADD_I, "0"}) + public int clzDiv8Int(int randInt) { + return Integer.numberOfLeadingZeros(randInt) / 8; + } + + // Test the output range of CLZ with random input range. + @Test + public int clzRandLimitInt(int randInt) { + randInt = RANGE_INT.clamp(randInt); + int result = Integer.numberOfLeadingZeros(randInt); + return getResultChecksum32(result); + } + + @DontCompile + public int clzRandLimitInterpretedInt(int randInt) { + randInt = RANGE_INT.clamp(randInt); + int result = Integer.numberOfLeadingZeros(randInt); + return getResultChecksum32(result); + } + + // Test CLZ with constant long inputs. + // All CLZs in this test are expected to be optimized away. + @Test + @IR(failOn = IRNode.COUNT_LEADING_ZEROS_L) + public int[] clzConstLongs() { + return new int[] { + Long.numberOfLeadingZeros(0), + Long.numberOfLeadingZeros(1l << 0), + Long.numberOfLeadingZeros(1l << 1), + Long.numberOfLeadingZeros(1l << 2), + Long.numberOfLeadingZeros(1l << 3), + Long.numberOfLeadingZeros(1l << 4), + Long.numberOfLeadingZeros(1l << 5), + Long.numberOfLeadingZeros(1l << 6), + Long.numberOfLeadingZeros(1l << 7), + Long.numberOfLeadingZeros(1l << 8), + Long.numberOfLeadingZeros(1l << 9), + Long.numberOfLeadingZeros(1l << 10), + Long.numberOfLeadingZeros(1l << 11), + Long.numberOfLeadingZeros(1l << 12), + Long.numberOfLeadingZeros(1l << 13), + Long.numberOfLeadingZeros(1l << 14), + Long.numberOfLeadingZeros(1l << 15), + Long.numberOfLeadingZeros(1l << 16), + Long.numberOfLeadingZeros(1l << 17), + Long.numberOfLeadingZeros(1l << 18), + Long.numberOfLeadingZeros(1l << 19), + Long.numberOfLeadingZeros(1l << 20), + Long.numberOfLeadingZeros(1l << 21), + Long.numberOfLeadingZeros(1l << 22), + Long.numberOfLeadingZeros(1l << 23), + Long.numberOfLeadingZeros(1l << 24), + Long.numberOfLeadingZeros(1l << 25), + Long.numberOfLeadingZeros(1l << 26), + Long.numberOfLeadingZeros(1l << 27), + Long.numberOfLeadingZeros(1l << 28), + Long.numberOfLeadingZeros(1l << 29), + Long.numberOfLeadingZeros(1l << 30), + Long.numberOfLeadingZeros(1l << 31), + Long.numberOfLeadingZeros(1l << 32), + Long.numberOfLeadingZeros(1l << 33), + Long.numberOfLeadingZeros(1l << 34), + Long.numberOfLeadingZeros(1l << 35), + Long.numberOfLeadingZeros(1l << 36), + Long.numberOfLeadingZeros(1l << 37), + Long.numberOfLeadingZeros(1l << 38), + Long.numberOfLeadingZeros(1l << 39), + Long.numberOfLeadingZeros(1l << 40), + Long.numberOfLeadingZeros(1l << 41), + Long.numberOfLeadingZeros(1l << 42), + Long.numberOfLeadingZeros(1l << 43), + Long.numberOfLeadingZeros(1l << 44), + Long.numberOfLeadingZeros(1l << 45), + Long.numberOfLeadingZeros(1l << 46), + Long.numberOfLeadingZeros(1l << 47), + Long.numberOfLeadingZeros(1l << 48), + Long.numberOfLeadingZeros(1l << 49), + Long.numberOfLeadingZeros(1l << 50), + Long.numberOfLeadingZeros(1l << 51), + Long.numberOfLeadingZeros(1l << 52), + Long.numberOfLeadingZeros(1l << 53), + Long.numberOfLeadingZeros(1l << 54), + Long.numberOfLeadingZeros(1l << 55), + Long.numberOfLeadingZeros(1l << 56), + Long.numberOfLeadingZeros(1l << 57), + Long.numberOfLeadingZeros(1l << 58), + Long.numberOfLeadingZeros(1l << 59), + Long.numberOfLeadingZeros(1l << 60), + Long.numberOfLeadingZeros(1l << 61), + Long.numberOfLeadingZeros(1l << 62), + Long.numberOfLeadingZeros(1l << 63), + }; + } + + // Test the range of CLZ with random long input. + // The result of CLZ should be in range [0, 64], so CLZs in this test are + // expected to be optimized away, and the test should always return false. + @Test + @IR(failOn = IRNode.COUNT_LEADING_ZEROS_L) + public boolean clzCompareLong(long randLong) { + return Long.numberOfLeadingZeros(randLong) < 0 + || Long.numberOfLeadingZeros(randLong) > 64; + } + + // Test the combination of CLZ and division by 8. + // The result of CLZ should be positive, so the division by 8 should be + // optimized to a simple right shift without rounding. + @Test + @IR(counts = {IRNode.COUNT_LEADING_ZEROS_L, "1", + IRNode.RSHIFT_I, "1", + IRNode.URSHIFT_I, "0", + IRNode.ADD_I, "0"}) + public int clzDiv8Long(long randLong) { + return Long.numberOfLeadingZeros(randLong) / 8; + } + + // Test the output range of CLZ with random input range. + @Test + public int clzRandLimitLong(long randLong) { + randLong = RANGE_LONG.clamp(randLong); + int result = Long.numberOfLeadingZeros(randLong); + return getResultChecksum64(result); + } + + @DontCompile + public int clzRandLimitInterpretedLong(long randLong) { + randLong = RANGE_LONG.clamp(randLong); + int result = Long.numberOfLeadingZeros(randLong); + return getResultChecksum64(result); + } + + // Test CTZ with constant integer inputs. + // All CTZs in this test are expected to be optimized away. + @Test + @IR(failOn = IRNode.COUNT_TRAILING_ZEROS_I) + public int[] ctzConstInts() { + return new int[] { + Integer.numberOfTrailingZeros(0), + Integer.numberOfTrailingZeros(1 << 0), + Integer.numberOfTrailingZeros(1 << 1), + Integer.numberOfTrailingZeros(1 << 2), + Integer.numberOfTrailingZeros(1 << 3), + Integer.numberOfTrailingZeros(1 << 4), + Integer.numberOfTrailingZeros(1 << 5), + Integer.numberOfTrailingZeros(1 << 6), + Integer.numberOfTrailingZeros(1 << 7), + Integer.numberOfTrailingZeros(1 << 8), + Integer.numberOfTrailingZeros(1 << 9), + Integer.numberOfTrailingZeros(1 << 10), + Integer.numberOfTrailingZeros(1 << 11), + Integer.numberOfTrailingZeros(1 << 12), + Integer.numberOfTrailingZeros(1 << 13), + Integer.numberOfTrailingZeros(1 << 14), + Integer.numberOfTrailingZeros(1 << 15), + Integer.numberOfTrailingZeros(1 << 16), + Integer.numberOfTrailingZeros(1 << 17), + Integer.numberOfTrailingZeros(1 << 18), + Integer.numberOfTrailingZeros(1 << 19), + Integer.numberOfTrailingZeros(1 << 20), + Integer.numberOfTrailingZeros(1 << 21), + Integer.numberOfTrailingZeros(1 << 22), + Integer.numberOfTrailingZeros(1 << 23), + Integer.numberOfTrailingZeros(1 << 24), + Integer.numberOfTrailingZeros(1 << 25), + Integer.numberOfTrailingZeros(1 << 26), + Integer.numberOfTrailingZeros(1 << 27), + Integer.numberOfTrailingZeros(1 << 28), + Integer.numberOfTrailingZeros(1 << 29), + Integer.numberOfTrailingZeros(1 << 30), + Integer.numberOfTrailingZeros(1 << 31), + }; + } + + // Test the range of CTZ with random integer input. + // The result of CTZ should be in range [0, 32], so CTZs in this test are + // expected to be optimized away, and the test should always return false. + @Test + @IR(failOn = IRNode.COUNT_TRAILING_ZEROS_I) + public boolean ctzCompareInt(int randInt) { + return Integer.numberOfTrailingZeros(randInt) < 0 + || Integer.numberOfTrailingZeros(randInt) > 32; + } + + // Test the combination of CTZ and division by 8. + // The result of CTZ should be positive, so the division by 8 should be + // optimized to a simple right shift without rounding. + @Test + @IR(counts = {IRNode.COUNT_TRAILING_ZEROS_I, "1", + IRNode.RSHIFT_I, "1", + IRNode.URSHIFT_I, "0", + IRNode.ADD_I, "0"}) + public int ctzDiv8Int(int randInt) { + return Integer.numberOfTrailingZeros(randInt) / 8; + } + + // Test the output range of CTZ with random input range. + @Test + public int ctzRandLimitInt(int randInt) { + randInt = RANGE_INT.clamp(randInt); + int result = Integer.numberOfTrailingZeros(randInt); + return getResultChecksum32(result); + } + + @DontCompile + public int ctzRandLimitInterpretedInt(int randInt) { + randInt = RANGE_INT.clamp(randInt); + int result = Integer.numberOfTrailingZeros(randInt); + return getResultChecksum32(result); + } + + // Test CTZ with constant long inputs. + // All CTZs in this test are expected to be optimized away. + @Test + @IR(failOn = IRNode.COUNT_TRAILING_ZEROS_L) + public int[] ctzConstLongs() { + return new int[] { + Long.numberOfTrailingZeros(0), + Long.numberOfTrailingZeros(1l << 0), + Long.numberOfTrailingZeros(1l << 1), + Long.numberOfTrailingZeros(1l << 2), + Long.numberOfTrailingZeros(1l << 3), + Long.numberOfTrailingZeros(1l << 4), + Long.numberOfTrailingZeros(1l << 5), + Long.numberOfTrailingZeros(1l << 6), + Long.numberOfTrailingZeros(1l << 7), + Long.numberOfTrailingZeros(1l << 8), + Long.numberOfTrailingZeros(1l << 9), + Long.numberOfTrailingZeros(1l << 10), + Long.numberOfTrailingZeros(1l << 11), + Long.numberOfTrailingZeros(1l << 12), + Long.numberOfTrailingZeros(1l << 13), + Long.numberOfTrailingZeros(1l << 14), + Long.numberOfTrailingZeros(1l << 15), + Long.numberOfTrailingZeros(1l << 16), + Long.numberOfTrailingZeros(1l << 17), + Long.numberOfTrailingZeros(1l << 18), + Long.numberOfTrailingZeros(1l << 19), + Long.numberOfTrailingZeros(1l << 20), + Long.numberOfTrailingZeros(1l << 21), + Long.numberOfTrailingZeros(1l << 22), + Long.numberOfTrailingZeros(1l << 23), + Long.numberOfTrailingZeros(1l << 24), + Long.numberOfTrailingZeros(1l << 25), + Long.numberOfTrailingZeros(1l << 26), + Long.numberOfTrailingZeros(1l << 27), + Long.numberOfTrailingZeros(1l << 28), + Long.numberOfTrailingZeros(1l << 29), + Long.numberOfTrailingZeros(1l << 30), + Long.numberOfTrailingZeros(1l << 31), + Long.numberOfTrailingZeros(1l << 32), + Long.numberOfTrailingZeros(1l << 33), + Long.numberOfTrailingZeros(1l << 34), + Long.numberOfTrailingZeros(1l << 35), + Long.numberOfTrailingZeros(1l << 36), + Long.numberOfTrailingZeros(1l << 37), + Long.numberOfTrailingZeros(1l << 38), + Long.numberOfTrailingZeros(1l << 39), + Long.numberOfTrailingZeros(1l << 40), + Long.numberOfTrailingZeros(1l << 41), + Long.numberOfTrailingZeros(1l << 42), + Long.numberOfTrailingZeros(1l << 43), + Long.numberOfTrailingZeros(1l << 44), + Long.numberOfTrailingZeros(1l << 45), + Long.numberOfTrailingZeros(1l << 46), + Long.numberOfTrailingZeros(1l << 47), + Long.numberOfTrailingZeros(1l << 48), + Long.numberOfTrailingZeros(1l << 49), + Long.numberOfTrailingZeros(1l << 50), + Long.numberOfTrailingZeros(1l << 51), + Long.numberOfTrailingZeros(1l << 52), + Long.numberOfTrailingZeros(1l << 53), + Long.numberOfTrailingZeros(1l << 54), + Long.numberOfTrailingZeros(1l << 55), + Long.numberOfTrailingZeros(1l << 56), + Long.numberOfTrailingZeros(1l << 57), + Long.numberOfTrailingZeros(1l << 58), + Long.numberOfTrailingZeros(1l << 59), + Long.numberOfTrailingZeros(1l << 60), + Long.numberOfTrailingZeros(1l << 61), + Long.numberOfTrailingZeros(1l << 62), + Long.numberOfTrailingZeros(1l << 63), + }; + } + + // Test the range of CTZ with random long input. + // The result of CTZ should be in range [0, 64], so CTZs in this test are + // expected to be optimized away, and the test should always return false. + @Test + @IR(failOn = IRNode.COUNT_TRAILING_ZEROS_L) + public boolean ctzCompareLong(long randLong) { + return Long.numberOfTrailingZeros(randLong) < 0 + || Long.numberOfTrailingZeros(randLong) > 64; + } + + // Test the combination of CTZ and division by 8. + // The result of CTZ should be positive, so the division by 8 should be + // optimized to a simple right shift without rounding. + @Test + @IR(counts = {IRNode.COUNT_TRAILING_ZEROS_L, "1", + IRNode.RSHIFT_I, "1", + IRNode.URSHIFT_I, "0", + IRNode.ADD_I, "0"}) + public int ctzDiv8Long(long randLong) { + return Long.numberOfTrailingZeros(randLong) / 8; + } + + // Test the output range of CTZ with random input range. + @Test + public int ctzRandLimitLong(long randLong) { + randLong = RANGE_LONG.clamp(randLong); + int result = Long.numberOfLeadingZeros(randLong); + return getResultChecksum64(result); + } + + @DontCompile + public int ctzRandLimitInterpretedLong(long randLong) { + randLong = RANGE_LONG.clamp(randLong); + int result = Long.numberOfLeadingZeros(randLong); + return getResultChecksum64(result); + } + + record IntRange(int lo, int hi) { + IntRange { + if (lo > hi) { + throw new IllegalArgumentException("lo > hi"); + } + } + + @ForceInline + int clamp(int v) { + return v < lo ? lo : v > hi ? hi : v; + } + + static IntRange generate(Generator g) { + int a = g.next(), b = g.next(); + return a < b ? new IntRange(a, b) : new IntRange(b, a); + } + } + + record LongRange(long lo, long hi) { + LongRange { + if (lo > hi) { + throw new IllegalArgumentException("lo > hi"); + } + } + + @ForceInline + long clamp(long v) { + return v < lo ? lo : v > hi ? hi : v; + } + + static LongRange generate(Generator g) { + long a = g.next(), b = g.next(); + return a < b ? new LongRange(a, b) : new LongRange(b, a); + } + } + + @ForceInline + int getResultChecksum32(int result) { + int sum = 0; + if (result < LIMITS_32_0) sum += 1; + if (result < LIMITS_32_1) sum += 2; + if (result < LIMITS_32_2) sum += 4; + if (result < LIMITS_32_3) sum += 8; + if (result > LIMITS_32_4) sum += 16; + if (result > LIMITS_32_5) sum += 32; + if (result > LIMITS_32_6) sum += 64; + if (result > LIMITS_32_7) sum += 128; + return sum; + } + + @ForceInline + int getResultChecksum64(int result) { + int sum = 0; + if (result < LIMITS_64_0) sum += 1; + if (result < LIMITS_64_1) sum += 2; + if (result < LIMITS_64_2) sum += 4; + if (result < LIMITS_64_3) sum += 8; + if (result > LIMITS_64_4) sum += 16; + if (result > LIMITS_64_5) sum += 32; + if (result > LIMITS_64_6) sum += 64; + if (result > LIMITS_64_7) sum += 128; + return sum; + } +} diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java index 85595b9b632..1648135434a 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java @@ -1661,6 +1661,16 @@ public class IRNode { vectorNode(POPCOUNT_VL, "PopCountVL", TYPE_LONG); } + public static final String COUNT_TRAILING_ZEROS_I = PREFIX + "COUNT_TRAILING_ZEROS_I" + POSTFIX; + static { + beforeMatchingNameRegex(COUNT_TRAILING_ZEROS_I, "CountTrailingZerosI"); + } + + public static final String COUNT_TRAILING_ZEROS_L = PREFIX + "COUNT_TRAILING_ZEROS_L" + POSTFIX; + static { + beforeMatchingNameRegex(COUNT_TRAILING_ZEROS_L, "CountTrailingZerosL"); + } + public static final String COUNT_TRAILING_ZEROS_VL = VECTOR_PREFIX + "COUNT_TRAILING_ZEROS_VL" + POSTFIX; static { vectorNode(COUNT_TRAILING_ZEROS_VL, "CountTrailingZerosV", TYPE_LONG); @@ -1671,6 +1681,16 @@ public class IRNode { vectorNode(COUNT_TRAILING_ZEROS_VI, "CountTrailingZerosV", TYPE_INT); } + public static final String COUNT_LEADING_ZEROS_I = PREFIX + "COUNT_LEADING_ZEROS_I" + POSTFIX; + static { + beforeMatchingNameRegex(COUNT_LEADING_ZEROS_I, "CountLeadingZerosI"); + } + + public static final String COUNT_LEADING_ZEROS_L = PREFIX + "COUNT_LEADING_ZEROS_L" + POSTFIX; + static { + beforeMatchingNameRegex(COUNT_LEADING_ZEROS_L, "CountLeadingZerosL"); + } + public static final String COUNT_LEADING_ZEROS_VL = VECTOR_PREFIX + "COUNT_LEADING_ZEROS_VL" + POSTFIX; static { vectorNode(COUNT_LEADING_ZEROS_VL, "CountLeadingZerosV", TYPE_LONG); diff --git a/test/micro/org/openjdk/bench/vm/compiler/CountLeadingZeros.java b/test/micro/org/openjdk/bench/vm/compiler/CountLeadingZeros.java new file mode 100644 index 00000000000..dc06e3ae764 --- /dev/null +++ b/test/micro/org/openjdk/bench/vm/compiler/CountLeadingZeros.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2025 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. + */ + +package org.openjdk.bench.vm.compiler; + +import org.openjdk.jmh.annotations.*; + +import java.util.concurrent.TimeUnit; +import java.util.concurrent.ThreadLocalRandom; + +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@Fork(value = 3) +@Warmup(iterations = 10, time = 1) +@Measurement(iterations = 5, time = 1) +@State(Scope.Thread) +public class CountLeadingZeros { + private long[] longArray = new long[1000]; + + @Setup + public void setup() { + for (int i = 0; i < longArray.length; i++) { + longArray[i] = ThreadLocalRandom.current().nextLong(); + } + } + + @Benchmark + public int benchNumberOfNibbles() { + int sum = 0; + for (long l : longArray) { + sum += numberOfNibbles((int) l); + } + return sum; + } + + public static int numberOfNibbles(int i) { + int mag = Integer.SIZE - Integer.numberOfLeadingZeros(i); + return Math.max((mag + 3) / 4, 1); + } + + @Benchmark + public int benchClzLongConstrained() { + int sum = 0; + for (long l : longArray) { + sum += clzLongConstrained(l); + } + return sum; + } + + public static int clzLongConstrained(long param) { + long constrainedParam = Math.min(175, Math.max(param, 160)); + return Long.numberOfLeadingZeros(constrainedParam); + } +} From 6700baa5052046f53eb1b04ed3205bbd8e9e9070 Mon Sep 17 00:00:00 2001 From: Hamlin Li Date: Mon, 8 Dec 2025 13:38:22 +0000 Subject: [PATCH 204/706] 8357551: RISC-V: support CMoveF/D vectorization Reviewed-by: fyang, luhenry --- .../cpu/riscv/c2_MacroAssembler_riscv.cpp | 77 ++ .../cpu/riscv/c2_MacroAssembler_riscv.hpp | 7 + .../cpu/riscv/macroAssembler_riscv.cpp | 256 +++- .../cpu/riscv/macroAssembler_riscv.hpp | 18 + src/hotspot/cpu/riscv/riscv.ad | 282 +++- ...onalMove.java => TestConditionalMove.java} | 731 ++++++++++- .../c2/irTests/TestFPComparison2.java | 1140 ++++++++++++++++- .../TestScalarConditionalMoveCmpObj.java | 357 ++++++ .../compiler/lib/ir_framework/IRNode.java | 30 + .../bench/java/lang/ClassComparison.java | 45 +- .../openjdk/bench/java/lang/FPComparison.java | 176 ++- .../bench/java/lang/IntegerComparison.java | 292 ++++- .../bench/java/lang/LongComparison.java | 291 ++++- .../bench/java/lang/PointerComparison.java | 45 +- 14 files changed, 3604 insertions(+), 143 deletions(-) rename test/hotspot/jtreg/compiler/c2/irTests/{TestVectorConditionalMove.java => TestConditionalMove.java} (76%) create mode 100644 test/hotspot/jtreg/compiler/c2/irTests/TestScalarConditionalMoveCmpObj.java diff --git a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp index abbd7eedbba..dcf20752a21 100644 --- a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp @@ -2067,6 +2067,83 @@ void C2_MacroAssembler::enc_cmove_cmp_fp(int cmpFlag, FloatRegister op1, FloatRe } } +void C2_MacroAssembler::enc_cmove_fp_cmp(int cmpFlag, Register op1, Register op2, + FloatRegister dst, FloatRegister src, bool is_single) { + bool is_unsigned = (cmpFlag & unsigned_branch_mask) == unsigned_branch_mask; + int op_select = cmpFlag & (~unsigned_branch_mask); + + switch (op_select) { + case BoolTest::eq: + cmov_fp_eq(op1, op2, dst, src, is_single); + break; + case BoolTest::ne: + cmov_fp_ne(op1, op2, dst, src, is_single); + break; + case BoolTest::le: + if (is_unsigned) { + cmov_fp_leu(op1, op2, dst, src, is_single); + } else { + cmov_fp_le(op1, op2, dst, src, is_single); + } + break; + case BoolTest::ge: + if (is_unsigned) { + cmov_fp_geu(op1, op2, dst, src, is_single); + } else { + cmov_fp_ge(op1, op2, dst, src, is_single); + } + break; + case BoolTest::lt: + if (is_unsigned) { + cmov_fp_ltu(op1, op2, dst, src, is_single); + } else { + cmov_fp_lt(op1, op2, dst, src, is_single); + } + break; + case BoolTest::gt: + if (is_unsigned) { + cmov_fp_gtu(op1, op2, dst, src, is_single); + } else { + cmov_fp_gt(op1, op2, dst, src, is_single); + } + break; + default: + assert(false, "unsupported compare condition"); + ShouldNotReachHere(); + } +} + +void C2_MacroAssembler::enc_cmove_fp_cmp_fp(int cmpFlag, + FloatRegister op1, FloatRegister op2, + FloatRegister dst, FloatRegister src, + bool cmp_single, bool cmov_single) { + int op_select = cmpFlag & (~unsigned_branch_mask); + + switch (op_select) { + case BoolTest::eq: + cmov_fp_cmp_fp_eq(op1, op2, dst, src, cmp_single, cmov_single); + break; + case BoolTest::ne: + cmov_fp_cmp_fp_ne(op1, op2, dst, src, cmp_single, cmov_single); + break; + case BoolTest::le: + cmov_fp_cmp_fp_le(op1, op2, dst, src, cmp_single, cmov_single); + break; + case BoolTest::ge: + cmov_fp_cmp_fp_ge(op1, op2, dst, src, cmp_single, cmov_single); + break; + case BoolTest::lt: + cmov_fp_cmp_fp_lt(op1, op2, dst, src, cmp_single, cmov_single); + break; + case BoolTest::gt: + cmov_fp_cmp_fp_gt(op1, op2, dst, src, cmp_single, cmov_single); + break; + default: + assert(false, "unsupported compare condition"); + ShouldNotReachHere(); + } +} + // Set dst to NaN if any NaN input. void C2_MacroAssembler::minmax_fp(FloatRegister dst, FloatRegister src1, FloatRegister src2, FLOAT_TYPE ft, bool is_min) { diff --git a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp index f08e5e27c87..fa87ceba295 100644 --- a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp @@ -132,6 +132,13 @@ FloatRegister op1, FloatRegister op2, Register dst, Register src, bool is_single); + void enc_cmove_fp_cmp(int cmpFlag, Register op1, Register op2, + FloatRegister dst, FloatRegister src, bool is_single); + + void enc_cmove_fp_cmp_fp(int cmpFlag, FloatRegister op1, FloatRegister op2, + FloatRegister dst, FloatRegister src, + bool cmp_single, bool cmov_single); + void spill(Register r, bool is64, int offset) { is64 ? sd(r, Address(sp, offset)) : sw(r, Address(sp, offset)); diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index 7a8496ae42b..a14a051fd3b 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -1233,7 +1233,119 @@ void MacroAssembler::cmov_gtu(Register cmp1, Register cmp2, Register dst, Regist bind(no_set); } -// ----------- cmove, compare float ----------- +// ----------- cmove float/double ----------- + +void MacroAssembler::cmov_fp_eq(Register cmp1, Register cmp2, FloatRegister dst, FloatRegister src, bool is_single) { + Label no_set; + bne(cmp1, cmp2, no_set); + if (is_single) { + fmv_s(dst, src); + } else { + fmv_d(dst, src); + } + bind(no_set); +} + +void MacroAssembler::cmov_fp_ne(Register cmp1, Register cmp2, FloatRegister dst, FloatRegister src, bool is_single) { + Label no_set; + beq(cmp1, cmp2, no_set); + if (is_single) { + fmv_s(dst, src); + } else { + fmv_d(dst, src); + } + bind(no_set); +} + +void MacroAssembler::cmov_fp_le(Register cmp1, Register cmp2, FloatRegister dst, FloatRegister src, bool is_single) { + Label no_set; + bgt(cmp1, cmp2, no_set); + if (is_single) { + fmv_s(dst, src); + } else { + fmv_d(dst, src); + } + bind(no_set); +} + +void MacroAssembler::cmov_fp_leu(Register cmp1, Register cmp2, FloatRegister dst, FloatRegister src, bool is_single) { + Label no_set; + bgtu(cmp1, cmp2, no_set); + if (is_single) { + fmv_s(dst, src); + } else { + fmv_d(dst, src); + } + bind(no_set); +} + +void MacroAssembler::cmov_fp_ge(Register cmp1, Register cmp2, FloatRegister dst, FloatRegister src, bool is_single) { + Label no_set; + blt(cmp1, cmp2, no_set); + if (is_single) { + fmv_s(dst, src); + } else { + fmv_d(dst, src); + } + bind(no_set); +} + +void MacroAssembler::cmov_fp_geu(Register cmp1, Register cmp2, FloatRegister dst, FloatRegister src, bool is_single) { + Label no_set; + bltu(cmp1, cmp2, no_set); + if (is_single) { + fmv_s(dst, src); + } else { + fmv_d(dst, src); + } + bind(no_set); +} + +void MacroAssembler::cmov_fp_lt(Register cmp1, Register cmp2, FloatRegister dst, FloatRegister src, bool is_single) { + Label no_set; + bge(cmp1, cmp2, no_set); + if (is_single) { + fmv_s(dst, src); + } else { + fmv_d(dst, src); + } + bind(no_set); +} + +void MacroAssembler::cmov_fp_ltu(Register cmp1, Register cmp2, FloatRegister dst, FloatRegister src, bool is_single) { + Label no_set; + bgeu(cmp1, cmp2, no_set); + if (is_single) { + fmv_s(dst, src); + } else { + fmv_d(dst, src); + } + bind(no_set); +} + +void MacroAssembler::cmov_fp_gt(Register cmp1, Register cmp2, FloatRegister dst, FloatRegister src, bool is_single) { + Label no_set; + ble(cmp1, cmp2, no_set); + if (is_single) { + fmv_s(dst, src); + } else { + fmv_d(dst, src); + } + bind(no_set); +} + +void MacroAssembler::cmov_fp_gtu(Register cmp1, Register cmp2, FloatRegister dst, FloatRegister src, bool is_single) { + Label no_set; + bleu(cmp1, cmp2, no_set); + if (is_single) { + fmv_s(dst, src); + } else { + fmv_d(dst, src); + } + bind(no_set); +} + +// ----------- cmove, compare float/double ----------- // // For CmpF/D + CMoveI/L, ordered ones are quite straight and simple, // so, just list behaviour of unordered ones as follow. @@ -1391,6 +1503,148 @@ void MacroAssembler::cmov_cmp_fp_gt(FloatRegister cmp1, FloatRegister cmp2, Regi bind(no_set); } +// ----------- cmove float/double, compare float/double ----------- + +// Move src to dst only if cmp1 == cmp2, +// otherwise leave dst unchanged, including the case where one of them is NaN. +// Clarification: +// java code : cmp1 != cmp2 ? dst : src +// transformed to : CMove dst, (cmp1 eq cmp2), dst, src +void MacroAssembler::cmov_fp_cmp_fp_eq(FloatRegister cmp1, FloatRegister cmp2, + FloatRegister dst, FloatRegister src, + bool cmp_single, bool cmov_single) { + Label no_set; + if (cmp_single) { + // jump if cmp1 != cmp2, including the case of NaN + // not jump (i.e. move src to dst) if cmp1 == cmp2 + float_bne(cmp1, cmp2, no_set); + } else { + double_bne(cmp1, cmp2, no_set); + } + if (cmov_single) { + fmv_s(dst, src); + } else { + fmv_d(dst, src); + } + bind(no_set); +} + +// Keep dst unchanged only if cmp1 == cmp2, +// otherwise move src to dst, including the case where one of them is NaN. +// Clarification: +// java code : cmp1 == cmp2 ? dst : src +// transformed to : CMove dst, (cmp1 ne cmp2), dst, src +void MacroAssembler::cmov_fp_cmp_fp_ne(FloatRegister cmp1, FloatRegister cmp2, + FloatRegister dst, FloatRegister src, + bool cmp_single, bool cmov_single) { + Label no_set; + if (cmp_single) { + // jump if cmp1 == cmp2 + // not jump (i.e. move src to dst) if cmp1 != cmp2, including the case of NaN + float_beq(cmp1, cmp2, no_set); + } else { + double_beq(cmp1, cmp2, no_set); + } + if (cmov_single) { + fmv_s(dst, src); + } else { + fmv_d(dst, src); + } + bind(no_set); +} + +// When cmp1 <= cmp2 or any of them is NaN then dst = src, otherwise, dst = dst +// Clarification +// scenario 1: +// java code : cmp2 < cmp1 ? dst : src +// transformed to : CMove dst, (cmp1 le cmp2), dst, src +// scenario 2: +// java code : cmp1 > cmp2 ? dst : src +// transformed to : CMove dst, (cmp1 le cmp2), dst, src +void MacroAssembler::cmov_fp_cmp_fp_le(FloatRegister cmp1, FloatRegister cmp2, + FloatRegister dst, FloatRegister src, + bool cmp_single, bool cmov_single) { + Label no_set; + if (cmp_single) { + // jump if cmp1 > cmp2 + // not jump (i.e. move src to dst) if cmp1 <= cmp2 or either is NaN + float_bgt(cmp1, cmp2, no_set); + } else { + double_bgt(cmp1, cmp2, no_set); + } + if (cmov_single) { + fmv_s(dst, src); + } else { + fmv_d(dst, src); + } + bind(no_set); +} + +void MacroAssembler::cmov_fp_cmp_fp_ge(FloatRegister cmp1, FloatRegister cmp2, + FloatRegister dst, FloatRegister src, + bool cmp_single, bool cmov_single) { + Label no_set; + if (cmp_single) { + // jump if cmp1 < cmp2 or either is NaN + // not jump (i.e. move src to dst) if cmp1 >= cmp2 + float_blt(cmp1, cmp2, no_set, false, true); + } else { + double_blt(cmp1, cmp2, no_set, false, true); + } + if (cmov_single) { + fmv_s(dst, src); + } else { + fmv_d(dst, src); + } + bind(no_set); +} + +// When cmp1 < cmp2 or any of them is NaN then dst = src, otherwise, dst = dst +// Clarification +// scenario 1: +// java code : cmp2 <= cmp1 ? dst : src +// transformed to : CMove dst, (cmp1 lt cmp2), dst, src +// scenario 2: +// java code : cmp1 >= cmp2 ? dst : src +// transformed to : CMove dst, (cmp1 lt cmp2), dst, src +void MacroAssembler::cmov_fp_cmp_fp_lt(FloatRegister cmp1, FloatRegister cmp2, + FloatRegister dst, FloatRegister src, + bool cmp_single, bool cmov_single) { + Label no_set; + if (cmp_single) { + // jump if cmp1 >= cmp2 + // not jump (i.e. move src to dst) if cmp1 < cmp2 or either is NaN + float_bge(cmp1, cmp2, no_set); + } else { + double_bge(cmp1, cmp2, no_set); + } + if (cmov_single) { + fmv_s(dst, src); + } else { + fmv_d(dst, src); + } + bind(no_set); +} + +void MacroAssembler::cmov_fp_cmp_fp_gt(FloatRegister cmp1, FloatRegister cmp2, + FloatRegister dst, FloatRegister src, + bool cmp_single, bool cmov_single) { + Label no_set; + if (cmp_single) { + // jump if cmp1 <= cmp2 or either is NaN + // not jump (i.e. move src to dst) if cmp1 > cmp2 + float_ble(cmp1, cmp2, no_set, false, true); + } else { + double_ble(cmp1, cmp2, no_set, false, true); + } + if (cmov_single) { + fmv_s(dst, src); + } else { + fmv_d(dst, src); + } + bind(no_set); +} + // Float compare branch instructions #define INSN(NAME, FLOATCMP, BRANCH) \ diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp index 1908b9a9605..3b021388fa5 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp @@ -665,6 +665,24 @@ class MacroAssembler: public Assembler { void cmov_cmp_fp_lt(FloatRegister cmp1, FloatRegister cmp2, Register dst, Register src, bool is_single); void cmov_cmp_fp_gt(FloatRegister cmp1, FloatRegister cmp2, Register dst, Register src, bool is_single); + void cmov_fp_eq(Register cmp1, Register cmp2, FloatRegister dst, FloatRegister src, bool is_single); + void cmov_fp_ne(Register cmp1, Register cmp2, FloatRegister dst, FloatRegister src, bool is_single); + void cmov_fp_le(Register cmp1, Register cmp2, FloatRegister dst, FloatRegister src, bool is_single); + void cmov_fp_leu(Register cmp1, Register cmp2, FloatRegister dst, FloatRegister src, bool is_single); + void cmov_fp_ge(Register cmp1, Register cmp2, FloatRegister dst, FloatRegister src, bool is_single); + void cmov_fp_geu(Register cmp1, Register cmp2, FloatRegister dst, FloatRegister src, bool is_single); + void cmov_fp_lt(Register cmp1, Register cmp2, FloatRegister dst, FloatRegister src, bool is_single); + void cmov_fp_ltu(Register cmp1, Register cmp2, FloatRegister dst, FloatRegister src, bool is_single); + void cmov_fp_gt(Register cmp1, Register cmp2, FloatRegister dst, FloatRegister src, bool is_single); + void cmov_fp_gtu(Register cmp1, Register cmp2, FloatRegister dst, FloatRegister src, bool is_single); + + void cmov_fp_cmp_fp_eq(FloatRegister cmp1, FloatRegister cmp2, FloatRegister dst, FloatRegister src, bool cmp_single, bool cmov_single); + void cmov_fp_cmp_fp_ne(FloatRegister cmp1, FloatRegister cmp2, FloatRegister dst, FloatRegister src, bool cmp_single, bool cmov_single); + void cmov_fp_cmp_fp_le(FloatRegister cmp1, FloatRegister cmp2, FloatRegister dst, FloatRegister src, bool cmp_single, bool cmov_single); + void cmov_fp_cmp_fp_ge(FloatRegister cmp1, FloatRegister cmp2, FloatRegister dst, FloatRegister src, bool cmp_single, bool cmov_single); + void cmov_fp_cmp_fp_lt(FloatRegister cmp1, FloatRegister cmp2, FloatRegister dst, FloatRegister src, bool cmp_single, bool cmov_single); + void cmov_fp_cmp_fp_gt(FloatRegister cmp1, FloatRegister cmp2, FloatRegister dst, FloatRegister src, bool cmp_single, bool cmov_single); + public: // We try to follow risc-v asm menomics. // But as we don't layout a reachable GOT, diff --git a/src/hotspot/cpu/riscv/riscv.ad b/src/hotspot/cpu/riscv/riscv.ad index 3f5dd4ad0ee..96984ba9a42 100644 --- a/src/hotspot/cpu/riscv/riscv.ad +++ b/src/hotspot/cpu/riscv/riscv.ad @@ -1924,8 +1924,6 @@ bool Matcher::match_rule_supported(int opcode) { case Op_SubHF: return UseZfh; - case Op_CMoveF: - case Op_CMoveD: case Op_CMoveP: case Op_CMoveN: return false; @@ -10466,6 +10464,286 @@ instruct cmovL_cmpP(iRegLNoSp dst, iRegL src, iRegP op1, iRegP op2, cmpOpU cop) ins_pipe(pipe_class_compare); %} +// --------- CMoveF --------- + +instruct cmovF_cmpI(fRegF dst, fRegF src, iRegI op1, iRegI op2, cmpOp cop) %{ + match(Set dst (CMoveF (Binary cop (CmpI op1 op2)) (Binary dst src))); + ins_cost(ALU_COST + BRANCH_COST); + + format %{ + "CMoveF $dst, ($op1 $cop $op2), $dst, $src\t#@cmovF_cmpI\n\t" + %} + + ins_encode %{ + __ enc_cmove_fp_cmp($cop$$cmpcode, + as_Register($op1$$reg), as_Register($op2$$reg), + as_FloatRegister($dst$$reg), as_FloatRegister($src$$reg), true /* is_single */); + %} + + ins_pipe(pipe_class_compare); +%} + +instruct cmovF_cmpU(fRegF dst, fRegF src, iRegI op1, iRegI op2, cmpOpU cop) %{ + match(Set dst (CMoveF (Binary cop (CmpU op1 op2)) (Binary dst src))); + ins_cost(ALU_COST + BRANCH_COST); + + format %{ + "CMoveF $dst, ($op1 $cop $op2), $dst, $src\t#@cmovF_cmpU\n\t" + %} + + ins_encode %{ + __ enc_cmove_fp_cmp($cop$$cmpcode | C2_MacroAssembler::unsigned_branch_mask, + as_Register($op1$$reg), as_Register($op2$$reg), + as_FloatRegister($dst$$reg), as_FloatRegister($src$$reg), true /* is_single */); + %} + + ins_pipe(pipe_class_compare); +%} + +instruct cmovF_cmpL(fRegF dst, fRegF src, iRegL op1, iRegL op2, cmpOp cop) %{ + match(Set dst (CMoveF (Binary cop (CmpL op1 op2)) (Binary dst src))); + ins_cost(ALU_COST + BRANCH_COST); + + format %{ + "CMoveF $dst, ($op1 $cop $op2), $dst, $src\t#@cmovF_cmpL\n\t" + %} + + ins_encode %{ + __ enc_cmove_fp_cmp($cop$$cmpcode, + as_Register($op1$$reg), as_Register($op2$$reg), + as_FloatRegister($dst$$reg), as_FloatRegister($src$$reg), true /* is_single */); + %} + + ins_pipe(pipe_class_compare); +%} + +instruct cmovF_cmpUL(fRegF dst, fRegF src, iRegL op1, iRegL op2, cmpOpU cop) %{ + match(Set dst (CMoveF (Binary cop (CmpUL op1 op2)) (Binary dst src))); + ins_cost(ALU_COST + BRANCH_COST); + + format %{ + "CMoveF $dst, ($op1 $cop $op2), $dst, $src\t#@cmovF_cmpUL\n\t" + %} + + ins_encode %{ + __ enc_cmove_fp_cmp($cop$$cmpcode | C2_MacroAssembler::unsigned_branch_mask, + as_Register($op1$$reg), as_Register($op2$$reg), + as_FloatRegister($dst$$reg), as_FloatRegister($src$$reg), true /* is_single */); + %} + + ins_pipe(pipe_class_compare); +%} + +instruct cmovF_cmpF(fRegF dst, fRegF src, fRegF op1, fRegF op2, cmpOp cop) %{ + match(Set dst (CMoveF (Binary cop (CmpF op1 op2)) (Binary dst src))); + ins_cost(ALU_COST + BRANCH_COST); + + format %{ + "CMoveF $dst, ($op1 $cop $op2), $dst, $src\t#@cmovF_cmpF\n\t" + %} + + ins_encode %{ + __ enc_cmove_fp_cmp_fp($cop$$cmpcode, + as_FloatRegister($op1$$reg), as_FloatRegister($op2$$reg), + as_FloatRegister($dst$$reg), as_FloatRegister($src$$reg), + true /* cmp_single */, true /* cmov_single */); + %} + + ins_pipe(pipe_class_compare); +%} + +instruct cmovF_cmpD(fRegF dst, fRegF src, fRegD op1, fRegD op2, cmpOp cop) %{ + match(Set dst (CMoveF (Binary cop (CmpD op1 op2)) (Binary dst src))); + ins_cost(ALU_COST + BRANCH_COST); + + format %{ + "CMoveF $dst, ($op1 $cop $op2), $dst, $src\t#@cmovF_cmpD\n\t" + %} + + ins_encode %{ + __ enc_cmove_fp_cmp_fp($cop$$cmpcode | C2_MacroAssembler::double_branch_mask, + as_FloatRegister($op1$$reg), as_FloatRegister($op2$$reg), + as_FloatRegister($dst$$reg), as_FloatRegister($src$$reg), + false /* cmp_single */, true /* cmov_single */); + %} + + ins_pipe(pipe_class_compare); +%} + +instruct cmovF_cmpN(fRegF dst, fRegF src, iRegN op1, iRegN op2, cmpOp cop) %{ + match(Set dst (CMoveF (Binary cop (CmpN op1 op2)) (Binary dst src))); + ins_cost(ALU_COST + BRANCH_COST); + + format %{ + "CMoveF $dst, ($op1 $cop $op2), $dst, $src\t#@cmovF_cmpN\n\t" + %} + + ins_encode %{ + __ enc_cmove_fp_cmp($cop$$cmpcode | C2_MacroAssembler::unsigned_branch_mask, + as_Register($op1$$reg), as_Register($op2$$reg), + as_FloatRegister($dst$$reg), as_FloatRegister($src$$reg), true /* is_single */); + %} + + ins_pipe(pipe_class_compare); +%} + +instruct cmovF_cmpP(fRegF dst, fRegF src, iRegP op1, iRegP op2, cmpOp cop) %{ + match(Set dst (CMoveF (Binary cop (CmpP op1 op2)) (Binary dst src))); + ins_cost(ALU_COST + BRANCH_COST); + + format %{ + "CMoveF $dst, ($op1 $cop $op2), $dst, $src\t#@cmovF_cmpP\n\t" + %} + + ins_encode %{ + __ enc_cmove_fp_cmp($cop$$cmpcode | C2_MacroAssembler::unsigned_branch_mask, + as_Register($op1$$reg), as_Register($op2$$reg), + as_FloatRegister($dst$$reg), as_FloatRegister($src$$reg), true /* is_single */); + %} + + ins_pipe(pipe_class_compare); +%} + +// --------- CMoveD --------- + +instruct cmovD_cmpI(fRegD dst, fRegD src, iRegI op1, iRegI op2, cmpOp cop) %{ + match(Set dst (CMoveD (Binary cop (CmpI op1 op2)) (Binary dst src))); + ins_cost(ALU_COST + BRANCH_COST); + + format %{ + "CMoveD $dst, ($op1 $cop $op2), $dst, $src\t#@cmovD_cmpI\n\t" + %} + + ins_encode %{ + __ enc_cmove_fp_cmp($cop$$cmpcode, + as_Register($op1$$reg), as_Register($op2$$reg), + as_FloatRegister($dst$$reg), as_FloatRegister($src$$reg), false /* is_single */); + %} + + ins_pipe(pipe_class_compare); +%} + +instruct cmovD_cmpU(fRegD dst, fRegD src, iRegI op1, iRegI op2, cmpOpU cop) %{ + match(Set dst (CMoveD (Binary cop (CmpU op1 op2)) (Binary dst src))); + ins_cost(ALU_COST + BRANCH_COST); + + format %{ + "CMoveD $dst, ($op1 $cop $op2), $dst, $src\t#@cmovD_cmpU\n\t" + %} + + ins_encode %{ + __ enc_cmove_fp_cmp($cop$$cmpcode | C2_MacroAssembler::unsigned_branch_mask, + as_Register($op1$$reg), as_Register($op2$$reg), + as_FloatRegister($dst$$reg), as_FloatRegister($src$$reg), false /* is_single */); + %} + + ins_pipe(pipe_class_compare); +%} + +instruct cmovD_cmpL(fRegD dst, fRegD src, iRegL op1, iRegL op2, cmpOp cop) %{ + match(Set dst (CMoveD (Binary cop (CmpL op1 op2)) (Binary dst src))); + ins_cost(ALU_COST + BRANCH_COST); + + format %{ + "CMoveD $dst, ($op1 $cop $op2), $dst, $src\t#@cmovD_cmpL\n\t" + %} + + ins_encode %{ + __ enc_cmove_fp_cmp($cop$$cmpcode, + as_Register($op1$$reg), as_Register($op2$$reg), + as_FloatRegister($dst$$reg), as_FloatRegister($src$$reg), false /* is_single */); + %} + + ins_pipe(pipe_class_compare); +%} + +instruct cmovD_cmpUL(fRegD dst, fRegD src, iRegL op1, iRegL op2, cmpOpU cop) %{ + match(Set dst (CMoveD (Binary cop (CmpUL op1 op2)) (Binary dst src))); + ins_cost(ALU_COST + BRANCH_COST); + + format %{ + "CMoveD $dst, ($op1 $cop $op2), $dst, $src\t#@cmovD_cmpUL\n\t" + %} + + ins_encode %{ + __ enc_cmove_fp_cmp($cop$$cmpcode | C2_MacroAssembler::unsigned_branch_mask, + as_Register($op1$$reg), as_Register($op2$$reg), + as_FloatRegister($dst$$reg), as_FloatRegister($src$$reg), false /* is_single */); + %} + + ins_pipe(pipe_class_compare); +%} + +instruct cmovD_cmpF(fRegD dst, fRegD src, fRegF op1, fRegF op2, cmpOp cop) %{ + match(Set dst (CMoveD (Binary cop (CmpF op1 op2)) (Binary dst src))); + ins_cost(ALU_COST + BRANCH_COST); + + format %{ + "CMoveD $dst, ($op1 $cop $op2), $dst, $src\t#@cmovD_cmpF\n\t" + %} + + ins_encode %{ + __ enc_cmove_fp_cmp_fp($cop$$cmpcode, + as_FloatRegister($op1$$reg), as_FloatRegister($op2$$reg), + as_FloatRegister($dst$$reg), as_FloatRegister($src$$reg), + true /* cmp_single */, false /* cmov_single */); + %} + + ins_pipe(pipe_class_compare); +%} + +instruct cmovD_cmpD(fRegD dst, fRegD src, fRegD op1, fRegD op2, cmpOp cop) %{ + match(Set dst (CMoveD (Binary cop (CmpD op1 op2)) (Binary dst src))); + ins_cost(ALU_COST + BRANCH_COST); + + format %{ + "CMoveD $dst, ($op1 $cop $op2), $dst, $src\t#@cmovD_cmpD\n\t" + %} + + ins_encode %{ + __ enc_cmove_fp_cmp_fp($cop$$cmpcode | C2_MacroAssembler::double_branch_mask, + as_FloatRegister($op1$$reg), as_FloatRegister($op2$$reg), + as_FloatRegister($dst$$reg), as_FloatRegister($src$$reg), + false /* cmp_single */, false /* cmov_single */); + %} + + ins_pipe(pipe_class_compare); +%} + +instruct cmovD_cmpN(fRegD dst, fRegD src, iRegN op1, iRegN op2, cmpOp cop) %{ + match(Set dst (CMoveD (Binary cop (CmpN op1 op2)) (Binary dst src))); + ins_cost(ALU_COST + BRANCH_COST); + + format %{ + "CMoveD $dst, ($op1 $cop $op2), $dst, $src\t#@cmovD_cmpN\n\t" + %} + + ins_encode %{ + __ enc_cmove_fp_cmp($cop$$cmpcode | C2_MacroAssembler::unsigned_branch_mask, + as_Register($op1$$reg), as_Register($op2$$reg), + as_FloatRegister($dst$$reg), as_FloatRegister($src$$reg), false /* is_single */); + %} + + ins_pipe(pipe_class_compare); +%} + +instruct cmovD_cmpP(fRegD dst, fRegD src, iRegP op1, iRegP op2, cmpOp cop) %{ + match(Set dst (CMoveD (Binary cop (CmpP op1 op2)) (Binary dst src))); + ins_cost(ALU_COST + BRANCH_COST); + + format %{ + "CMoveD $dst, ($op1 $cop $op2), $dst, $src\t#@cmovD_cmpP\n\t" + %} + + ins_encode %{ + __ enc_cmove_fp_cmp($cop$$cmpcode | C2_MacroAssembler::unsigned_branch_mask, + as_Register($op1$$reg), as_Register($op2$$reg), + as_FloatRegister($dst$$reg), as_FloatRegister($src$$reg), false /* is_single */); + %} + + ins_pipe(pipe_class_compare); +%} + // ============================================================================ // Procedure Call/Return Instructions diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestVectorConditionalMove.java b/test/hotspot/jtreg/compiler/c2/irTests/TestConditionalMove.java similarity index 76% rename from test/hotspot/jtreg/compiler/c2/irTests/TestVectorConditionalMove.java rename to test/hotspot/jtreg/compiler/c2/irTests/TestConditionalMove.java index 4759add94e9..c531f73b71d 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/TestVectorConditionalMove.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestConditionalMove.java @@ -1,6 +1,7 @@ /* - * Copyright (c) 2022, Arm Limited. All rights reserved. - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Arm Limited. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Rivos Inc. 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,14 +36,15 @@ import jdk.test.lib.Utils; * @key randomness * @summary Auto-vectorization enhancement to support vector conditional move. * @library /test/lib / - * @run driver compiler.c2.irTests.TestVectorConditionalMove + * @run driver compiler.c2.irTests.TestConditionalMove */ -public class TestVectorConditionalMove { +public class TestConditionalMove { final private static int SIZE = 1024; private static final Random RANDOM = Utils.getRandomInstance(); public static void main(String[] args) { + // Vectorizaion: +UseCMoveUnconditionally, +UseVectorCmov // Cross-product: +-AlignVector and +-UseCompactObjectHeaders TestFramework.runWithFlags("-XX:+UseCMoveUnconditionally", "-XX:+UseVectorCmov", "-XX:-UseCompactObjectHeaders", "-XX:-AlignVector"); @@ -52,6 +54,12 @@ public class TestVectorConditionalMove { "-XX:+UseCompactObjectHeaders", "-XX:-AlignVector"); TestFramework.runWithFlags("-XX:+UseCMoveUnconditionally", "-XX:+UseVectorCmov", "-XX:+UseCompactObjectHeaders", "-XX:+AlignVector"); + + // Scalar: +UseCMoveUnconditionally, -UseVectorCmov + TestFramework.runWithFlags("-XX:+UseCMoveUnconditionally", "-XX:-UseVectorCmov", + "-XX:+UnlockExperimentalVMOptions", "-XX:-UseCompactObjectHeaders"); + TestFramework.runWithFlags("-XX:+UseCMoveUnconditionally", "-XX:-UseVectorCmov", + "-XX:+UnlockExperimentalVMOptions", "-XX:+UseCompactObjectHeaders"); } // Compare 2 values, and pick one of them @@ -564,6 +572,7 @@ public class TestVectorConditionalMove { return (a > b) ? c : d; } + // Double comparison private int cmoveDGTforI(double a, double b, int c, int d) { return (a > b) ? c : d; } @@ -586,7 +595,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_F, ">0", IRNode.VECTOR_BLEND_F, ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_F, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveVFGT(float[] a, float[] b, float[] c) { for (int i = 0; i < a.length; i++) { c[i] = (a[i] > b[i]) ? a[i] : b[i]; @@ -598,7 +613,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_F, ">0", IRNode.VECTOR_BLEND_F, ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_F, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveVFGTSwap(float[] a, float[] b, float[] c) { for (int i = 0; i < a.length; i++) { c[i] = (b[i] > a[i]) ? a[i] : b[i]; @@ -610,7 +631,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_F, ">0", IRNode.VECTOR_BLEND_F, ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_F, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveVFLT(float[] a, float[] b, float[] c) { for (int i = 0; i < a.length; i++) { c[i] = (a[i] < b[i]) ? a[i] : b[i]; @@ -622,7 +649,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_F, ">0", IRNode.VECTOR_BLEND_F, ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_F, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveVFLTSwap(float[] a, float[] b, float[] c) { for (int i = 0; i < a.length; i++) { c[i] = (b[i] < a[i]) ? a[i] : b[i]; @@ -634,7 +667,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_F, ">0", IRNode.VECTOR_BLEND_F, ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_F, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveVFEQ(float[] a, float[] b, float[] c) { for (int i = 0; i < a.length; i++) { c[i] = (a[i] == b[i]) ? a[i] : b[i]; @@ -646,7 +685,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_D, ">0", IRNode.VECTOR_BLEND_D, ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_D, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveVDLE(double[] a, double[] b, double[] c) { for (int i = 0; i < a.length; i++) { c[i] = (a[i] <= b[i]) ? a[i] : b[i]; @@ -658,7 +703,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_D, ">0", IRNode.VECTOR_BLEND_D, ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_D, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveVDLESwap(double[] a, double[] b, double[] c) { for (int i = 0; i < a.length; i++) { c[i] = (b[i] <= a[i]) ? a[i] : b[i]; @@ -670,7 +721,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_D, ">0", IRNode.VECTOR_BLEND_D, ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_D, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveVDGE(double[] a, double[] b, double[] c) { for (int i = 0; i < a.length; i++) { c[i] = (a[i] >= b[i]) ? a[i] : b[i]; @@ -682,7 +739,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_D, ">0", IRNode.VECTOR_BLEND_D, ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_D, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveVDGESwap(double[] a, double[] b, double[] c) { for (int i = 0; i < a.length; i++) { c[i] = (b[i] >= a[i]) ? a[i] : b[i]; @@ -694,7 +757,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_D, ">0", IRNode.VECTOR_BLEND_D, ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_D, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveVDNE(double[] a, double[] b, double[] c) { for (int i = 0; i < a.length; i++) { c[i] = (a[i] != b[i]) ? a[i] : b[i]; @@ -707,7 +776,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_F, ">0", IRNode.VECTOR_BLEND_F, ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_F, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveFGTforFConst(float[] a, float[] b, float[] c) { for (int i = 0; i < a.length; i++) { c[i] = (a[i] > b[i]) ? 0.1f : -0.1f; @@ -719,7 +794,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_F, ">0", IRNode.VECTOR_BLEND_F, ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_F, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveFGEforFConst(float[] a, float[] b, float[] c) { for (int i = 0; i < a.length; i++) { c[i] = (a[i] >= b[i]) ? 0.1f : -0.1f; @@ -731,7 +812,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_F, ">0", IRNode.VECTOR_BLEND_F, ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_F, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveFLTforFConst(float[] a, float[] b, float[] c) { for (int i = 0; i < a.length; i++) { c[i] = (a[i] < b[i]) ? 0.1f : -0.1f; @@ -743,7 +830,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_F, ">0", IRNode.VECTOR_BLEND_F, ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_F, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveFLEforFConst(float[] a, float[] b, float[] c) { for (int i = 0; i < a.length; i++) { c[i] = (a[i] <= b[i]) ? 0.1f : -0.1f; @@ -755,7 +848,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_F, ">0", IRNode.VECTOR_BLEND_F, ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_F, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveFEQforFConst(float[] a, float[] b, float[] c) { for (int i = 0; i < a.length; i++) { c[i] = (a[i] == b[i]) ? 0.1f : -0.1f; @@ -767,7 +866,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_F, ">0", IRNode.VECTOR_BLEND_F, ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_F, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveFNEQforFConst(float[] a, float[] b, float[] c) { for (int i = 0; i < a.length; i++) { c[i] = (a[i] != b[i]) ? 0.1f : -0.1f; @@ -779,8 +884,19 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_F, ">0", IRNode.VECTOR_BLEND_F, ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfOr = {"UseCompactObjectHeaders", "false", "AlignVector", "false"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfAnd = {"UseCompactObjectHeaders", "false", "UseVectorCmov", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}) + @IR(counts = {IRNode.LOAD_VECTOR_F, ">0", + IRNode.VECTOR_MASK_CMP_F, ">0", + IRNode.VECTOR_BLEND_F, ">0", + IRNode.STORE_VECTOR, ">0"}, + applyIfAnd = {"AlignVector", "false", "UseVectorCmov", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_F, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveFLTforFConstH2(float[] a, float[] b, float[] c) { for (int i = 0; i < a.length; i+=2) { c[i+0] = (a[i+0] < b[i+0]) ? 0.1f : -0.1f; @@ -797,8 +913,19 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_F, ">0", IRNode.VECTOR_BLEND_F, ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfOr = {"UseCompactObjectHeaders", "false", "AlignVector", "false"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfAnd = {"UseCompactObjectHeaders", "false", "UseVectorCmov", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}) + @IR(counts = {IRNode.LOAD_VECTOR_F, ">0", + IRNode.VECTOR_MASK_CMP_F, ">0", + IRNode.VECTOR_BLEND_F, ">0", + IRNode.STORE_VECTOR, ">0"}, + applyIfAnd = {"AlignVector", "false", "UseVectorCmov", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_F, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveFLEforFConstH2(float[] a, float[] b, float[] c) { for (int i = 0; i < a.length; i+=2) { c[i+0] = (a[i+0] <= b[i+0]) ? 0.1f : -0.1f; @@ -815,7 +942,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_F, "=0", IRNode.VECTOR_BLEND_F, "=0", IRNode.STORE_VECTOR, "=0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_F, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveFYYforFConstH2(float[] a, float[] b, float[] c) { for (int i = 0; i < a.length; i+=2) { c[i+0] = (a[i+0] <= b[i+0]) ? 0.1f : -0.1f; @@ -828,7 +961,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_F, "=0", IRNode.VECTOR_BLEND_F, "=0", IRNode.STORE_VECTOR, "=0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_F, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveFXXforFConstH2(float[] a, float[] b, float[] c) { for (int i = 0; i < a.length; i+=2) { c[i+0] = (a[i+0] < b[i+0]) ? 0.1f : -0.1f; @@ -841,7 +980,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_D, ">0", IRNode.VECTOR_BLEND_D, ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_D, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveDGTforDConst(double[] a, double[] b, double[] c) { for (int i = 0; i < a.length; i++) { c[i] = (a[i] > b[i]) ? 0.1 : -0.1; @@ -853,7 +998,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_D, ">0", IRNode.VECTOR_BLEND_D, ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_D, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveDGEforDConst(double[] a, double[] b, double[] c) { for (int i = 0; i < a.length; i++) { c[i] = (a[i] >= b[i]) ? 0.1 : -0.1; @@ -865,7 +1016,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_D, ">0", IRNode.VECTOR_BLEND_D, ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_D, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveDLTforDConst(double[] a, double[] b, double[] c) { for (int i = 0; i < a.length; i++) { c[i] = (a[i] < b[i]) ? 0.1 : -0.1; @@ -877,7 +1034,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_D, ">0", IRNode.VECTOR_BLEND_D, ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_D, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveDLEforDConst(double[] a, double[] b, double[] c) { for (int i = 0; i < a.length; i++) { c[i] = (a[i] <= b[i]) ? 0.1 : -0.1; @@ -889,7 +1052,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_D, ">0", IRNode.VECTOR_BLEND_D, ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_D, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveDEQforDConst(double[] a, double[] b, double[] c) { for (int i = 0; i < a.length; i++) { c[i] = (a[i] == b[i]) ? 0.1 : -0.1; @@ -901,7 +1070,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_D, ">0", IRNode.VECTOR_BLEND_D, ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_D, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveDNEQforDConst(double[] a, double[] b, double[] c) { for (int i = 0; i < a.length; i++) { c[i] = (a[i] != b[i]) ? 0.1 : -0.1; @@ -913,7 +1088,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_D, ">0", IRNode.VECTOR_BLEND_D, ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_D, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveDLTforDConstH2(double[] a, double[] b, double[] c) { for (int i = 0; i < a.length; i+=2) { c[i+0] = (a[i+0] < b[i+0]) ? 0.1 : -0.1; @@ -926,7 +1107,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_D, ">0", IRNode.VECTOR_BLEND_D, ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_D, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveDLEforDConstH2(double[] a, double[] b, double[] c) { for (int i = 0; i < a.length; i+=2) { c[i+0] = (a[i+0] <= b[i+0]) ? 0.1 : -0.1; @@ -939,7 +1126,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_D, "=0", IRNode.VECTOR_BLEND_D, "=0", IRNode.STORE_VECTOR, "=0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_D, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveDYYforDConstH2(double[] a, double[] b, double[] c) { for (int i = 0; i < a.length; i+=2) { c[i+0] = (a[i+0] <= b[i+0]) ? 0.1 : -0.1; @@ -952,7 +1145,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_D, "=0", IRNode.VECTOR_BLEND_D, "=0", IRNode.STORE_VECTOR, "=0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_D, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveDXXforDConstH2(double[] a, double[] b, double[] c) { for (int i = 0; i < a.length; i+=2) { c[i+0] = (a[i+0] < b[i+0]) ? 0.1 : -0.1; @@ -966,10 +1165,15 @@ public class TestVectorConditionalMove { // do not float down into the branches, I compute a value, and store it to r2 (same as r, except that the // compilation does not know that). // So far, vectorization only works for CMoveF/D, with same data-width comparison (F/I for F, D/L for D). + // TODO: enable CMOVE_I/L verification when it's guaranteed to generate CMOVE_I/L, JDK-8371984. + // // Signed comparison: I/L // I fo I @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_I, ">0", IRNode.CMP_I, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveIEQforI(int[] a, int[] b, int[] c, int[] d, int[] r, int[] r2) { for (int i = 0; i < a.length; i++) { int cc = c[i]; @@ -981,6 +1185,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_I, ">0", IRNode.CMP_I, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveINEforI(int[] a, int[] b, int[] c, int[] d, int[] r, int[] r2) { for (int i = 0; i < a.length; i++) { int cc = c[i]; @@ -992,6 +1199,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_I, ">0", IRNode.CMP_I, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveIGTforI(int[] a, int[] b, int[] c, int[] d, int[] r, int[] r2) { for (int i = 0; i < a.length; i++) { int cc = c[i]; @@ -1003,6 +1213,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_I, ">0", IRNode.CMP_I, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveIGEforI(int[] a, int[] b, int[] c, int[] d, int[] r, int[] r2) { for (int i = 0; i < a.length; i++) { int cc = c[i]; @@ -1014,6 +1227,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_I, ">0", IRNode.CMP_I, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveILTforI(int[] a, int[] b, int[] c, int[] d, int[] r, int[] r2) { for (int i = 0; i < a.length; i++) { int cc = c[i]; @@ -1025,6 +1241,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_I, ">0", IRNode.CMP_I, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveILEforI(int[] a, int[] b, int[] c, int[] d, int[] r, int[] r2) { for (int i = 0; i < a.length; i++) { int cc = c[i]; @@ -1037,6 +1256,9 @@ public class TestVectorConditionalMove { // I fo L @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_L, ">0", IRNode.CMP_I, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveIEQforL(int[] a, int[] b, long[] c, long[] d, long[] r, long[] r2) { for (int i = 0; i < a.length; i++) { long cc = c[i]; @@ -1048,6 +1270,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_L, ">0", IRNode.CMP_I, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveINEforL(int[] a, int[] b, long[] c, long[] d, long[] r, long[] r2) { for (int i = 0; i < a.length; i++) { long cc = c[i]; @@ -1059,6 +1284,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_L, ">0", IRNode.CMP_I, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveIGTforL(int[] a, int[] b, long[] c, long[] d, long[] r, long[] r2) { for (int i = 0; i < a.length; i++) { long cc = c[i]; @@ -1070,6 +1298,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_L, ">0", IRNode.CMP_I, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveIGEforL(int[] a, int[] b, long[] c, long[] d, long[] r, long[] r2) { for (int i = 0; i < a.length; i++) { long cc = c[i]; @@ -1081,6 +1312,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_L, ">0", IRNode.CMP_I, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveILTforL(int[] a, int[] b, long[] c, long[] d, long[] r, long[] r2) { for (int i = 0; i < a.length; i++) { long cc = c[i]; @@ -1092,6 +1326,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_L, ">0", IRNode.CMP_I, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveILEforL(int[] a, int[] b, long[] c, long[] d, long[] r, long[] r2) { for (int i = 0; i < a.length; i++) { long cc = c[i]; @@ -1108,7 +1345,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_I, IRNode.VECTOR_SIZE + "min(max_int, max_float)", ">0", IRNode.VECTOR_BLEND_F, IRNode.VECTOR_SIZE + "min(max_int, max_float)", ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_I, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveIEQforF(int[] a, int[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -1124,7 +1367,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_I, IRNode.VECTOR_SIZE + "min(max_int, max_float)", ">0", IRNode.VECTOR_BLEND_F, IRNode.VECTOR_SIZE + "min(max_int, max_float)", ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_I, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveINEforF(int[] a, int[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -1140,7 +1389,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_I, IRNode.VECTOR_SIZE + "min(max_int, max_float)", ">0", IRNode.VECTOR_BLEND_F, IRNode.VECTOR_SIZE + "min(max_int, max_float)", ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_I, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveIGTforF(int[] a, int[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -1156,7 +1411,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_I, IRNode.VECTOR_SIZE + "min(max_int, max_float)", ">0", IRNode.VECTOR_BLEND_F, IRNode.VECTOR_SIZE + "min(max_int, max_float)", ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_I, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveIGEforF(int[] a, int[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -1172,7 +1433,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_I, IRNode.VECTOR_SIZE + "min(max_int, max_float)", ">0", IRNode.VECTOR_BLEND_F, IRNode.VECTOR_SIZE + "min(max_int, max_float)", ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_I, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveILTforF(int[] a, int[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -1188,7 +1455,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_I, IRNode.VECTOR_SIZE + "min(max_int, max_float)", ">0", IRNode.VECTOR_BLEND_F, IRNode.VECTOR_SIZE + "min(max_int, max_float)", ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_I, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveILEforF(int[] a, int[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -1201,6 +1474,9 @@ public class TestVectorConditionalMove { // I fo D @Test @IR(failOn = {IRNode.STORE_VECTOR}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_I, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveIEQforD(int[] a, int[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { double cc = c[i]; @@ -1212,6 +1488,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_I, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveINEforD(int[] a, int[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { double cc = c[i]; @@ -1223,6 +1502,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_I, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveIGTforD(int[] a, int[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { double cc = c[i]; @@ -1234,6 +1516,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_I, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveIGEforD(int[] a, int[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { double cc = c[i]; @@ -1245,6 +1530,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_I, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveILTforD(int[] a, int[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { double cc = c[i]; @@ -1256,6 +1544,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_I, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveILEforD(int[] a, int[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { double cc = c[i]; @@ -1268,6 +1559,9 @@ public class TestVectorConditionalMove { // L fo I @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_I, ">0", IRNode.CMP_L, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveLEQforI(long[] a, long[] b, int[] c, int[] d, int[] r, int[] r2) { for (int i = 0; i < a.length; i++) { int cc = c[i]; @@ -1279,6 +1573,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_I, ">0", IRNode.CMP_L, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveLNEforI(long[] a, long[] b, int[] c, int[] d, int[] r, int[] r2) { for (int i = 0; i < a.length; i++) { int cc = c[i]; @@ -1290,6 +1587,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_I, ">0", IRNode.CMP_L, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveLGTforI(long[] a, long[] b, int[] c, int[] d, int[] r, int[] r2) { for (int i = 0; i < a.length; i++) { int cc = c[i]; @@ -1301,6 +1601,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_I, ">0", IRNode.CMP_L, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveLGEforI(long[] a, long[] b, int[] c, int[] d, int[] r, int[] r2) { for (int i = 0; i < a.length; i++) { int cc = c[i]; @@ -1312,6 +1615,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_I, ">0", IRNode.CMP_L, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveLLTforI(long[] a, long[] b, int[] c, int[] d, int[] r, int[] r2) { for (int i = 0; i < a.length; i++) { int cc = c[i]; @@ -1323,6 +1629,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_I, ">0", IRNode.CMP_L, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveLLEforI(long[] a, long[] b, int[] c, int[] d, int[] r, int[] r2) { for (int i = 0; i < a.length; i++) { int cc = c[i]; @@ -1335,6 +1644,9 @@ public class TestVectorConditionalMove { // L fo L @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_L, ">0", IRNode.CMP_L, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveLEQforL(long[] a, long[] b, long[] c, long[] d, long[] r, long[] r2) { for (int i = 0; i < a.length; i++) { long cc = c[i]; @@ -1346,6 +1658,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_L, ">0", IRNode.CMP_L, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveLNEforL(long[] a, long[] b, long[] c, long[] d, long[] r, long[] r2) { for (int i = 0; i < a.length; i++) { long cc = c[i]; @@ -1357,6 +1672,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_L, ">0", IRNode.CMP_L, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveLGTforL(long[] a, long[] b, long[] c, long[] d, long[] r, long[] r2) { for (int i = 0; i < a.length; i++) { long cc = c[i]; @@ -1368,6 +1686,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_L, ">0", IRNode.CMP_L, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveLGEforL(long[] a, long[] b, long[] c, long[] d, long[] r, long[] r2) { for (int i = 0; i < a.length; i++) { long cc = c[i]; @@ -1379,6 +1700,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_L, ">0", IRNode.CMP_L, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveLLTforL(long[] a, long[] b, long[] c, long[] d, long[] r, long[] r2) { for (int i = 0; i < a.length; i++) { long cc = c[i]; @@ -1390,6 +1714,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_L, ">0", IRNode.CMP_L, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveLLEforL(long[] a, long[] b, long[] c, long[] d, long[] r, long[] r2) { for (int i = 0; i < a.length; i++) { long cc = c[i]; @@ -1402,6 +1729,9 @@ public class TestVectorConditionalMove { // L fo F @Test @IR(failOn = {IRNode.STORE_VECTOR}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_L, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveLEQforF(long[] a, long[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -1413,6 +1743,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_L, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveLNEforF(long[] a, long[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -1424,6 +1757,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_L, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveLGTforF(long[] a, long[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -1435,6 +1771,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_L, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveLGEforF(long[] a, long[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -1446,6 +1785,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_L, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveLLTforF(long[] a, long[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -1457,6 +1799,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_L, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveLLEforF(long[] a, long[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -1473,7 +1818,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_L, IRNode.VECTOR_SIZE + "min(max_long, max_double)", ">0", IRNode.VECTOR_BLEND_D, IRNode.VECTOR_SIZE + "min(max_long, max_double)", ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_L, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) // Requires avx2, else L is restricted to 16 byte, and D has 32. That leads to a vector elements mismatch of 2 to 4. private static void testCMoveLEQforD(long[] a, long[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { @@ -1490,7 +1841,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_L, IRNode.VECTOR_SIZE + "min(max_long, max_double)", ">0", IRNode.VECTOR_BLEND_D, IRNode.VECTOR_SIZE + "min(max_long, max_double)", ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_L, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) // Requires avx2, else L is restricted to 16 byte, and D has 32. That leads to a vector elements mismatch of 2 to 4. private static void testCMoveLNEforD(long[] a, long[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { @@ -1507,7 +1864,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_L, IRNode.VECTOR_SIZE + "min(max_long, max_double)", ">0", IRNode.VECTOR_BLEND_D, IRNode.VECTOR_SIZE + "min(max_long, max_double)", ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_L, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) // Requires avx2, else L is restricted to 16 byte, and D has 32. That leads to a vector elements mismatch of 2 to 4. private static void testCMoveLGTforD(long[] a, long[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { @@ -1524,7 +1887,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_L, IRNode.VECTOR_SIZE + "min(max_long, max_double)", ">0", IRNode.VECTOR_BLEND_D, IRNode.VECTOR_SIZE + "min(max_long, max_double)", ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_L, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) // Requires avx2, else L is restricted to 16 byte, and D has 32. That leads to a vector elements mismatch of 2 to 4. private static void testCMoveLGEforD(long[] a, long[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { @@ -1541,7 +1910,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_L, IRNode.VECTOR_SIZE + "min(max_long, max_double)", ">0", IRNode.VECTOR_BLEND_D, IRNode.VECTOR_SIZE + "min(max_long, max_double)", ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_L, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) // Requires avx2, else L is restricted to 16 byte, and D has 32. That leads to a vector elements mismatch of 2 to 4. private static void testCMoveLLTforD(long[] a, long[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { @@ -1558,7 +1933,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_L, IRNode.VECTOR_SIZE + "min(max_long, max_double)", ">0", IRNode.VECTOR_BLEND_D, IRNode.VECTOR_SIZE + "min(max_long, max_double)", ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_L, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) // Requires avx2, else L is restricted to 16 byte, and D has 32. That leads to a vector elements mismatch of 2 to 4. private static void testCMoveLLEforD(long[] a, long[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { @@ -1573,6 +1954,9 @@ public class TestVectorConditionalMove { // I fo I @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_I, ">0", IRNode.CMP_U, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveUIEQforI(int[] a, int[] b, int[] c, int[] d, int[] r, int[] r2) { for (int i = 0; i < a.length; i++) { int cc = c[i]; @@ -1584,6 +1968,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_I, ">0", IRNode.CMP_U, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveUINEforI(int[] a, int[] b, int[] c, int[] d, int[] r, int[] r2) { for (int i = 0; i < a.length; i++) { int cc = c[i]; @@ -1595,6 +1982,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_I, ">0", IRNode.CMP_U, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveUIGTforI(int[] a, int[] b, int[] c, int[] d, int[] r, int[] r2) { for (int i = 0; i < a.length; i++) { int cc = c[i]; @@ -1606,6 +1996,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_I, ">0", IRNode.CMP_U, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveUIGEforI(int[] a, int[] b, int[] c, int[] d, int[] r, int[] r2) { for (int i = 0; i < a.length; i++) { int cc = c[i]; @@ -1617,6 +2010,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_I, ">0", IRNode.CMP_U, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveUILTforI(int[] a, int[] b, int[] c, int[] d, int[] r, int[] r2) { for (int i = 0; i < a.length; i++) { int cc = c[i]; @@ -1628,6 +2024,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_I, ">0", IRNode.CMP_U, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveUILEforI(int[] a, int[] b, int[] c, int[] d, int[] r, int[] r2) { for (int i = 0; i < a.length; i++) { int cc = c[i]; @@ -1640,6 +2039,9 @@ public class TestVectorConditionalMove { // I fo L @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_L, ">0", IRNode.CMP_U, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveUIEQforL(int[] a, int[] b, long[] c, long[] d, long[] r, long[] r2) { for (int i = 0; i < a.length; i++) { long cc = c[i]; @@ -1651,6 +2053,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_L, ">0", IRNode.CMP_U, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveUINEforL(int[] a, int[] b, long[] c, long[] d, long[] r, long[] r2) { for (int i = 0; i < a.length; i++) { long cc = c[i]; @@ -1662,6 +2067,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_L, ">0", IRNode.CMP_U, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveUIGTforL(int[] a, int[] b, long[] c, long[] d, long[] r, long[] r2) { for (int i = 0; i < a.length; i++) { long cc = c[i]; @@ -1673,6 +2081,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_L, ">0", IRNode.CMP_U, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveUIGEforL(int[] a, int[] b, long[] c, long[] d, long[] r, long[] r2) { for (int i = 0; i < a.length; i++) { long cc = c[i]; @@ -1684,6 +2095,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_L, ">0", IRNode.CMP_U, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveUILTforL(int[] a, int[] b, long[] c, long[] d, long[] r, long[] r2) { for (int i = 0; i < a.length; i++) { long cc = c[i]; @@ -1695,6 +2109,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_L, ">0", IRNode.CMP_U, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveUILEforL(int[] a, int[] b, long[] c, long[] d, long[] r, long[] r2) { for (int i = 0; i < a.length; i++) { long cc = c[i]; @@ -1711,7 +2128,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_I, IRNode.VECTOR_SIZE + "min(max_int, max_float)", ">0", IRNode.VECTOR_BLEND_F, IRNode.VECTOR_SIZE + "min(max_int, max_float)", ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_U, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveUIEQforF(int[] a, int[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -1727,7 +2150,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_I, IRNode.VECTOR_SIZE + "min(max_int, max_float)", ">0", IRNode.VECTOR_BLEND_F, IRNode.VECTOR_SIZE + "min(max_int, max_float)", ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_U, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveUINEforF(int[] a, int[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -1743,7 +2172,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_I, IRNode.VECTOR_SIZE + "min(max_int, max_float)", ">0", IRNode.VECTOR_BLEND_F, IRNode.VECTOR_SIZE + "min(max_int, max_float)", ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_U, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveUIGTforF(int[] a, int[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -1759,7 +2194,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_I, IRNode.VECTOR_SIZE + "min(max_int, max_float)", ">0", IRNode.VECTOR_BLEND_F, IRNode.VECTOR_SIZE + "min(max_int, max_float)", ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_U, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveUIGEforF(int[] a, int[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -1775,7 +2216,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_I, IRNode.VECTOR_SIZE + "min(max_int, max_float)", ">0", IRNode.VECTOR_BLEND_F, IRNode.VECTOR_SIZE + "min(max_int, max_float)", ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_U, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveUILTforF(int[] a, int[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -1791,7 +2238,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_I, IRNode.VECTOR_SIZE + "min(max_int, max_float)", ">0", IRNode.VECTOR_BLEND_F, IRNode.VECTOR_SIZE + "min(max_int, max_float)", ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_U, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveUILEforF(int[] a, int[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -1804,6 +2257,9 @@ public class TestVectorConditionalMove { // I fo D @Test @IR(failOn = {IRNode.STORE_VECTOR}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_U, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveUIEQforD(int[] a, int[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { double cc = c[i]; @@ -1815,6 +2271,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_U, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveUINEforD(int[] a, int[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { double cc = c[i]; @@ -1826,6 +2285,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_U, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveUIGTforD(int[] a, int[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { double cc = c[i]; @@ -1837,6 +2299,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_U, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveUIGEforD(int[] a, int[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { double cc = c[i]; @@ -1848,6 +2313,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_U, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveUILTforD(int[] a, int[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { double cc = c[i]; @@ -1859,6 +2327,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_U, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveUILEforD(int[] a, int[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { double cc = c[i]; @@ -1871,6 +2342,9 @@ public class TestVectorConditionalMove { // L fo I @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_I, ">0", IRNode.CMP_UL, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveULEQforI(long[] a, long[] b, int[] c, int[] d, int[] r, int[] r2) { for (int i = 0; i < a.length; i++) { int cc = c[i]; @@ -1882,6 +2356,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_I, ">0", IRNode.CMP_UL, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveULNEforI(long[] a, long[] b, int[] c, int[] d, int[] r, int[] r2) { for (int i = 0; i < a.length; i++) { int cc = c[i]; @@ -1893,6 +2370,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_I, ">0", IRNode.CMP_UL, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveULGTforI(long[] a, long[] b, int[] c, int[] d, int[] r, int[] r2) { for (int i = 0; i < a.length; i++) { int cc = c[i]; @@ -1904,6 +2384,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_I, ">0", IRNode.CMP_UL, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveULGEforI(long[] a, long[] b, int[] c, int[] d, int[] r, int[] r2) { for (int i = 0; i < a.length; i++) { int cc = c[i]; @@ -1915,6 +2398,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_I, ">0", IRNode.CMP_UL, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveULLTforI(long[] a, long[] b, int[] c, int[] d, int[] r, int[] r2) { for (int i = 0; i < a.length; i++) { int cc = c[i]; @@ -1926,6 +2412,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_I, ">0", IRNode.CMP_UL, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveULLEforI(long[] a, long[] b, int[] c, int[] d, int[] r, int[] r2) { for (int i = 0; i < a.length; i++) { int cc = c[i]; @@ -1938,6 +2427,9 @@ public class TestVectorConditionalMove { // L fo L @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_L, ">0", IRNode.CMP_UL, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveULEQforL(long[] a, long[] b, long[] c, long[] d, long[] r, long[] r2) { for (int i = 0; i < a.length; i++) { long cc = c[i]; @@ -1949,6 +2441,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_L, ">0", IRNode.CMP_UL, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveULNEforL(long[] a, long[] b, long[] c, long[] d, long[] r, long[] r2) { for (int i = 0; i < a.length; i++) { long cc = c[i]; @@ -1960,6 +2455,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_L, ">0", IRNode.CMP_UL, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveULGTforL(long[] a, long[] b, long[] c, long[] d, long[] r, long[] r2) { for (int i = 0; i < a.length; i++) { long cc = c[i]; @@ -1971,6 +2469,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_L, ">0", IRNode.CMP_UL, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveULGEforL(long[] a, long[] b, long[] c, long[] d, long[] r, long[] r2) { for (int i = 0; i < a.length; i++) { long cc = c[i]; @@ -1982,6 +2483,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_L, ">0", IRNode.CMP_UL, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveULLTforL(long[] a, long[] b, long[] c, long[] d, long[] r, long[] r2) { for (int i = 0; i < a.length; i++) { long cc = c[i]; @@ -1993,6 +2497,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_L, ">0", IRNode.CMP_UL, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveULLEforL(long[] a, long[] b, long[] c, long[] d, long[] r, long[] r2) { for (int i = 0; i < a.length; i++) { long cc = c[i]; @@ -2005,6 +2512,9 @@ public class TestVectorConditionalMove { // L fo F @Test @IR(failOn = {IRNode.STORE_VECTOR}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_UL, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveULEQforF(long[] a, long[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -2016,6 +2526,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_UL, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveULNEforF(long[] a, long[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -2027,6 +2540,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_UL, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveULGTforF(long[] a, long[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -2038,6 +2554,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_UL, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveULGEforF(long[] a, long[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -2049,6 +2568,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_UL, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveULLTforF(long[] a, long[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -2060,6 +2582,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_UL, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveULLEforF(long[] a, long[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -2076,7 +2601,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_L, IRNode.VECTOR_SIZE + "min(max_long, max_double)", ">0", IRNode.VECTOR_BLEND_D, IRNode.VECTOR_SIZE + "min(max_long, max_double)", ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_UL, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) // Requires avx2, else L is restricted to 16 byte, and D has 32. That leads to a vector elements mismatch of 2 to 4. private static void testCMoveULEQforD(long[] a, long[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { @@ -2093,7 +2624,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_L, IRNode.VECTOR_SIZE + "min(max_long, max_double)", ">0", IRNode.VECTOR_BLEND_D, IRNode.VECTOR_SIZE + "min(max_long, max_double)", ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_UL, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) // Requires avx2, else L is restricted to 16 byte, and D has 32. That leads to a vector elements mismatch of 2 to 4. private static void testCMoveULNEforD(long[] a, long[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { @@ -2110,7 +2647,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_L, IRNode.VECTOR_SIZE + "min(max_long, max_double)", ">0", IRNode.VECTOR_BLEND_D, IRNode.VECTOR_SIZE + "min(max_long, max_double)", ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_UL, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) // Requires avx2, else L is restricted to 16 byte, and D has 32. That leads to a vector elements mismatch of 2 to 4. private static void testCMoveULGTforD(long[] a, long[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { @@ -2127,7 +2670,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_L, IRNode.VECTOR_SIZE + "min(max_long, max_double)", ">0", IRNode.VECTOR_BLEND_D, IRNode.VECTOR_SIZE + "min(max_long, max_double)", ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_UL, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) // Requires avx2, else L is restricted to 16 byte, and D has 32. That leads to a vector elements mismatch of 2 to 4. private static void testCMoveULGEforD(long[] a, long[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { @@ -2144,7 +2693,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_L, IRNode.VECTOR_SIZE + "min(max_long, max_double)", ">0", IRNode.VECTOR_BLEND_D, IRNode.VECTOR_SIZE + "min(max_long, max_double)", ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_UL, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) // Requires avx2, else L is restricted to 16 byte, and D has 32. That leads to a vector elements mismatch of 2 to 4. private static void testCMoveULLTforD(long[] a, long[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { @@ -2161,7 +2716,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_L, IRNode.VECTOR_SIZE + "min(max_long, max_double)", ">0", IRNode.VECTOR_BLEND_D, IRNode.VECTOR_SIZE + "min(max_long, max_double)", ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_UL, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) // Requires avx2, else L is restricted to 16 byte, and D has 32. That leads to a vector elements mismatch of 2 to 4. private static void testCMoveULLEforD(long[] a, long[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { @@ -2174,6 +2735,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_I, ">0", IRNode.CMP_F, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveFGTforI(float[] a, float[] b, int[] c, int[] d, int[] r, int[] r2) { for (int i = 0; i < a.length; i++) { int cc = c[i]; @@ -2185,6 +2749,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_L, ">0", IRNode.CMP_F, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveFGTforL(float[] a, float[] b, long[] c, long[] d, long[] r, long[] r2) { for (int i = 0; i < a.length; i++) { long cc = c[i]; @@ -2199,7 +2766,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_F, ">0", IRNode.VECTOR_BLEND_F, ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_F, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveFGTforF(float[] a, float[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -2211,6 +2784,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_F, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveFGTforD(float[] a, float[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { double cc = c[i]; @@ -2222,6 +2798,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_I, ">0", IRNode.CMP_D, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveDGTforI(double[] a, double[] b, int[] c, int[] d, int[] r, int[] r2) { for (int i = 0; i < a.length; i++) { int cc = c[i]; @@ -2233,6 +2812,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_L, ">0", IRNode.CMP_D, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveDGTforL(double[] a, double[] b, long[] c, long[] d, long[] r, long[] r2) { for (int i = 0; i < a.length; i++) { long cc = c[i]; @@ -2244,6 +2826,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_D, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveDGTforF(double[] a, double[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -2258,7 +2843,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_D, ">0", IRNode.VECTOR_BLEND_D, ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_D, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveDGTforD(double[] a, double[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { double cc = c[i]; @@ -2274,7 +2865,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_F, ">0", IRNode.VECTOR_BLEND_F, ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_F, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveFGTforFCmpCon1(float a, float[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < b.length; i++) { float cc = c[i]; @@ -2289,7 +2886,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_F, ">0", IRNode.VECTOR_BLEND_F, ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_F, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveFGTforFCmpCon2(float[] a, float b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestFPComparison2.java b/test/hotspot/jtreg/compiler/c2/irTests/TestFPComparison2.java index 59c70b6873f..8cf3f728666 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/TestFPComparison2.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestFPComparison2.java @@ -28,7 +28,7 @@ import java.util.List; /* * @test - * @bug 8358892 + * @bug 8358892 8357551 * @summary The test is to trigger code path of BoolTest::ge/gt in C2_MacroAssembler::enc_cmove_cmp_fp * @requires os.arch == "riscv64" * @requires vm.debug @@ -77,18 +77,33 @@ public class TestFPComparison2 { public static void main(String[] args) { List options = List.of("-XX:-TieredCompilation", "-Xlog:jit+compilation=trace"); // Booltest::ge - TestFramework framework = new TestFramework(Test_ge_1.class); + TestFramework + framework = new TestFramework(Test_ge_1.class); + framework.addFlags(options.toArray(new String[0])).start(); + framework = new TestFramework(Test_ge_cmove_fp_1.class); framework.addFlags(options.toArray(new String[0])).start(); framework = new TestFramework(Test_ge_2.class); framework.addFlags(options.toArray(new String[0])).start(); + framework = new TestFramework(Test_ge_cmove_fp_2.class); + framework.addFlags(options.toArray(new String[0])).start(); // Booltest::gt framework = new TestFramework(Test_gt_1.class); framework.addFlags(options.toArray(new String[0])).start(); + framework = new TestFramework(Test_gt_cmove_fp_1.class); + framework.addFlags(options.toArray(new String[0])).start(); framework = new TestFramework(Test_gt_2.class); framework.addFlags(options.toArray(new String[0])).start(); + framework = new TestFramework(Test_gt_cmove_fp_2.class); + framework.addFlags(options.toArray(new String[0])).start(); + + // BoolTest::ge/gt in C2_MacroAssembler::enc_cmove_fp_cmp_fp + framework = new TestFramework(Test_cmov_fp_cmp_fp_ge_3.class); + framework.addFlags(options.toArray(new String[0])).start(); + framework = new TestFramework(Test_cmov_fp_cmp_fp_ge_4.class); + framework.addFlags(options.toArray(new String[0])).start(); } } @@ -320,6 +335,235 @@ class Test_ge_1 { } } + +class Test_ge_cmove_fp_1 { + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_float_BoolTest_ge_fixed_1_0(float x, float y) { + // return 1 + // when either x or y is NaN + // when neither is NaN, and x > y + // return 0 + // when neither is NaN, and x <= y + return !(x <= y) ? 1.0f : 0.0f; + } + @DontCompile + public static float golden_float_BoolTest_ge_fixed_1_0(float x, float y) { + return !(x <= y) ? 1.0f : 0.0f; + } + + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_double_BoolTest_ge_fixed_1_0(double x, double y) { + // return 1 + // when either x or y is NaN + // when neither is NaN, and x > y + // return 0 + // when neither is NaN, and x <= y + return !(x <= y) ? 1.0f : 0.0f; + } + @DontCompile + public static float golden_double_BoolTest_ge_fixed_1_0(double x, double y) { + return !(x <= y) ? 1.0f : 0.0f; + } + + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_float_BoolTest_ge_fixed_0_1(float x, float y) { + return !(x <= y) ? 0.0f : 1.0f; + } + @DontCompile + public static float golden_float_BoolTest_ge_fixed_0_1(float x, float y) { + return !(x <= y) ? 0.0f : 1.0f; + } + + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_double_BoolTest_ge_fixed_0_1(double x, double y) { + return !(x <= y) ? 0.0f : 1.0f; + } + @DontCompile + public static float golden_double_BoolTest_ge_fixed_0_1(double x, double y) { + return !(x <= y) ? 0.0f : 1.0f; + } + + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_float_BoolTest_ge_fixed_10_20(float x, float y) { + return !(x <= y) ? 10.0f : 20.0f; + } + @DontCompile + public static float golden_float_BoolTest_ge_fixed_10_20(float x, float y) { + return !(x <= y) ? 10.0f : 20.0f; + } + + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_double_BoolTest_ge_fixed_10_20(double x, double y) { + return !(x <= y) ? 10.0f : 20.0f; + } + @DontCompile + public static float golden_double_BoolTest_ge_fixed_10_20(double x, double y) { + return !(x <= y) ? 10.0f : 20.0f; + } + + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_float_BoolTest_ge_variable_results(float x, float y, float a, float b) { + return !(x <= y) ? a : b; + } + @DontCompile + public static float golden_float_BoolTest_ge_variable_results(float x, float y, float a, float b) { + return !(x <= y) ? a : b; + } + + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_double_BoolTest_ge_variable_results(double x, double y, float a, float b) { + return !(x <= y) ? a : b; + } + @DontCompile + public static float golden_double_BoolTest_ge_variable_results(double x, double y, float a, float b) { + return !(x <= y) ? a : b; + } + + @Run(test = {"test_float_BoolTest_ge_fixed_1_0", "test_double_BoolTest_ge_fixed_1_0", + "test_float_BoolTest_ge_fixed_0_1", "test_double_BoolTest_ge_fixed_0_1", + "test_float_BoolTest_ge_fixed_10_20", "test_double_BoolTest_ge_fixed_10_20", + "test_float_BoolTest_ge_variable_results", "test_double_BoolTest_ge_variable_results"}) + public void runTests() { + int err = 0; + + for (int i = 0; i < TestFPComparison2.FLOATS.length; i++) { + for (int j = 0; j < TestFPComparison2.FLOATS.length; j++) { + float x = TestFPComparison2.FLOATS[i]; + float y = TestFPComparison2.FLOATS[j]; + float actual = test_float_BoolTest_ge_fixed_1_0(x, y); + float expected = golden_float_BoolTest_ge_fixed_1_0(x, y); + if (actual != expected) { + System.out.println("Float failed (ge, 1, 0), x: " + x + ", y: " + y + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + + for (int i = 0; i < TestFPComparison2.DOUBLES.length; i++) { + for (int j = 0; j < TestFPComparison2.DOUBLES.length; j++) { + double x = TestFPComparison2.DOUBLES[i]; + double y = TestFPComparison2.DOUBLES[j]; + float actual = test_double_BoolTest_ge_fixed_1_0(x, y); + float expected = golden_double_BoolTest_ge_fixed_1_0(x, y); + if (actual != expected) { + System.out.println("Double failed (ge, 1, 0), x: " + x + ", y: " + y + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + + for (int i = 0; i < TestFPComparison2.FLOATS.length; i++) { + for (int j = 0; j < TestFPComparison2.FLOATS.length; j++) { + float x = TestFPComparison2.FLOATS[i]; + float y = TestFPComparison2.FLOATS[j]; + float actual = test_float_BoolTest_ge_fixed_0_1(x, y); + float expected = golden_float_BoolTest_ge_fixed_0_1(x, y); + if (actual != expected) { + System.out.println("Float failed (ge, 0, 1), x: " + x + ", y: " + y + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + + for (int i = 0; i < TestFPComparison2.DOUBLES.length; i++) { + for (int j = 0; j < TestFPComparison2.DOUBLES.length; j++) { + double x = TestFPComparison2.DOUBLES[i]; + double y = TestFPComparison2.DOUBLES[j]; + float actual = test_double_BoolTest_ge_fixed_0_1(x, y); + float expected = golden_double_BoolTest_ge_fixed_0_1(x, y); + if (actual != expected) { + System.out.println("Double failed (ge, 0, 1), x: " + x + ", y: " + y + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + + for (int i = 0; i < TestFPComparison2.FLOATS.length; i++) { + for (int j = 0; j < TestFPComparison2.FLOATS.length; j++) { + float x = TestFPComparison2.FLOATS[i]; + float y = TestFPComparison2.FLOATS[j]; + float actual = test_float_BoolTest_ge_fixed_10_20(x, y); + float expected = golden_float_BoolTest_ge_fixed_10_20(x, y); + if (actual != expected) { + System.out.println("Float failed (ge, 10, 20), x: " + x + ", y: " + y + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + + for (int i = 0; i < TestFPComparison2.DOUBLES.length; i++) { + for (int j = 0; j < TestFPComparison2.DOUBLES.length; j++) { + double x = TestFPComparison2.DOUBLES[i]; + double y = TestFPComparison2.DOUBLES[j]; + float actual = test_double_BoolTest_ge_fixed_10_20(x, y); + float expected = golden_double_BoolTest_ge_fixed_10_20(x, y); + if (actual != expected) { + System.out.println("Double failed (ge, 10, 20), x: " + x + ", y: " + y + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + + for (int i = 0; i < TestFPComparison2.FLOATS.length; i++) { + for (int j = 0; j < TestFPComparison2.FLOATS.length; j++) { + float x = TestFPComparison2.FLOATS[i]; + float y = TestFPComparison2.FLOATS[j]; + for (int m = 0; m < TestFPComparison2.FLOATS.length; m++) { + for (int n = 0; n < TestFPComparison2.FLOATS.length; n++) { + float a = TestFPComparison2.FLOATS[m]; + float b = TestFPComparison2.FLOATS[n]; + float actual = test_float_BoolTest_ge_variable_results(x, y, a, b); + float expected = golden_float_BoolTest_ge_variable_results(x, y, a, b); + if (actual != expected && (!Float.isNaN(actual) || !Float.isNaN(expected))) { + System.out.println("Float failed (ge), x: " + x + ", y: " + y + ", a: " + a + ", b: " + b + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + } + } + + for (int i = 0; i < TestFPComparison2.DOUBLES.length; i++) { + for (int j = 0; j < TestFPComparison2.DOUBLES.length; j++) { + double x = TestFPComparison2.DOUBLES[i]; + double y = TestFPComparison2.DOUBLES[j]; + for (int m = 0; m < TestFPComparison2.FLOATS.length; m++) { + for (int n = 0; n < TestFPComparison2.FLOATS.length; n++) { + float a = TestFPComparison2.FLOATS[m]; + float b = TestFPComparison2.FLOATS[n]; + float actual = test_double_BoolTest_ge_variable_results(x, y, a, b); + float expected = golden_double_BoolTest_ge_variable_results(x, y, a, b); + if (actual != expected && (!Float.isNaN(actual) || !Float.isNaN(expected))) { + System.out.println("Double failed (ge), x: " + x + ", y: " + y + ", a: " + a + ", b: " + b + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + } + } + + if (err != 0) { + throw new RuntimeException("Some tests failed"); + } + } +} + class Test_ge_2 { @Test @IR(counts = {IRNode.CMOVE_I, "1"}) @@ -548,6 +792,234 @@ class Test_ge_2 { } } +class Test_ge_cmove_fp_2 { + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_float_BoolTest_ge_fixed_1_0(float x, float y) { + // return 1 + // when either x or y is NaN + // when neither is NaN, and x < y + // return 0 + // when neither is NaN, and x >= y + return !(x >= y) ? 1.0f : 0.0f; + } + @DontCompile + public static float golden_float_BoolTest_ge_fixed_1_0(float x, float y) { + return !(x >= y) ? 1.0f : 0.0f; + } + + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_double_BoolTest_ge_fixed_1_0(double x, double y) { + // return 1 + // when either x or y is NaN + // when neither is NaN, and x < y + // return 0 + // when neither is NaN, and x >= y + return !(x >= y) ? 1.0f : 0.0f; + } + @DontCompile + public static float golden_double_BoolTest_ge_fixed_1_0(double x, double y) { + return !(x >= y) ? 1.0f : 0.0f; + } + + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_float_BoolTest_ge_fixed_0_1(float x, float y) { + return !(x >= y) ? 0.0f : 1.0f; + } + @DontCompile + public static float golden_float_BoolTest_ge_fixed_0_1(float x, float y) { + return !(x >= y) ? 0.0f : 1.0f; + } + + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_double_BoolTest_ge_fixed_0_1(double x, double y) { + return !(x >= y) ? 0.0f : 1.0f; + } + @DontCompile + public static float golden_double_BoolTest_ge_fixed_0_1(double x, double y) { + return !(x >= y) ? 0.0f : 1.0f; + } + + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_float_BoolTest_ge_fixed_10_20(float x, float y) { + return !(x >= y) ? 10.0f : 20.0f; + } + @DontCompile + public static float golden_float_BoolTest_ge_fixed_10_20(float x, float y) { + return !(x >= y) ? 10.0f : 20.0f; + } + + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_double_BoolTest_ge_fixed_10_20(double x, double y) { + return !(x >= y) ? 10.0f : 20.0f; + } + @DontCompile + public static float golden_double_BoolTest_ge_fixed_10_20(double x, double y) { + return !(x >= y) ? 10.0f : 20.0f; + } + + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_float_BoolTest_ge_variable_results(float x, float y, float a, float b) { + return !(x >= y) ? a : b; + } + @DontCompile + public static float golden_float_BoolTest_ge_variable_results(float x, float y, float a, float b) { + return !(x >= y) ? a : b; + } + + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_double_BoolTest_ge_variable_results(double x, double y, float a, float b) { + return !(x >= y) ? a : b; + } + @DontCompile + public static float golden_double_BoolTest_ge_variable_results(double x, double y, float a, float b) { + return !(x >= y) ? a : b; + } + + @Run(test = {"test_float_BoolTest_ge_fixed_1_0", "test_double_BoolTest_ge_fixed_1_0", + "test_float_BoolTest_ge_fixed_0_1", "test_double_BoolTest_ge_fixed_0_1", + "test_float_BoolTest_ge_fixed_10_20", "test_double_BoolTest_ge_fixed_10_20", + "test_float_BoolTest_ge_variable_results", "test_double_BoolTest_ge_variable_results"}) + public void runTests() { + int err = 0; + + for (int i = 0; i < TestFPComparison2.FLOATS.length; i++) { + for (int j = 0; j < TestFPComparison2.FLOATS.length; j++) { + float x = TestFPComparison2.FLOATS[i]; + float y = TestFPComparison2.FLOATS[j]; + float actual = test_float_BoolTest_ge_fixed_1_0(x, y); + float expected = golden_float_BoolTest_ge_fixed_1_0(x, y); + if (actual != expected) { + System.out.println("Float failed (ge), x: " + x + ", y: " + y + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + + for (int i = 0; i < TestFPComparison2.DOUBLES.length; i++) { + for (int j = 0; j < TestFPComparison2.DOUBLES.length; j++) { + double x = TestFPComparison2.DOUBLES[i]; + double y = TestFPComparison2.DOUBLES[j]; + float actual = test_double_BoolTest_ge_fixed_1_0(x, y); + float expected = golden_double_BoolTest_ge_fixed_1_0(x, y); + if (actual != expected) { + System.out.println("Double failed (ge), x: " + x + ", y: " + y + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + + for (int i = 0; i < TestFPComparison2.FLOATS.length; i++) { + for (int j = 0; j < TestFPComparison2.FLOATS.length; j++) { + float x = TestFPComparison2.FLOATS[i]; + float y = TestFPComparison2.FLOATS[j]; + float actual = test_float_BoolTest_ge_fixed_0_1(x, y); + float expected = golden_float_BoolTest_ge_fixed_0_1(x, y); + if (actual != expected) { + System.out.println("Float failed (ge, 0, 1), x: " + x + ", y: " + y + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + + for (int i = 0; i < TestFPComparison2.DOUBLES.length; i++) { + for (int j = 0; j < TestFPComparison2.DOUBLES.length; j++) { + double x = TestFPComparison2.DOUBLES[i]; + double y = TestFPComparison2.DOUBLES[j]; + float actual = test_double_BoolTest_ge_fixed_0_1(x, y); + float expected = golden_double_BoolTest_ge_fixed_0_1(x, y); + if (actual != expected) { + System.out.println("Double failed (ge, 0, 1), x: " + x + ", y: " + y + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + + for (int i = 0; i < TestFPComparison2.FLOATS.length; i++) { + for (int j = 0; j < TestFPComparison2.FLOATS.length; j++) { + float x = TestFPComparison2.FLOATS[i]; + float y = TestFPComparison2.FLOATS[j]; + float actual = test_float_BoolTest_ge_fixed_10_20(x, y); + float expected = golden_float_BoolTest_ge_fixed_10_20(x, y); + if (actual != expected) { + System.out.println("Float failed (ge, 10, 20), x: " + x + ", y: " + y + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + + for (int i = 0; i < TestFPComparison2.DOUBLES.length; i++) { + for (int j = 0; j < TestFPComparison2.DOUBLES.length; j++) { + double x = TestFPComparison2.DOUBLES[i]; + double y = TestFPComparison2.DOUBLES[j]; + float actual = test_double_BoolTest_ge_fixed_10_20(x, y); + float expected = golden_double_BoolTest_ge_fixed_10_20(x, y); + if (actual != expected) { + System.out.println("Double failed (ge, 10, 20), x: " + x + ", y: " + y + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + + for (int i = 0; i < TestFPComparison2.FLOATS.length; i++) { + for (int j = 0; j < TestFPComparison2.FLOATS.length; j++) { + float x = TestFPComparison2.FLOATS[i]; + float y = TestFPComparison2.FLOATS[j]; + for (int m = 0; m < TestFPComparison2.FLOATS.length; m++) { + for (int n = 0; n < TestFPComparison2.FLOATS.length; n++) { + float a = TestFPComparison2.FLOATS[m]; + float b = TestFPComparison2.FLOATS[n]; + float actual = test_float_BoolTest_ge_variable_results(x, y, a, b); + float expected = golden_float_BoolTest_ge_variable_results(x, y, a, b); + if (actual != expected && (!Float.isNaN(actual) || !Float.isNaN(expected))) { + System.out.println("Float failed (ge), x: " + x + ", y: " + y + ", a: " + a + ", b: " + b + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + } + } + + for (int i = 0; i < TestFPComparison2.DOUBLES.length; i++) { + for (int j = 0; j < TestFPComparison2.DOUBLES.length; j++) { + double x = TestFPComparison2.DOUBLES[i]; + double y = TestFPComparison2.DOUBLES[j]; + for (int m = 0; m < TestFPComparison2.FLOATS.length; m++) { + for (int n = 0; n < TestFPComparison2.FLOATS.length; n++) { + float a = TestFPComparison2.FLOATS[m]; + float b = TestFPComparison2.FLOATS[n]; + float actual = test_double_BoolTest_ge_variable_results(x, y, a, b); + float expected = golden_double_BoolTest_ge_variable_results(x, y, a, b); + if (actual != expected && (!Float.isNaN(actual) || !Float.isNaN(expected))) { + System.out.println("Double failed (ge), x: " + x + ", y: " + y + ", a: " + a + ", b: " + b + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + } + } + + if (err != 0) { + throw new RuntimeException("Some tests failed"); + } + } +} + class Test_gt_1 { @Test @IR(counts = {IRNode.CMOVE_I, "1"}) @@ -776,6 +1248,234 @@ class Test_gt_1 { } } +class Test_gt_cmove_fp_1 { + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_float_BoolTest_gt_fixed_1_0(float x, float y) { + // return 1 + // when either x or y is NaN + // when neither is NaN, and x >= y + // return 0 + // when neither is NaN, and x < y + return !(x < y) ? 1.0f : 0.0f; + } + @DontCompile + public static float golden_float_BoolTest_gt_fixed_1_0(float x, float y) { + return !(x < y) ? 1.0f : 0.0f; + } + + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_double_BoolTest_gt_fixed_1_0(double x, double y) { + // return 1 + // when either x or y is NaN + // when neither is NaN, and x >= y + // return 0 + // when neither is NaN, and x < y + return !(x < y) ? 1.0f : 0.0f; + } + @DontCompile + public static float golden_double_BoolTest_gt_fixed_1_0(double x, double y) { + return !(x < y) ? 1.0f : 0.0f; + } + + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_float_BoolTest_gt_fixed_0_1(float x, float y) { + return !(x < y) ? 0.0f : 1.0f; + } + @DontCompile + public static float golden_float_BoolTest_gt_fixed_0_1(float x, float y) { + return !(x < y) ? 0.0f : 1.0f; + } + + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_double_BoolTest_gt_fixed_0_1(double x, double y) { + return !(x < y) ? 0.0f : 1.0f; + } + @DontCompile + public static float golden_double_BoolTest_gt_fixed_0_1(double x, double y) { + return !(x < y) ? 0.0f : 1.0f; + } + + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_float_BoolTest_gt_fixed_10_20(float x, float y) { + return !(x < y) ? 10.0f : 20.0f; + } + @DontCompile + public static float golden_float_BoolTest_gt_fixed_10_20(float x, float y) { + return !(x < y) ? 10.0f : 20.0f; + } + + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_double_BoolTest_gt_fixed_10_20(double x, double y) { + return !(x < y) ? 10.0f : 20.0f; + } + @DontCompile + public static float golden_double_BoolTest_gt_fixed_10_20(double x, double y) { + return !(x < y) ? 10.0f : 20.0f; + } + + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_float_BoolTest_gt_variable_results(float x, float y, float a, float b) { + return !(x < y) ? a : b; + } + @DontCompile + public static float golden_float_BoolTest_gt_variable_results(float x, float y, float a, float b) { + return !(x < y) ? a : b; + } + + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_double_BoolTest_gt_variable_results(double x, double y, float a, float b) { + return !(x < y) ? a : b; + } + @DontCompile + public static float golden_double_BoolTest_gt_variable_results(double x, double y, float a, float b) { + return !(x < y) ? a : b; + } + + @Run(test = {"test_float_BoolTest_gt_fixed_1_0", "test_double_BoolTest_gt_fixed_1_0", + "test_float_BoolTest_gt_fixed_0_1", "test_double_BoolTest_gt_fixed_0_1", + "test_float_BoolTest_gt_fixed_10_20", "test_double_BoolTest_gt_fixed_10_20", + "test_float_BoolTest_gt_variable_results", "test_double_BoolTest_gt_variable_results"}) + public void runTests() { + int err = 0; + + for (int i = 0; i < TestFPComparison2.FLOATS.length; i++) { + for (int j = 0; j < TestFPComparison2.FLOATS.length; j++) { + float x = TestFPComparison2.FLOATS[i]; + float y = TestFPComparison2.FLOATS[j]; + float actual = test_float_BoolTest_gt_fixed_1_0(x, y); + float expected = golden_float_BoolTest_gt_fixed_1_0(x, y); + if (actual != expected) { + System.out.println("Float failed (gt), x: " + x + ", y: " + y + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + + for (int i = 0; i < TestFPComparison2.DOUBLES.length; i++) { + for (int j = 0; j < TestFPComparison2.DOUBLES.length; j++) { + double x = TestFPComparison2.DOUBLES[i]; + double y = TestFPComparison2.DOUBLES[j]; + float actual = test_double_BoolTest_gt_fixed_1_0(x, y); + float expected = golden_double_BoolTest_gt_fixed_1_0(x, y); + if (actual != expected) { + System.out.println("Double failed (gt), x: " + x + ", y: " + y + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + + for (int i = 0; i < TestFPComparison2.FLOATS.length; i++) { + for (int j = 0; j < TestFPComparison2.FLOATS.length; j++) { + float x = TestFPComparison2.FLOATS[i]; + float y = TestFPComparison2.FLOATS[j]; + float actual = test_float_BoolTest_gt_fixed_0_1(x, y); + float expected = golden_float_BoolTest_gt_fixed_0_1(x, y); + if (actual != expected) { + System.out.println("Float failed (gt, 0, 1), x: " + x + ", y: " + y + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + + for (int i = 0; i < TestFPComparison2.DOUBLES.length; i++) { + for (int j = 0; j < TestFPComparison2.DOUBLES.length; j++) { + double x = TestFPComparison2.DOUBLES[i]; + double y = TestFPComparison2.DOUBLES[j]; + float actual = test_double_BoolTest_gt_fixed_0_1(x, y); + float expected = golden_double_BoolTest_gt_fixed_0_1(x, y); + if (actual != expected) { + System.out.println("Double failed (gt, 0, 1), x: " + x + ", y: " + y + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + + for (int i = 0; i < TestFPComparison2.FLOATS.length; i++) { + for (int j = 0; j < TestFPComparison2.FLOATS.length; j++) { + float x = TestFPComparison2.FLOATS[i]; + float y = TestFPComparison2.FLOATS[j]; + float actual = test_float_BoolTest_gt_fixed_10_20(x, y); + float expected = golden_float_BoolTest_gt_fixed_10_20(x, y); + if (actual != expected) { + System.out.println("Float failed (gt, 10, 20), x: " + x + ", y: " + y + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + + for (int i = 0; i < TestFPComparison2.DOUBLES.length; i++) { + for (int j = 0; j < TestFPComparison2.DOUBLES.length; j++) { + double x = TestFPComparison2.DOUBLES[i]; + double y = TestFPComparison2.DOUBLES[j]; + float actual = test_double_BoolTest_gt_fixed_10_20(x, y); + float expected = golden_double_BoolTest_gt_fixed_10_20(x, y); + if (actual != expected) { + System.out.println("Double failed (gt, 10, 20), x: " + x + ", y: " + y + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + + for (int i = 0; i < TestFPComparison2.FLOATS.length; i++) { + for (int j = 0; j < TestFPComparison2.FLOATS.length; j++) { + float x = TestFPComparison2.FLOATS[i]; + float y = TestFPComparison2.FLOATS[j]; + for (int m = 0; m < TestFPComparison2.FLOATS.length; m++) { + for (int n = 0; n < TestFPComparison2.FLOATS.length; n++) { + float a = TestFPComparison2.FLOATS[m]; + float b = TestFPComparison2.FLOATS[n]; + float actual = test_float_BoolTest_gt_variable_results(x, y, a, b); + float expected = golden_float_BoolTest_gt_variable_results(x, y, a, b); + if (actual != expected && (!Float.isNaN(actual) || !Float.isNaN(expected))) { + System.out.println("Float failed (gt), x: " + x + ", y: " + y + ", a: " + a + ", b: " + b + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + } + } + + for (int i = 0; i < TestFPComparison2.DOUBLES.length; i++) { + for (int j = 0; j < TestFPComparison2.DOUBLES.length; j++) { + double x = TestFPComparison2.DOUBLES[i]; + double y = TestFPComparison2.DOUBLES[j]; + for (int m = 0; m < TestFPComparison2.FLOATS.length; m++) { + for (int n = 0; n < TestFPComparison2.FLOATS.length; n++) { + float a = TestFPComparison2.FLOATS[m]; + float b = TestFPComparison2.FLOATS[n]; + float actual = test_double_BoolTest_gt_variable_results(x, y, a, b); + float expected = golden_double_BoolTest_gt_variable_results(x, y, a, b); + if (actual != expected && (!Float.isNaN(actual) || !Float.isNaN(expected))) { + System.out.println("Double failed (gt), x: " + x + ", y: " + y + ", a: " + a + ", b: " + b + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + } + } + + if (err != 0) { + throw new RuntimeException("Some tests failed"); + } + } +} + class Test_gt_2 { @Test @IR(counts = {IRNode.CMOVE_I, "1"}) @@ -1003,3 +1703,439 @@ class Test_gt_2 { } } } + +class Test_gt_cmove_fp_2 { + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_float_BoolTest_gt_fixed_1_0(float x, float y) { + // return 1 + // when either x or y is NaN + // when neither is NaN, and x <= y + // return 0 + // when neither is NaN, and x > y + return !(x > y) ? 1.0f : 0.0f; + } + @DontCompile + public static float golden_float_BoolTest_gt_fixed_1_0(float x, float y) { + return !(x > y) ? 1.0f : 0.0f; + } + + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_double_BoolTest_gt_fixed_1_0(double x, double y) { + // return 1 + // when either x or y is NaN + // when neither is NaN, and x <= y + // return 0 + // when neither is NaN, and x > y + return !(x > y) ? 1.0f : 0.0f; + } + @DontCompile + public static float golden_double_BoolTest_gt_fixed_1_0(double x, double y) { + return !(x > y) ? 1.0f : 0.0f; + } + + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_float_BoolTest_gt_fixed_0_1(float x, float y) { + return !(x > y) ? 0.0f : 1.0f; + } + @DontCompile + public static float golden_float_BoolTest_gt_fixed_0_1(float x, float y) { + return !(x > y) ? 0.0f : 1.0f; + } + + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_double_BoolTest_gt_fixed_0_1(double x, double y) { + return !(x > y) ? 0.0f : 1.0f; + } + @DontCompile + public static float golden_double_BoolTest_gt_fixed_0_1(double x, double y) { + return !(x > y) ? 0.0f : 1.0f; + } + + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_float_BoolTest_gt_fixed_10_20(float x, float y) { + return !(x > y) ? 10.0f : 20.0f; + } + @DontCompile + public static float golden_float_BoolTest_gt_fixed_10_20(float x, float y) { + return !(x > y) ? 10.0f : 20.0f; + } + + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_double_BoolTest_gt_fixed_10_20(double x, double y) { + return !(x > y) ? 10.0f : 20.0f; + } + @DontCompile + public static float golden_double_BoolTest_gt_fixed_10_20(double x, double y) { + return !(x > y) ? 10.0f : 20.0f; + } + + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_float_BoolTest_gt_variable_results(float x, float y, float a, float b) { + return !(x > y) ? a : b; + } + @DontCompile + public static float golden_float_BoolTest_gt_variable_results(float x, float y, float a, float b) { + return !(x > y) ? a : b; + } + + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_double_BoolTest_gt_variable_results(double x, double y, float a, float b) { + return !(x > y) ? a : b; + } + @DontCompile + public static float golden_double_BoolTest_gt_variable_results(double x, double y, float a, float b) { + return !(x > y) ? a : b; + } + + @Run(test = {"test_float_BoolTest_gt_fixed_1_0", "test_double_BoolTest_gt_fixed_1_0", + "test_float_BoolTest_gt_fixed_0_1", "test_double_BoolTest_gt_fixed_0_1", + "test_float_BoolTest_gt_fixed_10_20", "test_double_BoolTest_gt_fixed_10_20", + "test_float_BoolTest_gt_variable_results", "test_double_BoolTest_gt_variable_results"}) + public void runTests() { + int err = 0; + + for (int i = 0; i < TestFPComparison2.FLOATS.length; i++) { + for (int j = 0; j < TestFPComparison2.FLOATS.length; j++) { + float x = TestFPComparison2.FLOATS[i]; + float y = TestFPComparison2.FLOATS[j]; + float actual = test_float_BoolTest_gt_fixed_1_0(x, y); + float expected = golden_float_BoolTest_gt_fixed_1_0(x, y); + if (actual != expected) { + System.out.println("Float failed (gt), x: " + x + ", y: " + y + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + + for (int i = 0; i < TestFPComparison2.DOUBLES.length; i++) { + for (int j = 0; j < TestFPComparison2.DOUBLES.length; j++) { + double x = TestFPComparison2.DOUBLES[i]; + double y = TestFPComparison2.DOUBLES[j]; + float actual = test_double_BoolTest_gt_fixed_1_0(x, y); + float expected = golden_double_BoolTest_gt_fixed_1_0(x, y); + if (actual != expected) { + System.out.println("Double failed (gt), x: " + x + ", y: " + y + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + + for (int i = 0; i < TestFPComparison2.FLOATS.length; i++) { + for (int j = 0; j < TestFPComparison2.FLOATS.length; j++) { + float x = TestFPComparison2.FLOATS[i]; + float y = TestFPComparison2.FLOATS[j]; + float actual = test_float_BoolTest_gt_fixed_0_1(x, y); + float expected = golden_float_BoolTest_gt_fixed_0_1(x, y); + if (actual != expected) { + System.out.println("Float failed (gt, 0, 1), x: " + x + ", y: " + y + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + + for (int i = 0; i < TestFPComparison2.DOUBLES.length; i++) { + for (int j = 0; j < TestFPComparison2.DOUBLES.length; j++) { + double x = TestFPComparison2.DOUBLES[i]; + double y = TestFPComparison2.DOUBLES[j]; + float actual = test_double_BoolTest_gt_fixed_0_1(x, y); + float expected = golden_double_BoolTest_gt_fixed_0_1(x, y); + if (actual != expected) { + System.out.println("Double failed (gt, 0, 1), x: " + x + ", y: " + y + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + + for (int i = 0; i < TestFPComparison2.FLOATS.length; i++) { + for (int j = 0; j < TestFPComparison2.FLOATS.length; j++) { + float x = TestFPComparison2.FLOATS[i]; + float y = TestFPComparison2.FLOATS[j]; + float actual = test_float_BoolTest_gt_fixed_10_20(x, y); + float expected = golden_float_BoolTest_gt_fixed_10_20(x, y); + if (actual != expected) { + System.out.println("Float failed (gt, 10, 20), x: " + x + ", y: " + y + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + + for (int i = 0; i < TestFPComparison2.DOUBLES.length; i++) { + for (int j = 0; j < TestFPComparison2.DOUBLES.length; j++) { + double x = TestFPComparison2.DOUBLES[i]; + double y = TestFPComparison2.DOUBLES[j]; + float actual = test_double_BoolTest_gt_fixed_10_20(x, y); + float expected = golden_double_BoolTest_gt_fixed_10_20(x, y); + if (actual != expected) { + System.out.println("Double failed (gt, 10, 20), x: " + x + ", y: " + y + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + + for (int i = 0; i < TestFPComparison2.FLOATS.length; i++) { + for (int j = 0; j < TestFPComparison2.FLOATS.length; j++) { + float x = TestFPComparison2.FLOATS[i]; + float y = TestFPComparison2.FLOATS[j]; + for (int m = 0; m < TestFPComparison2.FLOATS.length; m++) { + for (int n = 0; n < TestFPComparison2.FLOATS.length; n++) { + float a = TestFPComparison2.FLOATS[m]; + float b = TestFPComparison2.FLOATS[n]; + float actual = test_float_BoolTest_gt_variable_results(x, y, a, b); + float expected = golden_float_BoolTest_gt_variable_results(x, y, a, b); + if (actual != expected && (!Float.isNaN(actual) || !Float.isNaN(expected))) { + System.out.println("Float failed (gt), x: " + x + ", y: " + y + ", a: " + a + ", b: " + b + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + } + } + + for (int i = 0; i < TestFPComparison2.DOUBLES.length; i++) { + for (int j = 0; j < TestFPComparison2.DOUBLES.length; j++) { + double x = TestFPComparison2.DOUBLES[i]; + double y = TestFPComparison2.DOUBLES[j]; + for (int m = 0; m < TestFPComparison2.FLOATS.length; m++) { + for (int n = 0; n < TestFPComparison2.FLOATS.length; n++) { + float a = TestFPComparison2.FLOATS[m]; + float b = TestFPComparison2.FLOATS[n]; + float actual = test_double_BoolTest_gt_variable_results(x, y, a, b); + float expected = golden_double_BoolTest_gt_variable_results(x, y, a, b); + if (actual != expected && (!Float.isNaN(actual) || !Float.isNaN(expected))) { + System.out.println("Double failed (gt), x: " + x + ", y: " + y + ", a: " + a + ", b: " + b + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + } + } + + if (err != 0) { + throw new RuntimeException("Some tests failed"); + } + } +} + +class Test_cmov_fp_cmp_fp_ge_3 { + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_float_BoolTest_gt_x_lt_0(float x) { + return x < 0 ? 0 : x; + } + @DontCompile + public static float golden_float_BoolTest_gt_x_lt_0(float x) { + return x < 0 ? 0 : x; + } + + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_float_BoolTest_gt_x_gt_0(float x) { + return x > 0 ? 0 : x; + } + @DontCompile + public static float golden_float_BoolTest_gt_x_gt_0(float x) { + return x > 0 ? 0 : x; + } + + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_float_BoolTest_gt_neg_x_lt_0(float x) { + return !(x < 0) ? 0 : x; + } + @DontCompile + public static float golden_float_BoolTest_gt_neg_x_lt_0(float x) { + return !(x < 0) ? 0 : x; + } + + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_float_BoolTest_gt_neg_x_gt_0(float x) { + return !(x > 0) ? 0 : x; + } + @DontCompile + public static float golden_float_BoolTest_gt_neg_x_gt_0(float x) { + return !(x > 0) ? 0 : x; + } + + @Run(test = {"test_float_BoolTest_gt_x_lt_0", "test_float_BoolTest_gt_x_gt_0", + "test_float_BoolTest_gt_neg_x_lt_0", "test_float_BoolTest_gt_neg_x_gt_0",}) + public void runTests() { + int err = 0; + + for (int i = 0; i < TestFPComparison2.FLOATS.length; i++) { + for (int j = 0; j < TestFPComparison2.FLOATS.length; j++) { + float x = TestFPComparison2.FLOATS[i]; + float actual = test_float_BoolTest_gt_x_lt_0(x); + float expected = golden_float_BoolTest_gt_x_lt_0(x); + if (actual != expected && (!Float.isNaN(actual) || !Float.isNaN(expected))) { + System.out.println("Float failed (lt, x, 0), x: " + x + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + + for (int i = 0; i < TestFPComparison2.FLOATS.length; i++) { + for (int j = 0; j < TestFPComparison2.FLOATS.length; j++) { + float x = TestFPComparison2.FLOATS[i]; + float actual = test_float_BoolTest_gt_x_gt_0(x); + float expected = golden_float_BoolTest_gt_x_gt_0(x); + if (actual != expected && (!Float.isNaN(actual) || !Float.isNaN(expected))) { + System.out.println("Float failed (gt, x, 0), x: " + x + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + + for (int i = 0; i < TestFPComparison2.FLOATS.length; i++) { + for (int j = 0; j < TestFPComparison2.FLOATS.length; j++) { + float x = TestFPComparison2.FLOATS[i]; + float actual = test_float_BoolTest_gt_neg_x_lt_0(x); + float expected = golden_float_BoolTest_gt_neg_x_lt_0(x); + if (actual != expected && (!Float.isNaN(actual) || !Float.isNaN(expected))) { + System.out.println("Float failed (neg lt, x, 0), x: " + x + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + + for (int i = 0; i < TestFPComparison2.FLOATS.length; i++) { + for (int j = 0; j < TestFPComparison2.FLOATS.length; j++) { + float x = TestFPComparison2.FLOATS[i]; + float actual = test_float_BoolTest_gt_neg_x_gt_0(x); + float expected = golden_float_BoolTest_gt_neg_x_gt_0(x); + if (actual != expected && (!Float.isNaN(actual) || !Float.isNaN(expected))) { + System.out.println("Float failed (neg gt, x, 0), x: " + x + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + + if (err != 0) { + throw new RuntimeException("Some tests failed"); + } + } +} + +class Test_cmov_fp_cmp_fp_ge_4 { + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_float_BoolTest_ge_x_le_0(float x) { + return x <= 0 ? 0 : x; + } + @DontCompile + public static float golden_float_BoolTest_ge_x_le_0(float x) { + return x <= 0 ? 0 : x; + } + + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_float_BoolTest_ge_x_ge_0(float x) { + return x >= 0 ? 0 : x; + } + @DontCompile + public static float golden_float_BoolTest_ge_x_ge_0(float x) { + return x >= 0 ? 0 : x; + } + + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_float_BoolTest_ge_neg_x_le_0(float x) { + return !(x <= 0) ? 0 : x; + } + @DontCompile + public static float golden_float_BoolTest_ge_neg_x_le_0(float x) { + return !(x <= 0) ? 0 : x; + } + + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_float_BoolTest_ge_neg_x_ge_0(float x) { + return !(x >= 0) ? 0 : x; + } + @DontCompile + public static float golden_float_BoolTest_ge_neg_x_ge_0(float x) { + return !(x >= 0) ? 0 : x; + } + + @Run(test = {"test_float_BoolTest_ge_x_le_0", "test_float_BoolTest_ge_x_ge_0", + "test_float_BoolTest_ge_neg_x_le_0", "test_float_BoolTest_ge_neg_x_ge_0",}) + public void runTests() { + int err = 0; + + for (int i = 0; i < TestFPComparison2.FLOATS.length; i++) { + for (int j = 0; j < TestFPComparison2.FLOATS.length; j++) { + float x = TestFPComparison2.FLOATS[i]; + float actual = test_float_BoolTest_ge_x_le_0(x); + float expected = golden_float_BoolTest_ge_x_le_0(x); + if (actual != expected && (!Float.isNaN(actual) || !Float.isNaN(expected))) { + System.out.println("Float failed (le, x, 0), x: " + x + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + + for (int i = 0; i < TestFPComparison2.FLOATS.length; i++) { + for (int j = 0; j < TestFPComparison2.FLOATS.length; j++) { + float x = TestFPComparison2.FLOATS[i]; + float actual = test_float_BoolTest_ge_x_ge_0(x); + float expected = golden_float_BoolTest_ge_x_ge_0(x); + if (actual != expected && (!Float.isNaN(actual) || !Float.isNaN(expected))) { + System.out.println("Float failed (ge, x, 0), x: " + x + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + + for (int i = 0; i < TestFPComparison2.FLOATS.length; i++) { + for (int j = 0; j < TestFPComparison2.FLOATS.length; j++) { + float x = TestFPComparison2.FLOATS[i]; + float actual = test_float_BoolTest_ge_neg_x_le_0(x); + float expected = golden_float_BoolTest_ge_neg_x_le_0(x); + if (actual != expected && (!Float.isNaN(actual) || !Float.isNaN(expected))) { + System.out.println("Float failed (neg le, x, 0), x: " + x + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + + for (int i = 0; i < TestFPComparison2.FLOATS.length; i++) { + for (int j = 0; j < TestFPComparison2.FLOATS.length; j++) { + float x = TestFPComparison2.FLOATS[i]; + float actual = test_float_BoolTest_ge_neg_x_ge_0(x); + float expected = golden_float_BoolTest_ge_neg_x_ge_0(x); + if (actual != expected && (!Float.isNaN(actual) || !Float.isNaN(expected))) { + System.out.println("Float failed (neg ge, x, 0), x: " + x + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + + if (err != 0) { + throw new RuntimeException("Some tests failed"); + } + } +} diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestScalarConditionalMoveCmpObj.java b/test/hotspot/jtreg/compiler/c2/irTests/TestScalarConditionalMoveCmpObj.java new file mode 100644 index 00000000000..e332ac9e293 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestScalarConditionalMoveCmpObj.java @@ -0,0 +1,357 @@ +/* + * Copyright (c) 2025, Rivos Inc. 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 compiler.c2.irTests; + +import compiler.lib.ir_framework.*; +import java.util.Random; +import jdk.test.lib.Asserts; +import jdk.test.lib.Utils; + +/* + * @test + * @summary Test conditional move + compare object. + * @requires vm.simpleArch == "riscv64" + * @library /test/lib / + * @run driver compiler.c2.irTests.TestScalarConditionalMoveCmpObj + */ + +public class TestScalarConditionalMoveCmpObj { + final private static int SIZE = 1024; + private static final Random RANDOM = Utils.getRandomInstance(); + + public static void main(String[] args) { + TestFramework.runWithFlags("-XX:+UseCMoveUnconditionally", "-XX:-UseVectorCmov", + "-XX:+UnlockExperimentalVMOptions", "-XX:-UseCompactObjectHeaders", "-XX:+UseCompressedOops"); + TestFramework.runWithFlags("-XX:+UseCMoveUnconditionally", "-XX:-UseVectorCmov", + "-XX:+UnlockExperimentalVMOptions", "-XX:-UseCompactObjectHeaders", "-XX:-UseCompressedOops"); + TestFramework.runWithFlags("-XX:+UseCMoveUnconditionally", "-XX:-UseVectorCmov", + "-XX:+UnlockExperimentalVMOptions", "-XX:+UseCompactObjectHeaders", "-XX:+UseCompressedOops"); + TestFramework.runWithFlags("-XX:+UseCMoveUnconditionally", "-XX:-UseVectorCmov", + "-XX:+UnlockExperimentalVMOptions", "-XX:+UseCompactObjectHeaders", "-XX:-UseCompressedOops"); + } + + // Object comparison + // O for I + private int cmoveOEQforI(Object a, Object b, int c, int d) { + return (a == b) ? c : d; + } + + private int cmoveONEforI(Object a, Object b, int c, int d) { + return (a != b) ? c : d; + } + + // O for L + private long cmoveOEQforL(Object a, Object b, long c, long d) { + return (a == b) ? c : d; + } + + private long cmoveONEforL(Object a, Object b, long c, long d) { + return (a != b) ? c : d; + } + + // O for F + private float cmoveOEQforF(Object a, Object b, float c, float d) { + return (a == b) ? c : d; + } + + private float cmoveONEforF(Object a, Object b, float c, float d) { + return (a != b) ? c : d; + } + + // O for D + private double cmoveOEQforD(Object a, Object b, double c, double d) { + return (a == b) ? c : d; + } + + private double cmoveONEforD(Object a, Object b, double c, double d) { + return (a != b) ? c : d; + } + + // Tests shows CMoveI is generated, so let @IR verify CMOVE_I. + // + @Test + @IR(failOn = {IRNode.STORE_VECTOR}) + @IR(counts = {IRNode.CMOVE_I, ">0", IRNode.CMP_P, ">0"}, + applyIf = {"UseCompressedOops", "false"}) + @IR(counts = {IRNode.CMOVE_I, ">0", IRNode.CMP_N, ">0"}, + applyIf = {"UseCompressedOops", "true"}) + private static void testCMoveOEQforI(Object[] a, Object[] b, int[] c, int[] d, int[] r, int[] r2) { + for (int i = 0; i < a.length; i++) { + int cc = c[i]; + int dd = d[i]; + r2[i] = cc + dd; + r[i] = (a[i] == b[i]) ? cc : dd; + } + } + + @Test + @IR(failOn = {IRNode.STORE_VECTOR}) + @IR(counts = {IRNode.CMOVE_I, ">0", IRNode.CMP_P, ">0"}, + applyIf = {"UseCompressedOops", "false"}) + @IR(counts = {IRNode.CMOVE_I, ">0", IRNode.CMP_N, ">0"}, + applyIf = {"UseCompressedOops", "true"}) + private static void testCMoveONEforI(Object[] a, Object[] b, int[] c, int[] d, int[] r, int[] r2) { + for (int i = 0; i < a.length; i++) { + int cc = c[i]; + int dd = d[i]; + r2[i] = cc + dd; + r[i] = (a[i] != b[i]) ? cc : dd; + } + } + + // So far, CMoveL is not guaranteed to be generated, so @IR not verify CMOVE_L. + // TODO: enable CMOVE_L verification when it's guaranteed to generate CMOVE_L. + // + @Test + @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_L, ">0", IRNode.CMP_P, ">0"}, + // applyIf = {"UseCompressedOops", "false"}) + // @IR(counts = {IRNode.CMOVE_L, ">0", IRNode.CMP_N, ">0"}, + // applyIf = {"UseCompressedOops", "true"}) + private static void testCMoveOEQforL(Object[] a, Object[] b, long[] c, long[] d, long[] r, long[] r2) { + for (int i = 0; i < a.length; i++) { + long cc = c[i]; + long dd = d[i]; + r2[i] = cc + dd; + r[i] = (a[i] == b[i]) ? cc : dd; + } + } + + @Test + @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_L, ">0", IRNode.CMP_P, ">0"}, + // applyIf = {"UseCompressedOops", "false"}) + // @IR(counts = {IRNode.CMOVE_L, ">0", IRNode.CMP_N, ">0"}, + // applyIf = {"UseCompressedOops", "true"}) + private static void testCMoveONEforL(Object[] a, Object[] b, long[] c, long[] d, long[] r, long[] r2) { + for (int i = 0; i < a.length; i++) { + long cc = c[i]; + long dd = d[i]; + r2[i] = cc + dd; + r[i] = (a[i] != b[i]) ? cc : dd; + } + } + + @Test + @IR(failOn = {IRNode.STORE_VECTOR}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_P, ">0"}, + applyIf = {"UseCompressedOops", "false"}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_N, ">0"}, + applyIf = {"UseCompressedOops", "true"}) + private static void testCMoveOEQforF(Object[] a, Object[] b, float[] c, float[] d, float[] r, float[] r2) { + for (int i = 0; i < a.length; i++) { + float cc = c[i]; + float dd = d[i]; + r2[i] = cc + dd; + r[i] = (a[i] == b[i]) ? cc : dd; + } + } + + @Test + @IR(failOn = {IRNode.STORE_VECTOR}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_P, ">0"}, + applyIf = {"UseCompressedOops", "false"}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_N, ">0"}, + applyIf = {"UseCompressedOops", "true"}) + private static void testCMoveONEforF(Object[] a, Object[] b, float[] c, float[] d, float[] r, float[] r2) { + for (int i = 0; i < a.length; i++) { + float cc = c[i]; + float dd = d[i]; + r2[i] = cc + dd; + r[i] = (a[i] != b[i]) ? cc : dd; + } + } + + @Test + @IR(failOn = {IRNode.STORE_VECTOR}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_P, ">0"}, + applyIf = {"UseCompressedOops", "false"}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_N, ">0"}, + applyIf = {"UseCompressedOops", "true"}) + private static void testCMoveOEQforD(Object[] a, Object[] b, double[] c, double[] d, double[] r, double[] r2) { + for (int i = 0; i < a.length; i++) { + double cc = c[i]; + double dd = d[i]; + r2[i] = cc + dd; + r[i] = (a[i] == b[i]) ? cc : dd; + } + } + + @Test + @IR(failOn = {IRNode.STORE_VECTOR}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_P, ">0"}, + applyIf = {"UseCompressedOops", "false"}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_N, ">0"}, + applyIf = {"UseCompressedOops", "true"}) + private static void testCMoveONEforD(Object[] a, Object[] b, double[] c, double[] d, double[] r, double[] r2) { + for (int i = 0; i < a.length; i++) { + double cc = c[i]; + double dd = d[i]; + r2[i] = cc + dd; + r[i] = (a[i] != b[i]) ? cc : dd; + } + } + + @Warmup(0) + @Run(test = {// Object + "testCMoveOEQforI", + "testCMoveONEforI", + "testCMoveOEQforL", + "testCMoveONEforL", + "testCMoveOEQforF", + "testCMoveONEforF", + "testCMoveOEQforD", + "testCMoveONEforD", + }) + private void testCMove_runner_two() { + Object[] aO = new Object[SIZE]; + Object[] bO = new Object[SIZE]; + int[] cI = new int[SIZE]; + int[] dI = new int[SIZE]; + int[] rI = new int[SIZE]; + long[] cL = new long[SIZE]; + long[] dL = new long[SIZE]; + long[] rL = new long[SIZE]; + float[] cF = new float[SIZE]; + float[] dF = new float[SIZE]; + float[] rF = new float[SIZE]; + double[] cD = new double[SIZE]; + double[] dD = new double[SIZE]; + double[] rD = new double[SIZE]; + + init(aO); + shuffle(aO, bO); + init(cL); + init(dL); + init(cF); + init(dF); + init(cD); + init(dD); + + testCMoveOEQforI(aO, bO, cI, dI, rI, rI); + for (int i = 0; i < SIZE; i++) { + Asserts.assertEquals(rI[i], cmoveOEQforI(aO[i], bO[i], cI[i], dI[i])); + } + + testCMoveONEforI(aO, bO, cI, dI, rI, rI); + for (int i = 0; i < SIZE; i++) { + Asserts.assertEquals(rI[i], cmoveONEforI(aO[i], bO[i], cI[i], dI[i])); + } + + testCMoveOEQforL(aO, bO, cL, dL, rL, rL); + for (int i = 0; i < SIZE; i++) { + Asserts.assertEquals(rL[i], cmoveOEQforL(aO[i], bO[i], cL[i], dL[i])); + } + + testCMoveONEforL(aO, bO, cL, dL, rL, rL); + for (int i = 0; i < SIZE; i++) { + Asserts.assertEquals(rL[i], cmoveONEforL(aO[i], bO[i], cL[i], dL[i])); + } + + testCMoveOEQforF(aO, bO, cF, dF, rF, rF); + for (int i = 0; i < SIZE; i++) { + Asserts.assertEquals(rF[i], cmoveOEQforF(aO[i], bO[i], cF[i], dF[i])); + } + + testCMoveONEforF(aO, bO, cF, dF, rF, rF); + for (int i = 0; i < SIZE; i++) { + Asserts.assertEquals(rF[i], cmoveONEforF(aO[i], bO[i], cF[i], dF[i])); + } + + testCMoveOEQforD(aO, bO, cD, dD, rD, rD); + for (int i = 0; i < SIZE; i++) { + Asserts.assertEquals(rD[i], cmoveOEQforD(aO[i], bO[i], cD[i], dD[i])); + } + + testCMoveONEforD(aO, bO, cD, dD, rD, rD); + for (int i = 0; i < SIZE; i++) { + Asserts.assertEquals(rD[i], cmoveONEforD(aO[i], bO[i], cD[i], dD[i])); + } + + } + + private static void init(Object[] a) { + for (int i = 0; i < SIZE; i++) { + a[i] = new Object(); + } + } + + private static void shuffle(Object[] a, Object[] b) { + for (int i = 0; i < a.length; i++) { + b[i] = a[i]; + } + Random rand = new Random(); + for (int i = 0; i < SIZE; i++) { + if (rand.nextInt(5) == 0) { + Object t = b[i]; + b[i] = b[SIZE-1-i]; + b[SIZE-1-i] = t; + } + } + } + + private static void init(int[] a) { + for (int i = 0; i < SIZE; i++) { + a[i] = RANDOM.nextInt(); + } + } + + private static void init(long[] a) { + for (int i = 0; i < SIZE; i++) { + a[i] = RANDOM.nextLong(); + } + } + + private static void init(float[] a) { + for (int i = 0; i < SIZE; i++) { + a[i] = switch(RANDOM.nextInt() % 20) { + case 0 -> Float.NaN; + case 1 -> 0; + case 2 -> 1; + case 3 -> Float.POSITIVE_INFINITY; + case 4 -> Float.NEGATIVE_INFINITY; + case 5 -> Float.MAX_VALUE; + case 6 -> Float.MIN_VALUE; + case 7, 8, 9 -> RANDOM.nextFloat(); + default -> Float.intBitsToFloat(RANDOM.nextInt()); + }; + } + } + + private static void init(double[] a) { + for (int i = 0; i < SIZE; i++) { + a[i] = switch(RANDOM.nextInt() % 20) { + case 0 -> Double.NaN; + case 1 -> 0; + case 2 -> 1; + case 3 -> Double.POSITIVE_INFINITY; + case 4 -> Double.NEGATIVE_INFINITY; + case 5 -> Double.MAX_VALUE; + case 6 -> Double.MIN_VALUE; + case 7, 8, 9 -> RANDOM.nextDouble(); + default -> Double.longBitsToDouble(RANDOM.nextLong()); + }; + } + } +} diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java index 1648135434a..41f185f3686 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java @@ -545,11 +545,36 @@ public class IRNode { trapNodes(CLASS_CHECK_TRAP, "class_check"); } + public static final String CMOVE_F = PREFIX + "CMOVE_F" + POSTFIX; + static { + beforeMatchingNameRegex(CMOVE_F, "CMoveF"); + } + + public static final String CMOVE_D = PREFIX + "CMOVE_D" + POSTFIX; + static { + beforeMatchingNameRegex(CMOVE_D, "CMoveD"); + } + public static final String CMOVE_I = PREFIX + "CMOVE_I" + POSTFIX; static { beforeMatchingNameRegex(CMOVE_I, "CMoveI"); } + public static final String CMOVE_L = PREFIX + "CMOVE_L" + POSTFIX; + static { + beforeMatchingNameRegex(CMOVE_L, "CMoveL"); + } + + public static final String CMP_F = PREFIX + "CMP_F" + POSTFIX; + static { + beforeMatchingNameRegex(CMP_F, "CmpF"); + } + + public static final String CMP_D = PREFIX + "CMP_D" + POSTFIX; + static { + beforeMatchingNameRegex(CMP_D, "CmpD"); + } + public static final String CMP_I = PREFIX + "CMP_I" + POSTFIX; static { beforeMatchingNameRegex(CMP_I, "CmpI"); @@ -585,6 +610,11 @@ public class IRNode { beforeMatchingNameRegex(CMP_P, "CmpP"); } + public static final String CMP_N = PREFIX + "CMP_N" + POSTFIX; + static { + beforeMatchingNameRegex(CMP_N, "CmpN"); + } + public static final String CMP_LT_MASK = PREFIX + "CMP_LT_MASK" + POSTFIX; static { beforeMatchingNameRegex(CMP_LT_MASK, "CmpLTMask"); diff --git a/test/micro/org/openjdk/bench/java/lang/ClassComparison.java b/test/micro/org/openjdk/bench/java/lang/ClassComparison.java index 2a768f243e2..15e631bb7fc 100644 --- a/test/micro/org/openjdk/bench/java/lang/ClassComparison.java +++ b/test/micro/org/openjdk/bench/java/lang/ClassComparison.java @@ -44,12 +44,8 @@ public class ClassComparison { Class[] c2; int[] res; long[] resLong; - Object[] resObject; - Object ro1; - Object ro2; - Object[] resClass; - Class rc1; - Class rc2; + float[] resFloat; + double[] resDouble; @Setup public void setup() { @@ -58,12 +54,8 @@ public class ClassComparison { c2 = new Class[INVOCATIONS]; res = new int[INVOCATIONS]; resLong = new long[INVOCATIONS]; - resObject = new Object[INVOCATIONS]; - ro1 = new Object(); - ro2 = new Object(); - resClass = new Class[INVOCATIONS]; - rc1 = Float.class; - rc2 = Double.class; + resFloat = new float[INVOCATIONS]; + resDouble = new double[INVOCATIONS]; for (int i = 0; i < INVOCATIONS; i++) { c1[i] = random.nextBoolean() ? Float.class : Double.class; } @@ -86,6 +78,7 @@ public class ClassComparison { } } + @Benchmark public void equalClassResLong() { for (int i = 0; i < INVOCATIONS; i++) { resLong[i] = (c1[i] == c2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; @@ -98,4 +91,32 @@ public class ClassComparison { resLong[i] = (c1[i] != c2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; } } + + @Benchmark + public void equalClassResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = (c1[i] == c2[i]) ? 0.1f : 0.2f; + } + } + + @Benchmark + public void notEqualClassResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = (c1[i] != c2[i]) ? 0.1f : 0.2f; + } + } + + @Benchmark + public void equalClassResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = (c1[i] == c2[i]) ? 0.1 : 0.2; + } + } + + @Benchmark + public void notEqualClassResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = (c1[i] != c2[i]) ? 0.1 : 0.2; + } + } } diff --git a/test/micro/org/openjdk/bench/java/lang/FPComparison.java b/test/micro/org/openjdk/bench/java/lang/FPComparison.java index 8074ada3257..18b2b79c7bd 100644 --- a/test/micro/org/openjdk/bench/java/lang/FPComparison.java +++ b/test/micro/org/openjdk/bench/java/lang/FPComparison.java @@ -37,34 +37,18 @@ import java.util.random.RandomGenerator; public class FPComparison { static final int INVOCATIONS = 1024; - float[] f1; - double[] d1; - float[] f2; - double[] d2; - int[] res; - long[] resLong; - Object[] resObject; - Object ro1; - Object ro2; - Class[] resClass; - Class rc1; - Class rc2; + static final float[] f1 = new float[INVOCATIONS]; + static final double[] d1 = new double[INVOCATIONS]; + static final float[] f2 = new float[INVOCATIONS]; + static final double[] d2 = new double[INVOCATIONS]; + static final int[] res = new int[INVOCATIONS];; + static final long[] resLong = new long[INVOCATIONS]; + static final float[] resFloat = new float[INVOCATIONS]; + static final double[] resDouble = new double[INVOCATIONS]; @Setup public void setup() { var random = RandomGenerator.getDefault(); - f1 = new float[INVOCATIONS]; - d1 = new double[INVOCATIONS]; - f2 = new float[INVOCATIONS]; - d2 = new double[INVOCATIONS]; - res = new int[INVOCATIONS]; - resLong = new long[INVOCATIONS]; - resObject = new Object[INVOCATIONS]; - ro1 = new Object(); - ro2 = new Object(); - resClass = new Class[INVOCATIONS]; - rc1 = Float.class; - rc2 = Double.class; for (int i = 0; i < INVOCATIONS; i++) { int type = random.nextInt(5); if (type == 1) { @@ -274,4 +258,148 @@ public class FPComparison { resLong[i] = (d1[i] >= d2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; } } + + // --------- result: float --------- + + @Benchmark + public void equalFloatResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = (f1[i] == f2[i]) ? 0.1f : 0.2f; + } + } + + @Benchmark + public void equalDoubleResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = (d1[i] == d2[i]) ? 0.1f : 0.2f; + } + } + + @Benchmark + public void lessFloatResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = (f1[i] < f2[i]) ? 0.1f : 0.2f; + } + } + + @Benchmark + public void lessDoubleResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = (d1[i] < d2[i]) ? 0.1f : 0.2f; + } + } + + @Benchmark + public void lessEqualFloatResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = (f1[i] <= f2[i]) ? 0.1f : 0.2f; + } + } + + @Benchmark + public void lessEqualDoubleResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = (d1[i] <= d2[i]) ? 0.1f : 0.2f; + } + } + + @Benchmark + public void greaterFloatResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = (f1[i] > f2[i]) ? 0.1f : 0.2f; + } + } + + @Benchmark + public void greaterDoubleResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = (d1[i] > d2[i]) ? 0.1f : 0.2f; + } + } + + @Benchmark + public void greaterEqualFloatResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = (f1[i] >= f2[i]) ? 0.1f : 0.2f; + } + } + + @Benchmark + public void greaterEqualDoubleResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = (d1[i] >= d2[i]) ? 0.1f : 0.2f; + } + } + + // --------- result: double --------- + + @Benchmark + public void equalFloatResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = (f1[i] == f2[i]) ? 0.1 : 0.2; + } + } + + @Benchmark + public void equalDoubleResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = (d1[i] == d2[i]) ? 0.1 : 0.2; + } + } + + @Benchmark + public void lessFloatResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = (f1[i] < f2[i]) ? 0.1 : 0.2; + } + } + + @Benchmark + public void lessDoubleResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = (d1[i] < d2[i]) ? 0.1 : 0.2; + } + } + + @Benchmark + public void lessEqualFloatResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = (f1[i] <= f2[i]) ? 0.1 : 0.2; + } + } + + @Benchmark + public void lessEqualDoubleResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = (d1[i] <= d2[i]) ? 0.1 : 0.2; + } + } + + @Benchmark + public void greaterFloatResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = (f1[i] > f2[i]) ? 0.1 : 0.2; + } + } + + @Benchmark + public void greaterDoubleResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = (d1[i] > d2[i]) ? 0.1 : 0.2; + } + } + + @Benchmark + public void greaterEqualFloatResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = (f1[i] >= f2[i]) ? 0.1 : 0.2; + } + } + + @Benchmark + public void greaterEqualDoubleResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = (d1[i] >= d2[i]) ? 0.1 : 0.2; + } + } } diff --git a/test/micro/org/openjdk/bench/java/lang/IntegerComparison.java b/test/micro/org/openjdk/bench/java/lang/IntegerComparison.java index 1853be8497d..832d398fc3d 100644 --- a/test/micro/org/openjdk/bench/java/lang/IntegerComparison.java +++ b/test/micro/org/openjdk/bench/java/lang/IntegerComparison.java @@ -42,12 +42,8 @@ public class IntegerComparison { int[] i2; int[] res; long[] resLong; - Object[] resObject; - Object ro1; - Object ro2; - Object[] resClass; - Class rc1; - Class rc2; + float[] resFloat; + double[] resDouble; @Setup public void setup() { @@ -56,18 +52,17 @@ public class IntegerComparison { i2 = new int[INVOCATIONS]; res = new int[INVOCATIONS]; resLong = new long[INVOCATIONS]; - resObject = new Object[INVOCATIONS]; - ro1 = new Object(); - ro2 = new Object(); - resClass = new Class[INVOCATIONS]; - rc1 = Float.class; - rc2 = Double.class; + resFloat = new float[INVOCATIONS]; + resDouble = new double[INVOCATIONS]; for (int i = 0; i < INVOCATIONS; i++) { i1[i] = random.nextInt(INVOCATIONS); i2[i] = random.nextInt(INVOCATIONS); } } + // --------- result: int --------- + // Signed comparison + @Benchmark public void equalInteger() { for (int i = 0; i < INVOCATIONS; i++) { @@ -110,8 +105,55 @@ public class IntegerComparison { } } - // --------- result: long --------- + // Unsigned comparison + @Benchmark + public void equalIntegerUnsigned() { + for (int i = 0; i < INVOCATIONS; i++) { + res[i] = Integer.compareUnsigned(i1[i], i2[i]) == 0 ? 1 : 2; + } + } + + @Benchmark + public void notEqualIntegerUnsigned() { + for (int i = 0; i < INVOCATIONS; i++) { + res[i] = Integer.compareUnsigned(i1[i], i2[i]) != 0 ? 1 : 2; + } + } + + @Benchmark + public void lessIntegerUnsigned() { + for (int i = 0; i < INVOCATIONS; i++) { + res[i] = Integer.compareUnsigned(i1[i], i2[i]) < 0 ? 1 : 2; + } + } + + @Benchmark + public void lessEqualIntegerUnsigned() { + for (int i = 0; i < INVOCATIONS; i++) { + res[i] = Integer.compareUnsigned(i1[i], i2[i]) <= 0 ? 1 : 2; + } + } + + @Benchmark + public void greaterIntegerUnsigned() { + for (int i = 0; i < INVOCATIONS; i++) { + res[i] = Integer.compareUnsigned(i1[i], i2[i]) > 0 ? 1 : 2; + } + } + + @Benchmark + public void greaterEqualIntegerUnsigned() { + for (int i = 0; i < INVOCATIONS; i++) { + res[i] = Integer.compareUnsigned(i1[i], i2[i]) >= 0 ? 1 : 2; + } + } + + + // --------- result: long --------- + // Signed comparison + + @Benchmark public void equalIntegerResLong() { for (int i = 0; i < INVOCATIONS; i++) { resLong[i] = (i1[i] == i2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; @@ -125,6 +167,7 @@ public class IntegerComparison { } } + @Benchmark public void lessIntegerResLong() { for (int i = 0; i < INVOCATIONS; i++) { resLong[i] = (i1[i] < i2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; @@ -138,6 +181,7 @@ public class IntegerComparison { } } + @Benchmark public void greaterIntegerResLong() { for (int i = 0; i < INVOCATIONS; i++) { resLong[i] = (i1[i] > i2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; @@ -150,4 +194,226 @@ public class IntegerComparison { resLong[i] = (i1[i] >= i2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; } } + + // Unsigned comparison + + @Benchmark + public void equalIntegerUnsignedResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = Integer.compareUnsigned(i1[i], i2[i]) == 0 ? Long.MAX_VALUE : Long.MIN_VALUE; + } + } + + @Benchmark + public void notEqualIntegerUnsignedResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = Integer.compareUnsigned(i1[i], i2[i]) != 0 ? Long.MAX_VALUE : Long.MIN_VALUE; + } + } + + @Benchmark + public void lessIntegerUnsignedResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = Integer.compareUnsigned(i1[i], i2[i]) < 0 ? Long.MAX_VALUE : Long.MIN_VALUE; + } + } + + @Benchmark + public void lessEqualIntegerUnsignedResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = Integer.compareUnsigned(i1[i], i2[i]) <= 0 ? Long.MAX_VALUE : Long.MIN_VALUE; + } + } + + @Benchmark + public void greaterIntegerUnsignedResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = Integer.compareUnsigned(i1[i], i2[i]) > 0 ? Long.MAX_VALUE : Long.MIN_VALUE; + } + } + + @Benchmark + public void greaterEqualIntegerUnsignedResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = Integer.compareUnsigned(i1[i], i2[i]) >= 0 ? Long.MAX_VALUE : Long.MIN_VALUE; + } + } + + // --------- result: float --------- + // Signed comparison + + @Benchmark + public void equalIntegerResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = (i1[i] == i2[i]) ? 0.1f : 0.2f; + } + } + + @Benchmark + public void notEqualIntegerResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = (i1[i] != i2[i]) ? 0.1f : 0.2f; + } + } + + @Benchmark + public void lessIntegerResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = (i1[i] < i2[i]) ? 0.1f : 0.2f; + } + } + + @Benchmark + public void lessEqualIntegerResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = (i1[i] <= i2[i]) ? 0.1f : 0.2f; + } + } + + @Benchmark + public void greaterIntegerResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = (i1[i] > i2[i]) ? 0.1f : 0.2f; + } + } + + @Benchmark + public void greaterEqualIntegerResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = (i1[i] >= i2[i]) ? 0.1f : 0.2f; + } + } + + // Unsigned comparison + + @Benchmark + public void equalIntegerUnsignedResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = Integer.compareUnsigned(i1[i], i2[i]) == 0 ? 0.1f : 0.2f; + } + } + + @Benchmark + public void notEqualIntegerUnsignedResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = Integer.compareUnsigned(i1[i], i2[i]) != 0 ? 0.1f : 0.2f; + } + } + + @Benchmark + public void lessIntegerUnsignedResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = Integer.compareUnsigned(i1[i], i2[i]) < 0 ? 0.1f : 0.2f; + } + } + + @Benchmark + public void lessEqualIntegerUnsignedResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = Integer.compareUnsigned(i1[i], i2[i]) <= 0 ? 0.1f : 0.2f; + } + } + + @Benchmark + public void greaterIntegerUnsignedResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = Integer.compareUnsigned(i1[i], i2[i]) > 0 ? 0.1f : 0.2f; + } + } + + @Benchmark + public void greaterEqualIntegerUnsignedResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = Integer.compareUnsigned(i1[i], i2[i]) >= 0 ? 0.1f : 0.2f; + } + } + + // --------- result: double --------- + // Signed comparison + + @Benchmark + public void equalIntegerResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = (i1[i] == i2[i]) ? 0.1 : 0.2; + } + } + + @Benchmark + public void notEqualIntegerResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = (i1[i] != i2[i]) ? 0.1 : 0.2; + } + } + + @Benchmark + public void lessIntegerResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = (i1[i] < i2[i]) ? 0.1 : 0.2; + } + } + + @Benchmark + public void lessEqualIntegerResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = (i1[i] <= i2[i]) ? 0.1 : 0.2; + } + } + + @Benchmark + public void greaterIntegerResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = (i1[i] > i2[i]) ? 0.1 : 0.2; + } + } + + @Benchmark + public void greaterEqualIntegerResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = (i1[i] >= i2[i]) ? 0.1 : 0.2; + } + } + + // Unsigned comparison + + @Benchmark + public void equalIntegerUnsignedResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = Integer.compareUnsigned(i1[i], i2[i]) == 0 ? 0.1 : 0.2; + } + } + + @Benchmark + public void notEqualIntegerUnsignedResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = Integer.compareUnsigned(i1[i], i2[i]) != 0 ? 0.1 : 0.2; + } + } + + @Benchmark + public void lessIntegerUnsignedResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = Integer.compareUnsigned(i1[i], i2[i]) < 0 ? 0.1 : 0.2; + } + } + + @Benchmark + public void lessEqualIntegerUnsignedResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = Integer.compareUnsigned(i1[i], i2[i]) <= 0 ? 0.1 : 0.2; + } + } + + @Benchmark + public void greaterIntegerUnsignedResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = Integer.compareUnsigned(i1[i], i2[i]) > 0 ? 0.1 : 0.2; + } + } + + @Benchmark + public void greaterEqualIntegerUnsignedResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = Integer.compareUnsigned(i1[i], i2[i]) >= 0 ? 0.1 : 0.2; + } + } } diff --git a/test/micro/org/openjdk/bench/java/lang/LongComparison.java b/test/micro/org/openjdk/bench/java/lang/LongComparison.java index bed5ee245b2..a7317244c6f 100644 --- a/test/micro/org/openjdk/bench/java/lang/LongComparison.java +++ b/test/micro/org/openjdk/bench/java/lang/LongComparison.java @@ -41,12 +41,8 @@ public class LongComparison { long[] l2; int[] res; long[] resLong; - Object[] resObject; - Object ro1; - Object ro2; - Object[] resClass; - Class rc1; - Class rc2; + float[] resFloat; + double[] resDouble; @Setup public void setup() { @@ -55,18 +51,17 @@ public class LongComparison { l2 = new long[INVOCATIONS]; res = new int[INVOCATIONS]; resLong = new long[INVOCATIONS]; - resObject = new Object[INVOCATIONS]; - ro1 = new Object(); - ro2 = new Object(); - resClass = new Class[INVOCATIONS]; - rc1 = Float.class; - rc2 = Double.class; + resFloat = new float[INVOCATIONS]; + resDouble = new double[INVOCATIONS]; for (int i = 0; i < INVOCATIONS; i++) { l1[i] = random.nextLong(INVOCATIONS); l2[i] = random.nextLong(INVOCATIONS); } } + // --------- result: int --------- + // Signed comparison + @Benchmark public void equalLong() { for (int i = 0; i < INVOCATIONS; i++) { @@ -109,8 +104,54 @@ public class LongComparison { } } - // --------- result: long --------- + // Unsigned comparison + @Benchmark + public void equalLongUnsigned() { + for (int i = 0; i < INVOCATIONS; i++) { + res[i] = Long.compareUnsigned(l1[i], l2[i]) == 0 ? 1 : 2; + } + } + + @Benchmark + public void notEqualLongUnsigned() { + for (int i = 0; i < INVOCATIONS; i++) { + res[i] = Long.compareUnsigned(l1[i], l2[i]) != 0 ? 1 : 2; + } + } + + @Benchmark + public void lessLongUnsigned() { + for (int i = 0; i < INVOCATIONS; i++) { + res[i] = Long.compareUnsigned(l1[i], l2[i]) < 0 ? 1 : 2; + } + } + + @Benchmark + public void lessEqualLongUnsigned() { + for (int i = 0; i < INVOCATIONS; i++) { + res[i] = Long.compareUnsigned(l1[i], l2[i]) <= 0 ? 1 : 2; + } + } + + @Benchmark + public void greaterLongUnsigned() { + for (int i = 0; i < INVOCATIONS; i++) { + res[i] = Long.compareUnsigned(l1[i], l2[i]) > 0 ? 1 : 2; + } + } + + @Benchmark + public void greaterEqualLongUnsigned() { + for (int i = 0; i < INVOCATIONS; i++) { + res[i] = Long.compareUnsigned(l1[i], l2[i]) >= 0 ? 1 : 2; + } + } + + // --------- result: long --------- + // Signed comparison + + @Benchmark public void equalLongResLong() { for (int i = 0; i < INVOCATIONS; i++) { resLong[i] = (l1[i] == l2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; @@ -124,6 +165,7 @@ public class LongComparison { } } + @Benchmark public void lessLongResLong() { for (int i = 0; i < INVOCATIONS; i++) { resLong[i] = (l1[i] < l2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; @@ -137,6 +179,7 @@ public class LongComparison { } } + @Benchmark public void greaterLongResLong() { for (int i = 0; i < INVOCATIONS; i++) { resLong[i] = (l1[i] > l2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; @@ -149,4 +192,226 @@ public class LongComparison { resLong[i] = (l1[i] >= l2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; } } + + // Unsigned comparison + + @Benchmark + public void equalLongUnsignedResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = Long.compareUnsigned(l1[i], l2[i]) == 0 ? Long.MAX_VALUE : Long.MIN_VALUE; + } + } + + @Benchmark + public void notEqualLongUnsignedResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = Long.compareUnsigned(l1[i], l2[i]) != 0 ? Long.MAX_VALUE : Long.MIN_VALUE; + } + } + + @Benchmark + public void lessLongUnsignedResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = Long.compareUnsigned(l1[i], l2[i]) < 0 ? Long.MAX_VALUE : Long.MIN_VALUE; + } + } + + @Benchmark + public void lessEqualLongUnsignedResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = Long.compareUnsigned(l1[i], l2[i]) <= 0 ? Long.MAX_VALUE : Long.MIN_VALUE; + } + } + + @Benchmark + public void greaterLongUnsignedResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = Long.compareUnsigned(l1[i], l2[i]) > 0 ? Long.MAX_VALUE : Long.MIN_VALUE; + } + } + + @Benchmark + public void greaterEqualLongUnsignedResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = Long.compareUnsigned(l1[i], l2[i]) >= 0 ? Long.MAX_VALUE : Long.MIN_VALUE; + } + } + + // --------- result: float --------- + // Signed comparison + + @Benchmark + public void equalLongResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = (l1[i] == l2[i]) ? 0.1f : 0.2f; + } + } + + @Benchmark + public void notEqualLongResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = (l1[i] != l2[i]) ? 0.1f : 0.2f; + } + } + + @Benchmark + public void lessLongResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = (l1[i] < l2[i]) ? 0.1f : 0.2f; + } + } + + @Benchmark + public void lessEqualLongResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = (l1[i] <= l2[i]) ? 0.1f : 0.2f; + } + } + + @Benchmark + public void greaterLongResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = (l1[i] > l2[i]) ? 0.1f : 0.2f; + } + } + + @Benchmark + public void greaterEqualLongResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = (l1[i] >= l2[i]) ? 0.1f : 0.2f; + } + } + + // Unsigned comparison + + @Benchmark + public void equalLongUnsignedResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = Long.compareUnsigned(l1[i], l2[i]) == 0 ? 0.1f : 0.2f; + } + } + + @Benchmark + public void notEqualLongUnsignedResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = Long.compareUnsigned(l1[i], l2[i]) != 0 ? 0.1f : 0.2f; + } + } + + @Benchmark + public void lessLongUnsignedResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = Long.compareUnsigned(l1[i], l2[i]) < 0 ? 0.1f : 0.2f; + } + } + + @Benchmark + public void lessEqualLongUnsignedResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = Long.compareUnsigned(l1[i], l2[i]) <= 0 ? 0.1f : 0.2f; + } + } + + @Benchmark + public void greaterLongUnsignedResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = Long.compareUnsigned(l1[i], l2[i]) > 0 ? 0.1f : 0.2f; + } + } + + @Benchmark + public void greaterEqualLongUnsignedResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = Long.compareUnsigned(l1[i], l2[i]) >= 0 ? 0.1f : 0.2f; + } + } + + // --------- result: double --------- + // Signed comparison + + @Benchmark + public void equalLongResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = (l1[i] == l2[i]) ? 0.1 : 0.2; + } + } + + @Benchmark + public void notEqualLongResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = (l1[i] != l2[i]) ? 0.1 : 0.2; + } + } + + @Benchmark + public void lessLongResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = (l1[i] < l2[i]) ? 0.1 : 0.2; + } + } + + @Benchmark + public void lessEqualLongResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = (l1[i] <= l2[i]) ? 0.1 : 0.2; + } + } + + @Benchmark + public void greaterLongResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = (l1[i] > l2[i]) ? 0.1 : 0.2; + } + } + + @Benchmark + public void greaterEqualLongResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = (l1[i] >= l2[i]) ? 0.1 : 0.2; + } + } + + // Unsigned comparison + + @Benchmark + public void equalLongUnsignedResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = Long.compareUnsigned(l1[i], l2[i]) == 0 ? 0.1 : 0.2; + } + } + + @Benchmark + public void notEqualLongUnsignedResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = Long.compareUnsigned(l1[i], l2[i]) != 0 ? 0.1 : 0.2; + } + } + + @Benchmark + public void lessLongUnsignedResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = Long.compareUnsigned(l1[i], l2[i]) < 0 ? 0.1 : 0.2; + } + } + + @Benchmark + public void lessEqualLongUnsignedResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = Long.compareUnsigned(l1[i], l2[i]) <= 0 ? 0.1 : 0.2; + } + } + + @Benchmark + public void greaterLongUnsignedResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = Long.compareUnsigned(l1[i], l2[i]) > 0 ? 0.1 : 0.2; + } + } + + @Benchmark + public void greaterEqualLongUnsignedResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = Long.compareUnsigned(l1[i], l2[i]) >= 0 ? 0.1 : 0.2; + } + } } diff --git a/test/micro/org/openjdk/bench/java/lang/PointerComparison.java b/test/micro/org/openjdk/bench/java/lang/PointerComparison.java index b6bcf008619..fc2fd95b1c0 100644 --- a/test/micro/org/openjdk/bench/java/lang/PointerComparison.java +++ b/test/micro/org/openjdk/bench/java/lang/PointerComparison.java @@ -44,12 +44,8 @@ public class PointerComparison { Object[] o2; int[] res; long[] resLong; - Object[] resObject; - Object ro1; - Object ro2; - Object[] resClass; - Class rc1; - Class rc2; + float[] resFloat; + double[] resDouble; @Setup public void setup() { @@ -58,12 +54,8 @@ public class PointerComparison { o2 = new Object[INVOCATIONS]; res = new int[INVOCATIONS]; resLong = new long[INVOCATIONS]; - resObject = new Object[INVOCATIONS]; - ro1 = new Object(); - ro2 = new Object(); - resClass = new Class[INVOCATIONS]; - rc1 = Float.class; - rc2 = Double.class; + resFloat = new float[INVOCATIONS]; + resDouble = new double[INVOCATIONS]; for (int i = 0; i < INVOCATIONS; i++) { o1[i] = new Object(); } @@ -86,6 +78,7 @@ public class PointerComparison { } } + @Benchmark public void equalObjectResLong() { for (int i = 0; i < INVOCATIONS; i++) { resLong[i] = (o1[i] == o2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; @@ -98,4 +91,32 @@ public class PointerComparison { resLong[i] = (o1[i] != o2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; } } + + @Benchmark + public void equalObjecResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = (o1[i] == o2[i]) ? 0.1f : 0.2f; + } + } + + @Benchmark + public void notEqualObjecResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = (o1[i] != o2[i]) ? 0.1f : 0.2f; + } + } + + @Benchmark + public void equalObjecResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = (o1[i] == o2[i]) ? 0.1 : 0.2; + } + } + + @Benchmark + public void notEqualObjecResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = (o1[i] != o2[i]) ? 0.1 : 0.2; + } + } } From ed5fc9ad2defb75ea5a68fe6427a591376ce6d6b Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Mon, 8 Dec 2025 14:21:40 +0000 Subject: [PATCH 205/706] 8373087: Parallel: Rename PSGenerationPool to PSOldGenerationPool Reviewed-by: tschatzl, jsikstro, iwalulya --- src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp | 6 +++--- src/hotspot/share/gc/parallel/psMemoryPool.cpp | 8 ++++---- src/hotspot/share/gc/parallel/psMemoryPool.hpp | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp index b85b16f58b5..cff53e84059 100644 --- a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp +++ b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp @@ -141,9 +141,9 @@ void ParallelScavengeHeap::initialize_serviceability() { "PS Survivor Space", false /* support_usage_threshold */); - _old_pool = new PSGenerationPool(_old_gen, - "PS Old Gen", - true /* support_usage_threshold */); + _old_pool = new PSOldGenerationPool(_old_gen, + "PS Old Gen", + true /* support_usage_threshold */); _young_manager = new GCMemoryManager("PS Scavenge"); _old_manager = new GCMemoryManager("PS MarkSweep"); diff --git a/src/hotspot/share/gc/parallel/psMemoryPool.cpp b/src/hotspot/share/gc/parallel/psMemoryPool.cpp index c120664600b..81c7b17a1ef 100644 --- a/src/hotspot/share/gc/parallel/psMemoryPool.cpp +++ b/src/hotspot/share/gc/parallel/psMemoryPool.cpp @@ -24,14 +24,14 @@ #include "gc/parallel/psMemoryPool.hpp" -PSGenerationPool::PSGenerationPool(PSOldGen* old_gen, - const char* name, - bool support_usage_threshold) : +PSOldGenerationPool::PSOldGenerationPool(PSOldGen* old_gen, + const char* name, + bool support_usage_threshold) : CollectedMemoryPool(name, old_gen->capacity_in_bytes(), old_gen->reserved().byte_size(), support_usage_threshold), _old_gen(old_gen) { } -MemoryUsage PSGenerationPool::get_memory_usage() { +MemoryUsage PSOldGenerationPool::get_memory_usage() { size_t maxSize = (available_for_allocation() ? max_size() : 0); size_t used = used_in_bytes(); size_t committed = _old_gen->capacity_in_bytes(); diff --git a/src/hotspot/share/gc/parallel/psMemoryPool.hpp b/src/hotspot/share/gc/parallel/psMemoryPool.hpp index 58f39cdc79f..0da47e5a8ef 100644 --- a/src/hotspot/share/gc/parallel/psMemoryPool.hpp +++ b/src/hotspot/share/gc/parallel/psMemoryPool.hpp @@ -31,12 +31,12 @@ #include "services/memoryPool.hpp" #include "services/memoryUsage.hpp" -class PSGenerationPool : public CollectedMemoryPool { +class PSOldGenerationPool : public CollectedMemoryPool { private: PSOldGen* _old_gen; public: - PSGenerationPool(PSOldGen* pool, const char* name, bool support_usage_threshold); + PSOldGenerationPool(PSOldGen* pool, const char* name, bool support_usage_threshold); MemoryUsage get_memory_usage(); size_t used_in_bytes() { return _old_gen->used_in_bytes(); } From ac81ce51fa4ed04b6dbcc28cb2dd8eabcfe52ad7 Mon Sep 17 00:00:00 2001 From: Chris Plummer Date: Mon, 8 Dec 2025 15:38:35 +0000 Subject: [PATCH 206/706] 8372555: Test com/sun/jdi/ExceptionEvents.java failed: ObjectCollectedException Reviewed-by: amenkov, dholmes --- test/jdk/com/sun/jdi/ExceptionEvents.java | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/test/jdk/com/sun/jdi/ExceptionEvents.java b/test/jdk/com/sun/jdi/ExceptionEvents.java index de5f51c4aa2..ee9e91b4dd9 100644 --- a/test/jdk/com/sun/jdi/ExceptionEvents.java +++ b/test/jdk/com/sun/jdi/ExceptionEvents.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, 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 @@ -355,7 +355,16 @@ public class ExceptionEvents extends TestScaffold { if (event.request() == request) { try { System.out.print("ExceptionEvent: "); - System.out.print("" + event.exception().referenceType().name()); + try { + System.out.print("" + event.exception().referenceType().name()); + } catch (ObjectCollectedException e) { + if (event.request().suspendPolicy() == EventRequest.SUSPEND_NONE) { + // Since the thread was not suspended, the exception object can be collected. + System.out.print(""); + } else { + throw e; + } + } Location loc = event.location(); System.out.print(" @ " + loc.method().name()); System.out.print(":" + loc.lineNumber()); From 355755d35de5c3155d1ea8d1afdd0debe5296a13 Mon Sep 17 00:00:00 2001 From: Anton Artemov Date: Mon, 8 Dec 2025 16:07:01 +0000 Subject: [PATCH 207/706] 8366671: Refactor Thread::SpinAcquire and Thread::SpinRelease Co-authored-by: Axel Boldt-Christmas Reviewed-by: coleenp, kbarrett, dholmes, aboldtch --- .../recorder/service/jfrEventThrottler.cpp | 4 +- .../share/jfr/support/jfrAdaptiveSampler.cpp | 4 +- .../share/jfr/support/jfrThreadLocal.cpp | 1 - .../share/jfr/utilities/jfrSpinlockHelper.hpp | 44 ------------ src/hotspot/share/runtime/objectMonitor.cpp | 24 +++---- src/hotspot/share/runtime/park.cpp | 7 +- .../share/runtime/safepointVerifiers.cpp | 4 +- src/hotspot/share/runtime/thread.cpp | 46 ------------- src/hotspot/share/runtime/thread.hpp | 5 -- .../share/utilities/spinCriticalSection.cpp | 69 +++++++++++++++++++ .../share/utilities/spinCriticalSection.hpp | 63 +++++++++++++++++ .../gtest/jfr/test_adaptiveSampler.cpp | 3 +- 12 files changed, 155 insertions(+), 119 deletions(-) delete mode 100644 src/hotspot/share/jfr/utilities/jfrSpinlockHelper.hpp create mode 100644 src/hotspot/share/utilities/spinCriticalSection.cpp create mode 100644 src/hotspot/share/utilities/spinCriticalSection.hpp diff --git a/src/hotspot/share/jfr/recorder/service/jfrEventThrottler.cpp b/src/hotspot/share/jfr/recorder/service/jfrEventThrottler.cpp index 787b2d7456b..e5420d29d94 100644 --- a/src/hotspot/share/jfr/recorder/service/jfrEventThrottler.cpp +++ b/src/hotspot/share/jfr/recorder/service/jfrEventThrottler.cpp @@ -24,11 +24,11 @@ */ #include "jfr/recorder/service/jfrEventThrottler.hpp" -#include "jfr/utilities/jfrSpinlockHelper.hpp" #include "jfrfiles/jfrEventIds.hpp" #include "logging/log.hpp" #include "utilities/debug.hpp" #include "utilities/globalDefinitions.hpp" +#include "utilities/spinCriticalSection.hpp" constexpr static const JfrSamplerParams _disabled_params = { 0, // sample points per window @@ -128,7 +128,7 @@ JfrEventThrottler* JfrEventThrottler::create_throttler(JfrEventId id) { * - period_ms time period expressed in milliseconds */ void JfrEventThrottler::configure(int64_t sample_size, int64_t period_ms) { - JfrSpinlockHelper mutex(&_lock); + SpinCriticalSection scs(&_lock); _sample_size = sample_size; _period_ms = period_ms; _update = true; diff --git a/src/hotspot/share/jfr/support/jfrAdaptiveSampler.cpp b/src/hotspot/share/jfr/support/jfrAdaptiveSampler.cpp index 22399f42bbb..571b5656576 100644 --- a/src/hotspot/share/jfr/support/jfrAdaptiveSampler.cpp +++ b/src/hotspot/share/jfr/support/jfrAdaptiveSampler.cpp @@ -25,13 +25,13 @@ #include "jfr/support/jfrAdaptiveSampler.hpp" #include "jfr/utilities/jfrRandom.inline.hpp" -#include "jfr/utilities/jfrSpinlockHelper.hpp" #include "jfr/utilities/jfrTime.hpp" #include "jfr/utilities/jfrTimeConverter.hpp" #include "jfr/utilities/jfrTryLock.hpp" #include "logging/log.hpp" #include "runtime/atomicAccess.hpp" #include "utilities/globalDefinitions.hpp" +#include "utilities/spinCriticalSection.hpp" #include @@ -342,7 +342,7 @@ JfrGTestFixedRateSampler::JfrGTestFixedRateSampler(size_t sample_points_per_wind bool JfrGTestFixedRateSampler::initialize() { const bool result = JfrAdaptiveSampler::initialize(); - JfrSpinlockHelper mutex(&_lock); + SpinCriticalSection scs(&_lock); reconfigure(); return result; } diff --git a/src/hotspot/share/jfr/support/jfrThreadLocal.cpp b/src/hotspot/share/jfr/support/jfrThreadLocal.cpp index 5fe5546e0a9..39b0eb3656c 100644 --- a/src/hotspot/share/jfr/support/jfrThreadLocal.cpp +++ b/src/hotspot/share/jfr/support/jfrThreadLocal.cpp @@ -36,7 +36,6 @@ #include "jfr/recorder/storage/jfrStorage.hpp" #include "jfr/support/jfrThreadId.inline.hpp" #include "jfr/support/jfrThreadLocal.hpp" -#include "jfr/utilities/jfrSpinlockHelper.hpp" #include "jfr/writers/jfrJavaEventWriter.hpp" #include "logging/log.hpp" #include "memory/allocation.inline.hpp" diff --git a/src/hotspot/share/jfr/utilities/jfrSpinlockHelper.hpp b/src/hotspot/share/jfr/utilities/jfrSpinlockHelper.hpp deleted file mode 100644 index 4b5ca80470e..00000000000 --- a/src/hotspot/share/jfr/utilities/jfrSpinlockHelper.hpp +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2013, 2025, 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. - * - */ - -#ifndef SHARE_JFR_UTILITIES_JFRSPINLOCKHELPER_HPP -#define SHARE_JFR_UTILITIES_JFRSPINLOCKHELPER_HPP - -#include "runtime/javaThread.hpp" - -class JfrSpinlockHelper { - private: - volatile int* const _lock; - - public: - JfrSpinlockHelper(volatile int* lock) : _lock(lock) { - Thread::SpinAcquire(_lock); - } - - ~JfrSpinlockHelper() { - Thread::SpinRelease(_lock); - } -}; - -#endif // SHARE_JFR_UTILITIES_JFRSPINLOCKHELPER_HPP diff --git a/src/hotspot/share/runtime/objectMonitor.cpp b/src/hotspot/share/runtime/objectMonitor.cpp index ee7629ec6f5..785ee2af592 100644 --- a/src/hotspot/share/runtime/objectMonitor.cpp +++ b/src/hotspot/share/runtime/objectMonitor.cpp @@ -59,6 +59,7 @@ #include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" #include "utilities/preserveException.hpp" +#include "utilities/spinCriticalSection.hpp" #if INCLUDE_JFR #include "jfr/support/jfrFlush.hpp" #endif @@ -1863,9 +1864,10 @@ void ObjectMonitor::wait(jlong millis, bool interruptible, TRAPS) { // returns because of a timeout of interrupt. Contention is exceptionally rare // so we use a simple spin-lock instead of a heavier-weight blocking lock. - Thread::SpinAcquire(&_wait_set_lock); - add_waiter(&node); - Thread::SpinRelease(&_wait_set_lock); + { + SpinCriticalSection scs(&_wait_set_lock); + add_waiter(&node); + } intx save = _recursions; // record the old recursion count _waiters++; // increment the number of waiters @@ -1922,12 +1924,11 @@ void ObjectMonitor::wait(jlong millis, bool interruptible, TRAPS) { // That is, we fail toward safety. if (node.TState == ObjectWaiter::TS_WAIT) { - Thread::SpinAcquire(&_wait_set_lock); + SpinCriticalSection scs(&_wait_set_lock); if (node.TState == ObjectWaiter::TS_WAIT) { dequeue_specific_waiter(&node); // unlink from wait_set node.TState = ObjectWaiter::TS_RUN; } - Thread::SpinRelease(&_wait_set_lock); } // The thread is now either on off-list (TS_RUN), @@ -2036,7 +2037,7 @@ void ObjectMonitor::wait(jlong millis, bool interruptible, TRAPS) { bool ObjectMonitor::notify_internal(JavaThread* current) { bool did_notify = false; - Thread::SpinAcquire(&_wait_set_lock); + SpinCriticalSection scs(&_wait_set_lock); ObjectWaiter* iterator = dequeue_waiter(); if (iterator != nullptr) { guarantee(iterator->TState == ObjectWaiter::TS_WAIT, "invariant"); @@ -2095,7 +2096,6 @@ bool ObjectMonitor::notify_internal(JavaThread* current) { } } } - Thread::SpinRelease(&_wait_set_lock); return did_notify; } @@ -2198,9 +2198,10 @@ void ObjectMonitor::vthread_wait(JavaThread* current, jlong millis, bool interru // returns because of a timeout or interrupt. Contention is exceptionally rare // so we use a simple spin-lock instead of a heavier-weight blocking lock. - Thread::SpinAcquire(&_wait_set_lock); - add_waiter(node); - Thread::SpinRelease(&_wait_set_lock); + { + SpinCriticalSection scs(&_wait_set_lock); + add_waiter(node); + } node->_recursions = _recursions; // record the old recursion count _recursions = 0; // set the recursion level to be 0 @@ -2221,12 +2222,11 @@ bool ObjectMonitor::vthread_wait_reenter(JavaThread* current, ObjectWaiter* node // need to check if we were interrupted or the wait timed-out, and // in that case remove ourselves from the _wait_set queue. if (node->TState == ObjectWaiter::TS_WAIT) { - Thread::SpinAcquire(&_wait_set_lock); + SpinCriticalSection scs(&_wait_set_lock); if (node->TState == ObjectWaiter::TS_WAIT) { dequeue_specific_waiter(node); // unlink from wait_set node->TState = ObjectWaiter::TS_RUN; } - Thread::SpinRelease(&_wait_set_lock); } // If this was an interrupted case, set the _interrupted boolean so that diff --git a/src/hotspot/share/runtime/park.cpp b/src/hotspot/share/runtime/park.cpp index 37dfe6fcc3d..338a01bbfb9 100644 --- a/src/hotspot/share/runtime/park.cpp +++ b/src/hotspot/share/runtime/park.cpp @@ -25,6 +25,7 @@ #include "memory/allocation.inline.hpp" #include "nmt/memTracker.hpp" #include "runtime/javaThread.hpp" +#include "utilities/spinCriticalSection.hpp" // Lifecycle management for TSM ParkEvents. // ParkEvents are type-stable (TSM). @@ -60,14 +61,13 @@ ParkEvent * ParkEvent::Allocate (Thread * t) { // Using a spin lock since we are part of the mutex impl. // 8028280: using concurrent free list without memory management can leak // pretty badly it turns out. - Thread::SpinAcquire(&ListLock); { + SpinCriticalSection scs(&ListLock); ev = FreeList; if (ev != nullptr) { FreeList = ev->FreeNext; } } - Thread::SpinRelease(&ListLock); if (ev != nullptr) { guarantee (ev->AssociatedWith == nullptr, "invariant") ; @@ -88,12 +88,11 @@ void ParkEvent::Release (ParkEvent * ev) { ev->AssociatedWith = nullptr ; // Note that if we didn't have the TSM/immortal constraint, then // when reattaching we could trim the list. - Thread::SpinAcquire(&ListLock); { + SpinCriticalSection scs(&ListLock); ev->FreeNext = FreeList; FreeList = ev; } - Thread::SpinRelease(&ListLock); } // Override operator new and delete so we can ensure that the diff --git a/src/hotspot/share/runtime/safepointVerifiers.cpp b/src/hotspot/share/runtime/safepointVerifiers.cpp index 6eb61efe0ca..0c6f2e9add3 100644 --- a/src/hotspot/share/runtime/safepointVerifiers.cpp +++ b/src/hotspot/share/runtime/safepointVerifiers.cpp @@ -30,7 +30,9 @@ #ifdef ASSERT -NoSafepointVerifier::NoSafepointVerifier(bool active) : _thread(Thread::current()), _active(active) { +NoSafepointVerifier::NoSafepointVerifier(bool active) + : _thread(active ? Thread::current() : nullptr), + _active(active) { if (!_active) { return; } diff --git a/src/hotspot/share/runtime/thread.cpp b/src/hotspot/share/runtime/thread.cpp index d018c8a1a3a..f3c08ae62f7 100644 --- a/src/hotspot/share/runtime/thread.cpp +++ b/src/hotspot/share/runtime/thread.cpp @@ -566,49 +566,3 @@ bool Thread::set_as_starting_thread(JavaThread* jt) { DEBUG_ONLY(_starting_thread = jt;) return os::create_main_thread(jt); } - -// Ad-hoc mutual exclusion primitive: spin lock -// -// We employ a spin lock _only for low-contention, fixed-length -// short-duration critical sections where we're concerned -// about native mutex_t or HotSpot Mutex:: latency. - -void Thread::SpinAcquire(volatile int * adr) { - if (AtomicAccess::cmpxchg(adr, 0, 1) == 0) { - return; // normal fast-path return - } - - // Slow-path : We've encountered contention -- Spin/Yield/Block strategy. - int ctr = 0; - int Yields = 0; - for (;;) { - while (*adr != 0) { - ++ctr; - if ((ctr & 0xFFF) == 0 || !os::is_MP()) { - if (Yields > 5) { - os::naked_short_sleep(1); - } else { - os::naked_yield(); - ++Yields; - } - } else { - SpinPause(); - } - } - if (AtomicAccess::cmpxchg(adr, 0, 1) == 0) return; - } -} - -void Thread::SpinRelease(volatile int * adr) { - assert(*adr != 0, "invariant"); - // Roach-motel semantics. - // It's safe if subsequent LDs and STs float "up" into the critical section, - // but prior LDs and STs within the critical section can't be allowed - // to reorder or float past the ST that releases the lock. - // Loads and stores in the critical section - which appear in program - // order before the store that releases the lock - must also appear - // before the store that releases the lock in memory visibility order. - // So we need a #loadstore|#storestore "release" memory barrier before - // the ST of 0 into the lock-word which releases the lock. - AtomicAccess::release_store(adr, 0); -} diff --git a/src/hotspot/share/runtime/thread.hpp b/src/hotspot/share/runtime/thread.hpp index 240821e90bd..181dfc46f87 100644 --- a/src/hotspot/share/runtime/thread.hpp +++ b/src/hotspot/share/runtime/thread.hpp @@ -602,11 +602,6 @@ protected: jint _hashStateY; jint _hashStateZ; - // Low-level leaf-lock primitives used to implement synchronization. - // Not for general synchronization use. - static void SpinAcquire(volatile int * Lock); - static void SpinRelease(volatile int * Lock); - #if defined(__APPLE__) && defined(AARCH64) private: DEBUG_ONLY(bool _wx_init); diff --git a/src/hotspot/share/utilities/spinCriticalSection.cpp b/src/hotspot/share/utilities/spinCriticalSection.cpp new file mode 100644 index 00000000000..0bbbc82c12b --- /dev/null +++ b/src/hotspot/share/utilities/spinCriticalSection.cpp @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2025, 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. + * + */ + +#include "runtime/atomicAccess.hpp" +#include "utilities/spinCriticalSection.hpp" + +void SpinCriticalSection::spin_acquire(volatile int* adr) { + if (AtomicAccess::cmpxchg(adr, 0, 1) == 0) { + return; // normal fast-path return + } + + // Slow-path : We've encountered contention -- Spin/Yield/Block strategy. + int ctr = 0; + int Yields = 0; + for (;;) { + while (*adr != 0) { + ++ctr; + if ((ctr & 0xFFF) == 0 || !os::is_MP()) { + if (Yields > 5) { + os::naked_short_sleep(1); + } + else { + os::naked_yield(); + ++Yields; + } + } + else { + SpinPause(); + } + } + if (AtomicAccess::cmpxchg(adr, 0, 1) == 0) return; + } +} + +void SpinCriticalSection::spin_release(volatile int* adr) { + assert(*adr != 0, "invariant"); + // Roach-motel semantics. + // It's safe if subsequent LDs and STs float "up" into the critical section, + // but prior LDs and STs within the critical section can't be allowed + // to reorder or float past the ST that releases the lock. + // Loads and stores in the critical section - which appear in program + // order before the store that releases the lock - must also appear + // before the store that releases the lock in memory visibility order. + // So we need a #loadstore|#storestore "release" memory barrier before + // the ST of 0 into the lock-word which releases the lock. + AtomicAccess::release_store(adr, 0); +} + diff --git a/src/hotspot/share/utilities/spinCriticalSection.hpp b/src/hotspot/share/utilities/spinCriticalSection.hpp new file mode 100644 index 00000000000..0ebdc5de63e --- /dev/null +++ b/src/hotspot/share/utilities/spinCriticalSection.hpp @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2025, 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. + * + */ + +#ifndef SHARE_UTILITIES_SPINCRITICALSECTION_HPP +#define SHARE_UTILITIES_SPINCRITICALSECTION_HPP + +#include "runtime/javaThread.hpp" +#include "runtime/safepointVerifiers.hpp" +#include "runtime/thread.hpp" +#include "utilities/macros.hpp" + +// Ad-hoc mutual exclusion primitive: spin critical section, +// which employs a spin lock. +// +// We use this critical section only for low-contention code, and +// when it is know that the duration is short. To be used where +// we're concerned about native mutex_t or HotSpot Mutex:: latency. +// This class uses low-level leaf-lock primitives to implement +// synchronization and is not for general synchronization use. +// Should not be used in signal-handling contexts. +class SpinCriticalSection { +private: + // We use int type as 32-bit atomic operation is the most performant + // compared to smaller/larger types. + volatile int* const _lock; + DEBUG_ONLY(NoSafepointVerifier _nsv;) + + static void spin_acquire(volatile int* Lock); + static void spin_release(volatile int* Lock); +public: + NONCOPYABLE(SpinCriticalSection); + SpinCriticalSection(volatile int* lock) + : _lock(lock) + DEBUG_ONLY(COMMA _nsv(Thread::current_or_null() != nullptr)) { + spin_acquire(_lock); + } + ~SpinCriticalSection() { + spin_release(_lock); + } +}; + +#endif // SHARE_UTILITIES_SPINCRITICALSECTION_HPP diff --git a/test/hotspot/gtest/jfr/test_adaptiveSampler.cpp b/test/hotspot/gtest/jfr/test_adaptiveSampler.cpp index 69548b06e51..8625f64099d 100644 --- a/test/hotspot/gtest/jfr/test_adaptiveSampler.cpp +++ b/test/hotspot/gtest/jfr/test_adaptiveSampler.cpp @@ -34,13 +34,12 @@ #include "jfr/utilities/jfrAllocation.hpp" #include "jfr/utilities/jfrRandom.inline.hpp" -#include "jfr/utilities/jfrSpinlockHelper.hpp" #include "jfr/utilities/jfrTime.hpp" #include "jfr/utilities/jfrTimeConverter.hpp" #include "jfr/utilities/jfrTryLock.hpp" #include "logging/log.hpp" -#include "runtime/atomicAccess.hpp" #include "utilities/globalDefinitions.hpp" +#include "utilities/spinCriticalSection.hpp" #include "unittest.hpp" #include From 811591c5c332e6427dc96819451e046841fe635b Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Mon, 8 Dec 2025 16:11:28 +0000 Subject: [PATCH 208/706] 8373262: Parallel: gc/metaspace/CompressedClassSpaceSizeInJmapHeap.java fails Reviewed-by: cjplummer --- .../sun/jvm/hotspot/gc/parallel/ParallelScavengeHeap.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/parallel/ParallelScavengeHeap.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/parallel/ParallelScavengeHeap.java index 76125e33e80..b0d158f409d 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/parallel/ParallelScavengeHeap.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/parallel/ParallelScavengeHeap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, 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,11 +60,11 @@ public class ParallelScavengeHeap extends CollectedHeap { // Accessors public PSYoungGen youngGen() { - return VMObjectFactory.newObject(PSYoungGen.class, youngGenField.getValue()); + return VMObjectFactory.newObject(PSYoungGen.class, youngGenField.getValue(addr)); } public PSOldGen oldGen() { - return VMObjectFactory.newObject(PSOldGen.class, oldGenField.getValue()); + return VMObjectFactory.newObject(PSOldGen.class, oldGenField.getValue(addr)); } public long capacity() { From d34ef196c298aa91f8511714cfb04b15ae7fbf0a Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Mon, 8 Dec 2025 18:51:34 +0000 Subject: [PATCH 209/706] 8370198: Test gc/arguments/TestShrinkHeapInSteps.java crashed: assert(left >= right) failed: avoid underflow Reviewed-by: stefank, tschatzl --- .../cpu/aarch64/macroAssembler_aarch64.cpp | 1 - src/hotspot/cpu/riscv/macroAssembler_riscv.cpp | 1 - src/hotspot/share/gc/serial/serialHeap.cpp | 17 +++++++++++++++++ src/hotspot/share/gc/serial/serialHeap.hpp | 2 ++ 4 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp index ceedb4f1063..2ccc755be3c 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp @@ -5379,7 +5379,6 @@ void MacroAssembler::set_narrow_klass(Register dst, Klass* k) { assert (UseCompressedClassPointers, "should only be used for compressed headers"); assert (oop_recorder() != nullptr, "this assembler needs an OopRecorder"); int index = oop_recorder()->find_index(k); - assert(! Universe::heap()->is_in(k), "should not be an oop"); InstructionMark im(this); RelocationHolder rspec = metadata_Relocation::spec(index); diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index a14a051fd3b..43b17a13c20 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -5187,7 +5187,6 @@ void MacroAssembler::set_narrow_klass(Register dst, Klass* k) { assert (UseCompressedClassPointers, "should only be used for compressed headers"); assert (oop_recorder() != nullptr, "this assembler needs an OopRecorder"); int index = oop_recorder()->find_index(k); - assert(!Universe::heap()->is_in(k), "should not be an oop"); narrowKlass nk = CompressedKlassPointers::encode(k); relocate(metadata_Relocation::spec(index), [&] { diff --git a/src/hotspot/share/gc/serial/serialHeap.cpp b/src/hotspot/share/gc/serial/serialHeap.cpp index 932c06b8109..104924c1cad 100644 --- a/src/hotspot/share/gc/serial/serialHeap.cpp +++ b/src/hotspot/share/gc/serial/serialHeap.cpp @@ -630,6 +630,14 @@ bool SerialHeap::requires_barriers(stackChunkOop obj) const { // Returns "TRUE" iff "p" points into the committed areas of the heap. bool SerialHeap::is_in(const void* p) const { + // precondition + verify_not_in_native_if_java_thread(); + + if (!is_in_reserved(p)) { + // If it's not even in reserved. + return false; + } + return _young_gen->is_in(p) || _old_gen->is_in(p); } @@ -797,3 +805,12 @@ void SerialHeap::gc_epilogue(bool full) { MetaspaceCounters::update_performance_counters(); }; + +#ifdef ASSERT +void SerialHeap::verify_not_in_native_if_java_thread() { + if (Thread::current()->is_Java_thread()) { + JavaThread* thread = JavaThread::current(); + assert(thread->thread_state() != _thread_in_native, "precondition"); + } +} +#endif diff --git a/src/hotspot/share/gc/serial/serialHeap.hpp b/src/hotspot/share/gc/serial/serialHeap.hpp index ee016173c2a..f5286179abf 100644 --- a/src/hotspot/share/gc/serial/serialHeap.hpp +++ b/src/hotspot/share/gc/serial/serialHeap.hpp @@ -111,6 +111,8 @@ private: void print_tracing_info() const override; void stop() override {}; + static void verify_not_in_native_if_java_thread() NOT_DEBUG_RETURN; + public: // Returns JNI_OK on success jint initialize() override; From b118caf6777cbf5bf75b41156fdfaaa15479f924 Mon Sep 17 00:00:00 2001 From: Alexandre Iline Date: Mon, 8 Dec 2025 22:16:28 +0000 Subject: [PATCH 210/706] 8373285: Update JCov for class file version 71 Reviewed-by: erikj --- make/conf/jib-profiles.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/make/conf/jib-profiles.js b/make/conf/jib-profiles.js index 795335d7c3c..93aeebc0dd6 100644 --- a/make/conf/jib-profiles.js +++ b/make/conf/jib-profiles.js @@ -1192,8 +1192,8 @@ var getJibProfilesDependencies = function (input, common) { server: "jpg", product: "jcov", version: "3.0", - build_number: "3", - file: "bundles/jcov-3.0+3.zip", + build_number: "5", + file: "bundles/jcov-3.0+5.zip", environment_name: "JCOV_HOME", }, From 8df3f3d3417bc8fdb5a75d986e084441bbf6ebd2 Mon Sep 17 00:00:00 2001 From: Erik Joelsson Date: Mon, 8 Dec 2025 22:45:59 +0000 Subject: [PATCH 211/706] 8373117: Update build doc link in README.md Reviewed-by: ayang, tbell --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b3f30676b3c..e939f6a9ca4 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Welcome to the JDK! For build instructions please see the -[online documentation](https://openjdk.org/groups/build/doc/building.html), +[online documentation](https://git.openjdk.org/jdk/blob/master/doc/building.md), or either of these files: - [doc/building.html](doc/building.html) (html version) From b86b2cbc7d9dd57aeaf64f70f248a120ae3cb751 Mon Sep 17 00:00:00 2001 From: Ben Taylor Date: Tue, 9 Dec 2025 00:17:30 +0000 Subject: [PATCH 212/706] 8352914: Shenandoah: Change definition of ShenandoahSharedValue to int32_t to leverage platform atomics Reviewed-by: wkemper, ysr --- .../share/gc/shenandoah/shenandoahSharedVariables.hpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahSharedVariables.hpp b/src/hotspot/share/gc/shenandoah/shenandoahSharedVariables.hpp index 127882201d7..12c01ad5c90 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahSharedVariables.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahSharedVariables.hpp @@ -29,11 +29,7 @@ #include "memory/allocation.hpp" #include "runtime/atomicAccess.hpp" -typedef jbyte ShenandoahSharedValue; - -// Needed for cooperation with generated code. -STATIC_ASSERT(sizeof(ShenandoahSharedValue) == 1); - +typedef int32_t ShenandoahSharedValue; typedef struct ShenandoahSharedFlag { enum { UNSET = 0, From c03d445a8ccfced5a59da680c37587f1024f3eca Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Tue, 9 Dec 2025 00:34:58 +0000 Subject: [PATCH 213/706] 6223700: XP L&F: Non-TopLevel JMenu's painting error Reviewed-by: kizune, dnguyen --- .../swing/plaf/windows/WindowsMenuUI.java | 2 +- .../swing/JMenu/TestPaintSpillOverBug.java | 82 +++++++++++++++++++ 2 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 test/jdk/javax/swing/JMenu/TestPaintSpillOverBug.java diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuUI.java index 130b09227cc..a7aca0c5ccf 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuUI.java @@ -301,7 +301,7 @@ public final class WindowsMenuUI extends BasicMenuUI { JMenu menu = (JMenu)evt.getSource(); ButtonModel model = menu.getModel(); - if (menu.isRolloverEnabled()) { + if (menu.isRolloverEnabled() && menu.isTopLevelMenu()) { model.setRollover(false); menuItem.repaint(); } diff --git a/test/jdk/javax/swing/JMenu/TestPaintSpillOverBug.java b/test/jdk/javax/swing/JMenu/TestPaintSpillOverBug.java new file mode 100644 index 00000000000..8452b93cf45 --- /dev/null +++ b/test/jdk/javax/swing/JMenu/TestPaintSpillOverBug.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2025, 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 6223700 + * @requires (os.family == "windows") + * @summary Verifies no painting spillover in Win L&F + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual TestPaintSpillOverBug + */ + +import javax.swing.JFrame; +import javax.swing.JMenuBar; +import javax.swing.JMenu; +import javax.swing.UIManager; + +public class TestPaintSpillOverBug { + + static final String INSTRUCTIONS = """ + A JMenu "click Me" will be shown. Click on it. + Position the mouse in the "Slowly Move Mouse Out of This" JMenu + so that the popup menu appears to the right. + Slowly move the mouse towards the edge of the item, + one pixel at a time + When the mouse hits the edge, + if the selection background spill over on to the popup + press Fail else press Pass."""; + + public static void main(String[] args) throws Exception { + UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); + + PassFailJFrame.builder() + .title("TestPaintSpillOverBug Instructions") + .instructions(INSTRUCTIONS) + .columns(60) + .testUI(TestPaintSpillOverBug::createUI) + .position(PassFailJFrame.Position.TOP_LEFT_CORNER) + .build() + .awaitAndCheck(); + + } + + static JFrame createUI() { + JFrame f = new JFrame("TestPaintSpillOverBug"); + JMenuBar bar = new JMenuBar(); + JMenu clickMe = new JMenu("Click Me"); + JMenu culprit = new JMenu("Slowly Move Mouse Out of This"); + culprit.add("This item gets partially obscured"); + culprit.add(" "); + clickMe.add(" "); + clickMe.addSeparator(); + clickMe.add(culprit); + clickMe.addSeparator(); + clickMe.add(" "); + bar.add(clickMe); + f.setJMenuBar(bar); + f.setSize(600, 200); + return f; + } +} From b1c955018281a228a67695e5077666d751cd87d2 Mon Sep 17 00:00:00 2001 From: Phil Race Date: Tue, 9 Dec 2025 01:00:52 +0000 Subject: [PATCH 214/706] 8372554: Test windows-x64-cmp-baseline failed due to differences with splashscreen object file Reviewed-by: dholmes --- make/modules/java.desktop/lib/ClientLibraries.gmk | 1 - 1 file changed, 1 deletion(-) diff --git a/make/modules/java.desktop/lib/ClientLibraries.gmk b/make/modules/java.desktop/lib/ClientLibraries.gmk index f273065a6df..499d5bef841 100644 --- a/make/modules/java.desktop/lib/ClientLibraries.gmk +++ b/make/modules/java.desktop/lib/ClientLibraries.gmk @@ -226,7 +226,6 @@ ifeq ($(ENABLE_HEADLESS_ONLY), false) EXCLUDE_FILES := imageioJPEG.c jpegdecoder.c pngtest.c, \ EXCLUDES := $(LIBSPLASHSCREEN_EXCLUDES), \ OPTIMIZATION := SIZE, \ - LINK_TIME_OPTIMIZATION := true, \ CFLAGS := $(LIBSPLASHSCREEN_CFLAGS) \ $(GIFLIB_CFLAGS) $(LIBJPEG_CFLAGS) $(PNG_CFLAGS) $(LIBZ_CFLAGS) \ $(ICONV_CFLAGS), \ From 3ea82b9ff90aebc1a169fdd967c44408dc4a4f51 Mon Sep 17 00:00:00 2001 From: Xiaolong Peng Date: Tue, 9 Dec 2025 01:16:48 +0000 Subject: [PATCH 215/706] 8373272: Genshen: ShenandoahOldGenerationTest fails after JDK-8373056 Reviewed-by: wkemper --- .../test_shenandoahOldGeneration.cpp | 29 ++----------------- 1 file changed, 3 insertions(+), 26 deletions(-) diff --git a/test/hotspot/gtest/gc/shenandoah/test_shenandoahOldGeneration.cpp b/test/hotspot/gtest/gc/shenandoah/test_shenandoahOldGeneration.cpp index b2491226e5c..4167e33b706 100644 --- a/test/hotspot/gtest/gc/shenandoah/test_shenandoahOldGeneration.cpp +++ b/test/hotspot/gtest/gc/shenandoah/test_shenandoahOldGeneration.cpp @@ -165,35 +165,12 @@ TEST_VM_F(ShenandoahOldGenerationTest, test_actual_size_exceeds_promotion_reserv EXPECT_FALSE(promotions_enabled()) << "New plab can only be used for evacuations"; } -TEST_VM_F(ShenandoahOldGenerationTest, test_shared_expends_promoted_but_does_not_change_plab) { +TEST_VM_F(ShenandoahOldGenerationTest, test_expend_promoted_should_increase_expended) { SKIP_IF_NOT_SHENANDOAH(); - ShenandoahAllocRequest req = ShenandoahAllocRequest::for_shared_gc(128, ShenandoahAffiliation::OLD_GENERATION, true); - req.set_actual_size(128); - size_t actual_size = req.actual_size() * HeapWordSize; - size_t expended_before = old->get_promoted_expended(); - old->configure_plab_for_current_thread(req); + old->expend_promoted(128); size_t expended_after = old->get_promoted_expended(); - - EXPECT_EQ(expended_before + actual_size, expended_after) << "Shared promotion still expends promotion"; - EXPECT_EQ(plab_promoted(), INITIAL_PLAB_PROMOTED) << "Shared promotion should not count in plab"; - EXPECT_EQ(plab_size(), INITIAL_PLAB_SIZE) << "Shared promotion should not change size of plab"; - EXPECT_FALSE(promotions_enabled()); -} - -TEST_VM_F(ShenandoahOldGenerationTest, test_shared_evacuation_has_no_side_effects) { - SKIP_IF_NOT_SHENANDOAH(); - ShenandoahAllocRequest req = ShenandoahAllocRequest::for_shared_gc(128, ShenandoahAffiliation::OLD_GENERATION, false); - req.set_actual_size(128); - - size_t expended_before = old->get_promoted_expended(); - old->configure_plab_for_current_thread(req); - size_t expended_after = old->get_promoted_expended(); - - EXPECT_EQ(expended_before, expended_after) << "Not a promotion, should not expend promotion reserve"; - EXPECT_EQ(plab_promoted(), INITIAL_PLAB_PROMOTED) << "Not a plab, should not have touched plab"; - EXPECT_EQ(plab_size(), INITIAL_PLAB_SIZE) << "Not a plab, should not have touched plab"; - EXPECT_FALSE(promotions_enabled()); + EXPECT_EQ(expended_before + 128, expended_after) << "Should expend promotion"; } #undef SKIP_IF_NOT_SHENANDOAH From c9ab330b7bdd3cc2410ffdb336a63aa0ac7256a3 Mon Sep 17 00:00:00 2001 From: Xiaolong Peng Date: Tue, 9 Dec 2025 03:28:11 +0000 Subject: [PATCH 216/706] 8373116: Genshen: arraycopy_work should be always done for arrays in old gen during young concurrent marking 8372498: [genshen] gc/TestAllocHumongousFragment.java#generational causes intermittent SIGSEGV crashes Reviewed-by: wkemper, kdnilsen --- .../share/gc/shenandoah/shenandoahBarrierSet.hpp | 4 ++-- .../gc/shenandoah/shenandoahBarrierSet.inline.hpp | 11 ++++++++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.hpp b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.hpp index 2b5bc766a46..7db478a781a 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.hpp @@ -128,8 +128,8 @@ public: void write_ref_array(HeapWord* start, size_t count); private: - template - inline void arraycopy_marking(T* dst, size_t count); + template + void arraycopy_marking(T* dst, size_t count); template inline void arraycopy_evacuation(T* src, size_t count); template diff --git a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.inline.hpp index adeea8ebf96..199256ca31b 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.inline.hpp @@ -429,7 +429,11 @@ void ShenandoahBarrierSet::arraycopy_barrier(T* src, T* dst, size_t count) { // If marking old or young, we must evaluate the SATB barrier. This will be the only // action if we are not marking old. If we are marking old, we must still evaluate the // load reference barrier for a young collection. - arraycopy_marking(dst, count); + if (_heap->mode()->is_generational()) { + arraycopy_marking(dst, count); + } else { + arraycopy_marking(dst, count); + } } if ((gc_state & ShenandoahHeap::EVACUATION) != 0) { @@ -441,11 +445,12 @@ void ShenandoahBarrierSet::arraycopy_barrier(T* src, T* dst, size_t count) { } } -template +template void ShenandoahBarrierSet::arraycopy_marking(T* dst, size_t count) { assert(_heap->is_concurrent_mark_in_progress(), "only during marking"); if (ShenandoahSATBBarrier) { - if (!_heap->marking_context()->allocated_after_mark_start(reinterpret_cast(dst))) { + if (!_heap->marking_context()->allocated_after_mark_start(reinterpret_cast(dst)) || + (IS_GENERATIONAL && _heap->heap_region_containing(dst)->is_old() && _heap->is_concurrent_young_mark_in_progress())) { arraycopy_work(dst, count); } } From 35fe0b11015bd3a88ee21c76b54f9d4969fdedf6 Mon Sep 17 00:00:00 2001 From: Harshit470250 <133243171+Harshit470250@users.noreply.github.com> Date: Tue, 9 Dec 2025 04:59:53 +0000 Subject: [PATCH 217/706] 8372641: [s390x] Test failure TestMergeStores.java Reviewed-by: mhaessig, amitkumar, lucy --- src/hotspot/cpu/s390/s390.ad | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/hotspot/cpu/s390/s390.ad b/src/hotspot/cpu/s390/s390.ad index 7d3e963a108..19bd3620228 100644 --- a/src/hotspot/cpu/s390/s390.ad +++ b/src/hotspot/cpu/s390/s390.ad @@ -1715,6 +1715,8 @@ bool Matcher::match_rule_supported(int opcode) { switch (opcode) { case Op_ReverseBytesI: case Op_ReverseBytesL: + case Op_ReverseBytesS: + case Op_ReverseBytesUS: return UseByteReverseInstruction; case Op_PopCountI: case Op_PopCountL: @@ -11615,6 +11617,38 @@ instruct vround2D_reg(vecX dst, vecX src, immI8 rmode) %{ // Byte reverse +instruct bytes_reverse_short(iRegI dst, iRegI src) %{ + match(Set dst (ReverseBytesS src)); + predicate(UseByteReverseInstruction); + ins_cost(2 * DEFAULT_COST); + size(8); + + format %{ "LRVR $dst, $src\n\t # byte reverse int" + "SRA $dst, 0x0010\t # right shift by 16, sign extended" %} + + ins_encode %{ + __ z_lrvr($dst$$Register, $src$$Register); + __ z_sra($dst$$Register, 0x0010); + %} + ins_pipe(pipe_class_dummy); +%} + +instruct bytes_reverse_unsigned_short(iRegI dst, iRegI src) %{ + match(Set dst (ReverseBytesUS src)); + predicate(UseByteReverseInstruction); + ins_cost(2 * DEFAULT_COST); + size(8); + + format %{ "LRVR $dst, $src\n\t # byte reverse int" + "SRL $dst, 0x0010\t # right shift by 16, zero extended" %} + + ins_encode %{ + __ z_lrvr($dst$$Register, $src$$Register); + __ z_srl($dst$$Register, 0x0010); + %} + ins_pipe(pipe_class_dummy); +%} + instruct bytes_reverse_int(iRegI dst, iRegI src) %{ match(Set dst (ReverseBytesI src)); predicate(UseByteReverseInstruction); // See Matcher::match_rule_supported From 020e3f959194029715c18891e79aeed020abd59c Mon Sep 17 00:00:00 2001 From: David Holmes Date: Tue, 9 Dec 2025 05:15:47 +0000 Subject: [PATCH 218/706] 8373293: Change the exception handling in TestNestHostErrorWithMultiThread.java Reviewed-by: jpai, iklam --- .../TestNestHostErrorWithMultiThread.java | 69 +++++++++++++------ 1 file changed, 47 insertions(+), 22 deletions(-) diff --git a/test/hotspot/jtreg/runtime/Nestmates/membership/TestNestHostErrorWithMultiThread.java b/test/hotspot/jtreg/runtime/Nestmates/membership/TestNestHostErrorWithMultiThread.java index 11025fd4c12..0559c5858e0 100644 --- a/test/hotspot/jtreg/runtime/Nestmates/membership/TestNestHostErrorWithMultiThread.java +++ b/test/hotspot/jtreg/runtime/Nestmates/membership/TestNestHostErrorWithMultiThread.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2021, Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (c) 2025, 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 @@ -40,14 +41,12 @@ import java.util.concurrent.CountDownLatch; public class TestNestHostErrorWithMultiThread { - public static void main(String args[]) { + public static void main(String args[]) throws Throwable { CountDownLatch runLatch = new CountDownLatch(1); CountDownLatch startLatch = new CountDownLatch(2); - Runnable test = new Test(runLatch, startLatch); - - Thread t1 = new Thread(test); - Thread t2 = new Thread(test); + TestThread t1 = new TestThread(runLatch, startLatch); + TestThread t2 = new TestThread(runLatch, startLatch); t1.start(); t2.start(); @@ -59,39 +58,65 @@ public class TestNestHostErrorWithMultiThread { t1.join(); t2.join(); + + Throwable threadException = t1.exception() != null ? t1.exception() + : t2.exception(); + if (threadException != null) { + Throwable t = threadException; + try { + throw new Error("TestThread encountered unexpected exception", t); + } + catch (OutOfMemoryError oome) { + // If we encounter an OOME trying to create the wrapper Error, + // then just re-throw the original exception so we report it and + // not the secondary OOME. + throw t; + } + } } catch (InterruptedException e) { throw new Error("Unexpected interrupt"); } } - static class Test implements Runnable { + static class TestThread extends Thread { private CountDownLatch runLatch; private CountDownLatch startLatch; + private Throwable exception; - Test(CountDownLatch runLatch, CountDownLatch startLatch) { + Throwable exception() { + return exception; + } + + TestThread(CountDownLatch runLatch, CountDownLatch startLatch) { this.runLatch = runLatch; this.startLatch = startLatch; } @Override public void run() { + // Don't allow any exceptions to escape - the main thread will + // report them. try { - startLatch.countDown(); - // Try to have all threads trigger the nesthost check at the same time - runLatch.await(); - HostNoNestMember h = new HostNoNestMember(); - h.test(); - throw new Error("IllegalAccessError was not thrown as expected"); - } catch (IllegalAccessError expected) { - String msg = "current type is not listed as a nest member"; - if (!expected.getMessage().contains(msg)) { - throw new Error("Wrong " + expected.getClass().getSimpleName() +": \"" + - expected.getMessage() + "\" does not contain \"" + - msg + "\"", expected); + try { + startLatch.countDown(); + // Try to have all threads trigger the nesthost check at the same time + runLatch.await(); + HostNoNestMember h = new HostNoNestMember(); + h.test(); + throw new Error("IllegalAccessError was not thrown as expected"); + } catch (IllegalAccessError expected) { + String msg = "current type is not listed as a nest member"; + if (!expected.getMessage().contains(msg)) { + throw new Error("Wrong " + expected.getClass().getSimpleName() +": \"" + + expected.getMessage() + "\" does not contain \"" + + msg + "\"", expected); + } + System.out.println("OK - got expected exception: " + expected); + } catch (InterruptedException e) { + throw new Error("Unexpected interrupt", e); } - System.out.println("OK - got expected exception: " + expected); - } catch (InterruptedException e) { - throw new Error("Unexpected interrupt"); + } catch (Throwable t) { + exception = t; } } } From cba09cd10d4e4482852a317786242836419c313b Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Tue, 9 Dec 2025 07:40:52 +0000 Subject: [PATCH 219/706] 5107379: Component orientation in JOptionPane is not proper in Motif L&F. Reviewed-by: tr, kizune --- .../swing/plaf/motif/MotifOptionPaneUI.java | 5 +- .../javax/swing/plaf/motif/TestIconRTL.java | 119 ++++++++++++++++++ 2 files changed, 122 insertions(+), 2 deletions(-) create mode 100644 test/jdk/javax/swing/plaf/motif/TestIconRTL.java diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifOptionPaneUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifOptionPaneUI.java index e68d7e2d8bf..21e8c0f6747 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifOptionPaneUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifOptionPaneUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, 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,7 @@ package com.sun.java.swing.plaf.motif; +import java.awt.BorderLayout; import java.awt.Color; import java.awt.Container; import java.awt.Dimension; @@ -102,7 +103,7 @@ public class MotifOptionPaneUI extends BasicOptionPaneUI JLabel iconLabel = new JLabel(sideIcon); iconLabel.setVerticalAlignment(SwingConstants.CENTER); - top.add(iconLabel, "West"); + top.add(iconLabel, BorderLayout.BEFORE_LINE_BEGINS); } } diff --git a/test/jdk/javax/swing/plaf/motif/TestIconRTL.java b/test/jdk/javax/swing/plaf/motif/TestIconRTL.java new file mode 100644 index 00000000000..e86e1ab38a6 --- /dev/null +++ b/test/jdk/javax/swing/plaf/motif/TestIconRTL.java @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2025, 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 5107379 + * @summary Component orientation in JOptionPane is not proper in Motif L&F. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual TestIconRTL + */ + +import java.awt.ComponentOrientation; +import java.util.concurrent.atomic.AtomicBoolean; +import javax.swing.JFrame; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JOptionPane; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; + +public class TestIconRTL { + + private static JFrame frame; + private static JOptionPane pane; + + static final String INSTRUCTIONS = """ + A JOptionPane is shown in Motif LookAndFeel with "Orientation" menu. + Click on "Orientation" menu and + test with "Left To Right" and "Right to Left" Orientation + If JOptionPane is drawn properly in different orientation, + then test passed, otherwise it failed."""; + + public static void main(String[] args) throws Exception { + UIManager.setLookAndFeel("com.sun.java.swing.plaf.motif.MotifLookAndFeel"); + PassFailJFrame.builder() + .title("TestIconRTL Instructions") + .instructions(INSTRUCTIONS) + .columns(60) + .testUI(TestIconRTL::createTestUI) + .build() + .awaitAndCheck(); + } + + static JFrame createTestUI() { + pane = new JOptionPane(new String("Testing CCC4265463"), + JOptionPane.INFORMATION_MESSAGE, JOptionPane.YES_NO_CANCEL_OPTION); + pane.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT); + pane.setVisible(true); + + frame = new JFrame("TestIconRTL"); + + JMenuBar menuBar = new JMenuBar(); + menuBar.add(getOrientationJMenu()); + + frame.setJMenuBar(menuBar); + + frame.getContentPane().add(pane); + frame.pack(); + frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + frame.setLocationRelativeTo(null); + return frame; + } + + public static void test() throws Exception { + AtomicBoolean leftToRightOrientationFlag = new AtomicBoolean(false); + SwingUtilities.invokeAndWait(() -> leftToRightOrientationFlag.set(pane.getComponentOrientation().isLeftToRight())); + if (leftToRightOrientationFlag.get()) { + System.out.println("LTR LOCATION ..."); + } else { + System.out.println("RTL LOCATION ..."); + } + } + + private static JMenu getOrientationJMenu() { + JMenu lafMenu = new JMenu("Orientation"); + JMenuItem leftToRight = new JMenuItem("Left to Right"); + leftToRight.addActionListener(e -> { + pane.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT); + pane.invalidate(); + SwingUtilities.updateComponentTreeUI(frame); + }); + + JMenuItem rightToLeft = new JMenuItem("Right to Left"); + rightToLeft.addActionListener(e -> { + pane.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT); + pane.invalidate(); + SwingUtilities.updateComponentTreeUI(frame); + }); + + pane.invalidate(); + lafMenu.add(leftToRight); + lafMenu.add(rightToLeft); + return lafMenu; + } + + +} From 3a8a6e07f2a2cffa467815df55e746e92765903d Mon Sep 17 00:00:00 2001 From: Ramkumar Sunderbabu Date: Tue, 9 Dec 2025 09:15:04 +0000 Subject: [PATCH 220/706] 8319326: GC: Make TestParallelRefProc use createTestJavaProcessBuilder Reviewed-by: stefank, iwalulya --- .../gc/arguments/TestParallelRefProc.java | 85 +++++++++++++------ 1 file changed, 57 insertions(+), 28 deletions(-) diff --git a/test/hotspot/jtreg/gc/arguments/TestParallelRefProc.java b/test/hotspot/jtreg/gc/arguments/TestParallelRefProc.java index 6e2e3c0239e..2cd9e9cd60b 100644 --- a/test/hotspot/jtreg/gc/arguments/TestParallelRefProc.java +++ b/test/hotspot/jtreg/gc/arguments/TestParallelRefProc.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, 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,13 +24,30 @@ package gc.arguments; /* - * @test TestParallelRefProc - * @summary Test defaults processing for -XX:+ParallelRefProcEnabled. + * @test id=Serial + * @summary Test defaults processing for -XX:+ParallelRefProcEnabled with Serial GC. * @library /test/lib * @library / - * @build jdk.test.whitebox.WhiteBox - * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI gc.arguments.TestParallelRefProc + * @requires vm.gc.Serial + * @run driver gc.arguments.TestParallelRefProc Serial + */ + +/* + * @test id=Parallel + * @summary Test defaults processing for -XX:+ParallelRefProcEnabled with Parallel GC. + * @library /test/lib + * @library / + * @requires vm.gc.Parallel + * @run driver gc.arguments.TestParallelRefProc Parallel + */ + +/* + * @test id=G1 + * @summary Test defaults processing for -XX:+ParallelRefProcEnabled with G1 GC. + * @library /test/lib + * @library / + * @requires vm.gc.G1 + * @run driver gc.arguments.TestParallelRefProc G1 */ import java.util.Arrays; @@ -38,34 +55,46 @@ import java.util.ArrayList; import jdk.test.lib.process.OutputAnalyzer; -import jtreg.SkippedException; -import jdk.test.whitebox.gc.GC; - public class TestParallelRefProc { public static void main(String args[]) throws Exception { - boolean noneGCSupported = true; - if (GC.Serial.isSupported()) { - noneGCSupported = false; - testFlag(new String[] { "-XX:+UseSerialGC" }, false); + if (args.length == 0) { + throw new IllegalArgumentException("Test type must be specified as argument"); } - if (GC.Parallel.isSupported()) { - noneGCSupported = false; - testFlag(new String[] { "-XX:+UseParallelGC", "-XX:ParallelGCThreads=1" }, false); - testFlag(new String[] { "-XX:+UseParallelGC", "-XX:ParallelGCThreads=2" }, true); - testFlag(new String[] { "-XX:+UseParallelGC", "-XX:-ParallelRefProcEnabled", "-XX:ParallelGCThreads=2" }, false); - } - if (GC.G1.isSupported()) { - noneGCSupported = false; - testFlag(new String[] { "-XX:+UseG1GC", "-XX:ParallelGCThreads=1" }, false); - testFlag(new String[] { "-XX:+UseG1GC", "-XX:ParallelGCThreads=2" }, true); - testFlag(new String[] { "-XX:+UseG1GC", "-XX:-ParallelRefProcEnabled", "-XX:ParallelGCThreads=2" }, false); - } - if (noneGCSupported) { - throw new SkippedException("Skipping test because none of Serial/Parallel/G1 is supported."); + + String testType = args[0]; + + switch (testType) { + case "Serial": + testSerial(); + break; + case "Parallel": + testParallel(); + break; + case "G1": + testG1(); + break; + default: + throw new IllegalArgumentException("Unknown test type \"" + testType + "\""); } } + private static void testSerial() throws Exception { + testFlag(new String[] { "-XX:+UseSerialGC" }, false); + } + + private static void testParallel() throws Exception { + testFlag(new String[] { "-XX:+UseParallelGC", "-XX:ParallelGCThreads=1" }, false); + testFlag(new String[] { "-XX:+UseParallelGC", "-XX:ParallelGCThreads=2" }, true); + testFlag(new String[] { "-XX:+UseParallelGC", "-XX:-ParallelRefProcEnabled", "-XX:ParallelGCThreads=2" }, false); + } + + private static void testG1() throws Exception { + testFlag(new String[] { "-XX:+UseG1GC", "-XX:ParallelGCThreads=1" }, false); + testFlag(new String[] { "-XX:+UseG1GC", "-XX:ParallelGCThreads=2" }, true); + testFlag(new String[] { "-XX:+UseG1GC", "-XX:-ParallelRefProcEnabled", "-XX:ParallelGCThreads=2" }, false); + } + private static final String parallelRefProcEnabledPattern = " *bool +ParallelRefProcEnabled *= *true +\\{product\\}"; @@ -77,7 +106,7 @@ public class TestParallelRefProc { result.addAll(Arrays.asList(args)); result.add("-XX:+PrintFlagsFinal"); result.add("-version"); - OutputAnalyzer output = GCArguments.executeLimitedTestJava(result); + OutputAnalyzer output = GCArguments.executeTestJava(result); output.shouldHaveExitValue(0); From 24244e41210be5b71b9e8238badbf975ed4b02ef Mon Sep 17 00:00:00 2001 From: Ramkumar Sunderbabu Date: Tue, 9 Dec 2025 09:17:38 +0000 Subject: [PATCH 221/706] 8319161: GC: Make TestParallelGCThreads use createTestJavaProcessBuilder Reviewed-by: stefank, iwalulya --- .../gc/arguments/TestParallelGCThreads.java | 139 ++++++++++++------ 1 file changed, 91 insertions(+), 48 deletions(-) diff --git a/test/hotspot/jtreg/gc/arguments/TestParallelGCThreads.java b/test/hotspot/jtreg/gc/arguments/TestParallelGCThreads.java index 0ce17efd1a7..9b5e9843b5e 100644 --- a/test/hotspot/jtreg/gc/arguments/TestParallelGCThreads.java +++ b/test/hotspot/jtreg/gc/arguments/TestParallelGCThreads.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, 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,30 +24,86 @@ package gc.arguments; /* - * @test TestParallelGCThreads + * @test id=DefaultValue * @bug 8059527 8081382 - * @summary Tests argument processing for ParallelGCThreads + * @summary Tests default value of ParallelGCThreads * @library /test/lib * @library / - * @modules java.base/jdk.internal.misc - * java.management - * @build jdk.test.whitebox.WhiteBox - * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI gc.arguments.TestParallelGCThreads + * @requires vm.gc.Z | vm.gc.Parallel | vm.gc.G1 + * @run driver gc.arguments.TestParallelGCThreads DefaultValue + */ + +/* + * @test id=Z + * @bug 8059527 8081382 + * @summary Tests argument processing for ParallelGCThreads with ZGC + * @library /test/lib + * @library / + * @requires vm.gc.Z + * @run driver gc.arguments.TestParallelGCThreads Z + */ + +/* + * @test id=Parallel + * @bug 8059527 8081382 + * @summary Tests argument processing for ParallelGCThreads with Parallel GC + * @library /test/lib + * @library / + * @requires vm.gc.Parallel + * @run driver gc.arguments.TestParallelGCThreads Parallel + */ + +/* + * @test id=G1 + * @bug 8059527 8081382 + * @summary Tests argument processing for ParallelGCThreads with G1 GC + * @library /test/lib + * @library / + * @requires vm.gc.G1 + * @run driver gc.arguments.TestParallelGCThreads G1 + */ + +/* + * @test id=MaxValue + * @bug 8059527 8081382 + * @summary Tests max value for ParallelGCThreads + * @library /test/lib + * @library / + * @requires vm.gc.Serial + * @run driver gc.arguments.TestParallelGCThreads MaxValue */ -import java.util.ArrayList; -import java.util.List; import jdk.test.lib.Asserts; import jdk.test.lib.process.OutputAnalyzer; -import jtreg.SkippedException; -import jdk.test.whitebox.gc.GC; public class TestParallelGCThreads { public static void main(String args[]) throws Exception { - testFlags(); - testDefaultValue(); + if (args.length == 0) { + throw new IllegalArgumentException("Test type must be specified as argument"); + } + + String testType = args[0]; + + switch (testType) { + case "DefaultValue": + testDefaultValue(); + break; + case "Z": + testFlags("-XX:+UseZGC"); + break; + case "Parallel": + testFlags("-XX:+UseParallelGC"); + break; + case "G1": + testFlags("-XX:+UseG1GC"); + break; + case "MaxValue": + testMaxValue(); + break; + default: + throw new IllegalArgumentException("Unknown test type \"" + testType + "\""); + } } private static final String flagName = "ParallelGCThreads"; @@ -55,8 +111,8 @@ public class TestParallelGCThreads { // uint ParallelGCThreads = 23 {product} private static final String printFlagsFinalPattern = " *uint *" + flagName + " *:?= *(\\d+) *\\{product\\} *"; - public static void testDefaultValue() throws Exception { - OutputAnalyzer output = GCArguments.executeLimitedTestJava( + private static void testDefaultValue() throws Exception { + OutputAnalyzer output = GCArguments.executeTestJava( "-XX:+UnlockExperimentalVMOptions", "-XX:+PrintFlagsFinal", "-version"); String value = output.firstMatch(printFlagsFinalPattern, 1); @@ -64,10 +120,10 @@ public class TestParallelGCThreads { try { Asserts.assertNotNull(value, "Couldn't find uint flag " + flagName); - Long longValue = new Long(value); + Long longValue = Long.valueOf(value); // Sanity check that we got a non-zero value. - Asserts.assertNotEquals(longValue, "0"); + Asserts.assertNotEquals(longValue, 0L); output.shouldHaveExitValue(0); } catch (Exception e) { @@ -76,41 +132,28 @@ public class TestParallelGCThreads { } } - public static void testFlags() throws Exception { - // For each parallel collector (G1, Parallel) - List supportedGC = new ArrayList(); + private static void testFlags(String gcFlag) throws Exception { - if (GC.G1.isSupported()) { - supportedGC.add("G1"); - } - if (GC.Parallel.isSupported()) { - supportedGC.add("Parallel"); - } + // Make sure the VM does not allow ParallelGCThreads set to 0 + OutputAnalyzer output = GCArguments.executeTestJava( + gcFlag, + "-XX:ParallelGCThreads=0", + "-XX:+PrintFlagsFinal", + "-version"); + output.shouldHaveExitValue(1); - if (supportedGC.isEmpty()) { - throw new SkippedException("Skipping test because none of G1/Parallel is supported."); - } - - for (String gc : supportedGC) { - // Make sure the VM does not allow ParallelGCThreads set to 0 - OutputAnalyzer output = GCArguments.executeLimitedTestJava( - "-XX:+Use" + gc + "GC", - "-XX:ParallelGCThreads=0", + // Do some basic testing to ensure the flag updates the count + for (long i = 1; i <= 3; i++) { + long count = getParallelGCThreadCount( + gcFlag, + "-XX:ParallelGCThreads=" + i, "-XX:+PrintFlagsFinal", "-version"); - output.shouldHaveExitValue(1); - - // Do some basic testing to ensure the flag updates the count - for (long i = 1; i <= 3; i++) { - long count = getParallelGCThreadCount( - "-XX:+Use" + gc + "GC", - "-XX:ParallelGCThreads=" + i, - "-XX:+PrintFlagsFinal", - "-version"); - Asserts.assertEQ(count, i, "Specifying ParallelGCThreads=" + i + " for " + gc + "GC does not set the thread count properly!"); - } + Asserts.assertEQ(count, i, "Specifying ParallelGCThreads=" + i + " for \"" + gcFlag + "\" does not set the thread count properly!"); } + } + private static void testMaxValue() throws Exception { // Test the max value for ParallelGCThreads // So setting ParallelGCThreads=2147483647 should give back 2147483647 long count = getParallelGCThreadCount( @@ -122,7 +165,7 @@ public class TestParallelGCThreads { } public static long getParallelGCThreadCount(String... flags) throws Exception { - OutputAnalyzer output = GCArguments.executeLimitedTestJava(flags); + OutputAnalyzer output = GCArguments.executeTestJava(flags); output.shouldHaveExitValue(0); String stdout = output.getStdout(); return FlagsValue.getFlagLongValue("ParallelGCThreads", stdout); From 9c91c68d1d5938d7e2b9a90c82b0a36ef1a063cd Mon Sep 17 00:00:00 2001 From: Kevin Walls Date: Tue, 9 Dec 2025 09:18:04 +0000 Subject: [PATCH 222/706] 8373111: Test java/lang/management/MemoryMXBean/MemoryManagement.java timed out Reviewed-by: lmesnik --- .../management/MemoryMXBean/MemoryManagement.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/test/jdk/java/lang/management/MemoryMXBean/MemoryManagement.java b/test/jdk/java/lang/management/MemoryMXBean/MemoryManagement.java index b136b724b71..f6c7446d1f3 100644 --- a/test/jdk/java/lang/management/MemoryMXBean/MemoryManagement.java +++ b/test/jdk/java/lang/management/MemoryMXBean/MemoryManagement.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, 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 @@ -49,7 +49,7 @@ * * @modules jdk.management * - * @run main/timeout=600 MemoryManagement + * @run main/othervm/timeout=600 -Xmn8m MemoryManagement */ import java.lang.management.*; @@ -58,6 +58,10 @@ import javax.management.*; import javax.management.openmbean.CompositeData; public class MemoryManagement { + + private static final int YOUNG_GEN_SIZE = 8 * 1024 * 1024; // Must match -Xmn set on the @run line + private static final int NUM_CHUNKS = 2; + private static final MemoryMXBean mm = ManagementFactory.getMemoryMXBean(); private static final List pools = Collections.synchronizedList(ManagementFactory.getMemoryPoolMXBeans()); @@ -66,9 +70,6 @@ public class MemoryManagement { private static volatile MemoryPoolMXBean mpool = null; private static volatile boolean trace = false; private static volatile boolean testFailed = false; - private static final int NUM_CHUNKS = 2; - // Must match -Xmn set on the @run line - private static final int YOUNG_GEN_SIZE = 8 * 1024 * 1024; private static volatile long chunkSize; private static volatile int listenerInvoked = 0; From 786833cd1bf8eda1cef25da392a055f4eb371abf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20Sikstr=C3=B6m?= Date: Tue, 9 Dec 2025 09:44:18 +0000 Subject: [PATCH 223/706] 8373022: serviceability/sa/ClhsdbScanOops.java assumes no GC should occur Reviewed-by: cjplummer, stefank, ayang, tschatzl --- test/hotspot/jtreg/ProblemList.txt | 3 --- test/hotspot/jtreg/serviceability/sa/ClhsdbScanOops.java | 5 ++++- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index ddc6e55dc05..48d0da048fe 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -140,9 +140,6 @@ serviceability/sa/ClhsdbPstack.java#core 8318754 macosx-aarch64 serviceability/sa/TestJmapCore.java 8318754 macosx-aarch64 serviceability/sa/TestJmapCoreMetaspace.java 8318754 macosx-aarch64 -serviceability/sa/ClhsdbScanOops.java#parallel 8373022 generic-all -serviceability/sa/ClhsdbScanOops.java#serial 8373022 generic-all - serviceability/sa/ClhsdbThreadContext.java 8356704 windows-x64 serviceability/jvmti/stress/StackTrace/NotSuspended/GetStackTraceNotSuspendedStressTest.java 8315980 linux-all,windows-x64 diff --git a/test/hotspot/jtreg/serviceability/sa/ClhsdbScanOops.java b/test/hotspot/jtreg/serviceability/sa/ClhsdbScanOops.java index b6919a566a9..ef75b08c995 100644 --- a/test/hotspot/jtreg/serviceability/sa/ClhsdbScanOops.java +++ b/test/hotspot/jtreg/serviceability/sa/ClhsdbScanOops.java @@ -60,7 +60,10 @@ public class ClhsdbScanOops { try { ClhsdbLauncher test = new ClhsdbLauncher(); - theApp = LingeredApp.startApp(gc); + // This test assumes that no GC should happen during its execution. + // Setting the initial heap size to a reasonably high number avoids + // running a GC. + theApp = LingeredApp.startApp(gc, "-XX:InitialHeapSize=100M"); System.out.println ("Started LingeredApp with the GC option " + gc + " and pid " + theApp.getPid()); From 1f49edd9783ed4579d989d6939ee75e926f0716a Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Tue, 9 Dec 2025 10:02:01 +0000 Subject: [PATCH 224/706] 4459231: Focus of JTabbedPane(with Scrollable tablayout) changes on change in LookAndFeel Reviewed-by: tr, kizune --- .../swing/plaf/basic/BasicTabbedPaneUI.java | 10 ++ .../JTabbedPane/TabbedPaneBugWithLNF.java | 110 ++++++++++++++++++ 2 files changed, 120 insertions(+) create mode 100644 test/jdk/javax/swing/JTabbedPane/TabbedPaneBugWithLNF.java diff --git a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTabbedPaneUI.java b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTabbedPaneUI.java index 59799f4d91a..842e8892c76 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTabbedPaneUI.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTabbedPaneUI.java @@ -293,6 +293,16 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants { installDefaults(); installListeners(); installKeyboardActions(); + setFocusIndex(tabPane.getSelectedIndex(), false); + + if (tabPane.getLayout() instanceof TabbedPaneScrollLayout) { + ensureCurrentLayout(); + int index = tabPane.getSelectedIndex(); + if (index < rects.length && index != -1) { + tabScroller.tabPanel.scrollRectToVisible( + (Rectangle)rects[index].clone()); + } + } } public void uninstallUI(JComponent c) { diff --git a/test/jdk/javax/swing/JTabbedPane/TabbedPaneBugWithLNF.java b/test/jdk/javax/swing/JTabbedPane/TabbedPaneBugWithLNF.java new file mode 100644 index 00000000000..cf989280da2 --- /dev/null +++ b/test/jdk/javax/swing/JTabbedPane/TabbedPaneBugWithLNF.java @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2025, 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 4459231 + * @summary Verifies if JTabbedPane(with Scrollable tablayout) changes focus + * on change in LookAndFeel + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual TabbedPaneBugWithLNF + */ + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JTabbedPane; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; + +public class TabbedPaneBugWithLNF { + + private static String LNF = "com.sun.java.swing.plaf.motif.MotifLookAndFeel"; + private static JTabbedPane tabPane; + private static JButton testBtn; + + static final String INSTRUCTIONS = """ + A JTabbedPane with 10 tabs will be shown. + Scroll the tabs till the end, i.e., to "Testing Tab9". + Select that tab. + You will see the main tab JButton's text changed to 'Test Button9'. + Click on it, which will change the lookandfeel. + Verify if child tabs have scrolled back to starting child tab + i.e., 'Testing Tab0', where as the selected tab is still 'Testing Tab9'. + If it does, press Fail + else if focus of the child Tab is still at "Testing Tab9" press Pass."""; + + public static void main(String[] args) throws Exception { + UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel"); + PassFailJFrame.builder() + .title("TabbedPaneBugWithLNF Test Instructions") + .instructions(INSTRUCTIONS) + .columns(50) + .testUI(TabbedPaneBugWithLNF::createUI) + .position(PassFailJFrame.Position.TOP_LEFT_CORNER) + .build() + .awaitAndCheck(); + } + + static JFrame createUI() { + JFrame frame = new JFrame("TabbedPaneBugWithLNF"); + frame.setSize(640, 180); + + tabPane = new JTabbedPane(JTabbedPane.BOTTOM,JTabbedPane.SCROLL_TAB_LAYOUT); + + tabPane.addTab("Testing Tab0", testBtn = new JButton("Test Button0")); + + tabPane.addTab("Testing Tab1", testBtn = new JButton("Test Button1")); + + tabPane.addTab("Testing Tab2", testBtn = new JButton("Test Button2")); + + tabPane.addTab("Testing Tab3", testBtn = new JButton("Test Button3")); + + tabPane.addTab("Testing Tab4", testBtn = new JButton("Test Button4")); + + tabPane.addTab("Testing Tab5", testBtn = new JButton("Test Button5")); + + tabPane.addTab("Testing Tab6", testBtn = new JButton("Test Button6")); + + tabPane.addTab("Testing Tab7", testBtn = new JButton("Test Button7")); + tabPane.addTab("Testing Tab8", testBtn = new JButton("Test Button8")); + JButton myBtn = null; + tabPane.addTab("Testing Tab9", myBtn = new JButton("Test Button9")); + myBtn.addActionListener( new ActionListener() { + public void actionPerformed(ActionEvent ae) { + try { + UIManager.setLookAndFeel(LNF); + SwingUtilities.updateComponentTreeUI(frame); + System.out.println("tabPane.selectedIndex " + tabPane.getSelectedIndex()); + } catch (Exception exc) { + System.out.println("Error changing L&F : " + LNF); + } + } + }); + frame.add(tabPane); + return frame; + } +} + From 0a557890a50b0dc83c70dc877027d951dcc05470 Mon Sep 17 00:00:00 2001 From: Axel Boldt-Christmas Date: Tue, 9 Dec 2025 10:04:25 +0000 Subject: [PATCH 225/706] 8373025: test/hotspot/jtreg/gc/cslocker/TestCSLocker.java may deadlock Reviewed-by: ayang, tschatzl, stefank --- test/hotspot/jtreg/ProblemList.txt | 1 - .../jtreg/gc/cslocker/TestCSLocker.java | 24 ++++------------- .../jtreg/gc/cslocker/libTestCSLocker.c | 26 +++++++++++-------- 3 files changed, 20 insertions(+), 31 deletions(-) diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index 48d0da048fe..177c14da785 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -94,7 +94,6 @@ gc/shenandoah/TestEvilSyncBug.java#generational 8345501 generic-all gc/shenandoah/TestRetainObjects.java#no-tlab 8361099 generic-all gc/shenandoah/TestSieveObjects.java#no-tlab 8361099 generic-all gc/shenandoah/TestSieveObjects.java#no-tlab-genshen 8361099 generic-all -gc/cslocker/TestCSLocker.java 8373025 generic-all ############################################################################# diff --git a/test/hotspot/jtreg/gc/cslocker/TestCSLocker.java b/test/hotspot/jtreg/gc/cslocker/TestCSLocker.java index 3550c4e5f14..82dc2fb99a1 100644 --- a/test/hotspot/jtreg/gc/cslocker/TestCSLocker.java +++ b/test/hotspot/jtreg/gc/cslocker/TestCSLocker.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2025, 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,18 +33,11 @@ import static gc.testlibrary.Allocation.blackHole; * @summary completely in JNI CS, while other is trying to allocate memory * @summary provoking GC. OOM means FAIL, deadlock means PASS. * - * @comment This test assumes that no allocation happens during the sleep loop, - * which is something that we can't guarantee. With ZGC we see test - * timeouts because the main thread allocates and waits for the GC, - * which waits for the CSLocker, which waits for the main thread. - * @requires vm.gc != "Z" - * * @run main/native/othervm -Xmx256m gc.cslocker.TestCSLocker */ public class TestCSLocker extends Thread { - static int timeoutMillis = 5000; public static void main(String args[]) throws Exception { // start garbage producer thread GarbageProducer garbageProducer = new GarbageProducer(1000000, 10); @@ -53,15 +46,9 @@ public class TestCSLocker extends Thread // start CS locker thread CSLocker csLocker = new CSLocker(); csLocker.start(); - // After the CSLocker thread has started, any operation such as an allocation, - // which could rely on the GC to make progress, will cause a deadlock that will - // make the test time out. That includes printing. Please don't use any such - // code until unlock() is called below. - // check timeout to success deadlocking - sleep(timeoutMillis); - - csLocker.unlock(); + // Wait for the csLocker thread to finish its critical section + csLocker.join(); garbageProducer.interrupt(); } } @@ -97,11 +84,10 @@ class CSLocker extends Thread public void run() { int[] a = new int[10]; a[0] = 1; - if (!lock(a)) { + if (!criticalSection(a)) { throw new RuntimeException("failed to acquire CSLock"); } } - native boolean lock(int[] array); - native void unlock(); + native boolean criticalSection(int[] array); } diff --git a/test/hotspot/jtreg/gc/cslocker/libTestCSLocker.c b/test/hotspot/jtreg/gc/cslocker/libTestCSLocker.c index ae75c631072..58779d40cb9 100644 --- a/test/hotspot/jtreg/gc/cslocker/libTestCSLocker.c +++ b/test/hotspot/jtreg/gc/cslocker/libTestCSLocker.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2025, 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 @@ -23,9 +23,15 @@ #include +#ifdef WINDOWS +#include +#else +#include +#endif + static volatile int release_critical = 0; -JNIEXPORT jboolean JNICALL Java_gc_cslocker_CSLocker_lock +JNIEXPORT jboolean JNICALL Java_gc_cslocker_CSLocker_criticalSection (JNIEnv *env, jobject obj, jintArray array) { jboolean retval = JNI_TRUE; @@ -33,17 +39,15 @@ JNIEXPORT jboolean JNICALL Java_gc_cslocker_CSLocker_lock if (nativeArray == NULL) { retval = JNI_FALSE; + } else { + // Wait for 5 seconds +#ifdef WINDOWS + Sleep(5000); +#else + sleep(5); +#endif } - // deadblock - while (!release_critical) /* empty */; - (*env)->ReleasePrimitiveArrayCritical(env, array, nativeArray, 0); return retval; } - -JNIEXPORT void JNICALL Java_gc_cslocker_CSLocker_unlock - (JNIEnv *env, jobject obj) -{ - release_critical = 1; -} From 830c4d3b198597b6af7a21b708bd3a852af200d4 Mon Sep 17 00:00:00 2001 From: Anton Artemov Date: Tue, 9 Dec 2025 10:15:04 +0000 Subject: [PATCH 226/706] 8366272: The os::xxx APIs do not manage errno correctly Reviewed-by: dholmes --- src/hotspot/os/aix/os_aix.cpp | 2 +- src/hotspot/os/bsd/os_bsd.cpp | 2 +- src/hotspot/os/linux/os_linux.cpp | 2 +- src/hotspot/os/posix/os_posix.cpp | 1 + src/hotspot/os/posix/signals_posix.cpp | 3 +-- src/hotspot/os/windows/os_windows.cpp | 11 ++++++----- 6 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/hotspot/os/aix/os_aix.cpp b/src/hotspot/os/aix/os_aix.cpp index 7de031cac58..f88729cdc66 100644 --- a/src/hotspot/os/aix/os_aix.cpp +++ b/src/hotspot/os/aix/os_aix.cpp @@ -2333,8 +2333,8 @@ int os::open(const char *path, int oflag, int mode) { if (ret != -1) { if ((st_mode & S_IFMT) == S_IFDIR) { - errno = EISDIR; ::close(fd); + errno = EISDIR; return -1; } } else { diff --git a/src/hotspot/os/bsd/os_bsd.cpp b/src/hotspot/os/bsd/os_bsd.cpp index 0889cc4cdf8..dc8f5187b5a 100644 --- a/src/hotspot/os/bsd/os_bsd.cpp +++ b/src/hotspot/os/bsd/os_bsd.cpp @@ -2277,8 +2277,8 @@ int os::open(const char *path, int oflag, int mode) { if (ret != -1) { if ((st_mode & S_IFMT) == S_IFDIR) { - errno = EISDIR; ::close(fd); + errno = EISDIR; return -1; } } else { diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index 880dbeccf7d..ba05fde7f12 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -4932,8 +4932,8 @@ int os::open(const char *path, int oflag, int mode) { if (ret != -1) { if ((st_mode & S_IFMT) == S_IFDIR) { - errno = EISDIR; ::close(fd); + errno = EISDIR; return -1; } } else { diff --git a/src/hotspot/os/posix/os_posix.cpp b/src/hotspot/os/posix/os_posix.cpp index 8f1f07dd055..ef52b946cc6 100644 --- a/src/hotspot/os/posix/os_posix.cpp +++ b/src/hotspot/os/posix/os_posix.cpp @@ -1028,6 +1028,7 @@ char* os::realpath(const char* filename, char* outbuf, size_t outbuflen) { } else { errno = ENAMETOOLONG; } + ErrnoPreserver ep; permit_forbidden_function::free(p); // *not* os::free } else { // Fallback for platforms struggling with modern Posix standards (AIX 5.3, 6.1). If realpath diff --git a/src/hotspot/os/posix/signals_posix.cpp b/src/hotspot/os/posix/signals_posix.cpp index 625eb63445a..a989b40d49d 100644 --- a/src/hotspot/os/posix/signals_posix.cpp +++ b/src/hotspot/os/posix/signals_posix.cpp @@ -1645,7 +1645,7 @@ static void SR_handler(int sig, siginfo_t* siginfo, void* context) { // Save and restore errno to avoid confusing native code with EINTR // after sigsuspend. - int old_errno = errno; + ErrnoPreserver ep; PosixSignals::unblock_error_signals(); @@ -1727,7 +1727,6 @@ static void SR_handler(int sig, siginfo_t* siginfo, void* context) { // ignore } - errno = old_errno; } static int SR_initialize() { diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp index b9aeb4e8dd6..0ac05e8a435 100644 --- a/src/hotspot/os/windows/os_windows.cpp +++ b/src/hotspot/os/windows/os_windows.cpp @@ -4782,8 +4782,8 @@ int os::stat(const char *path, struct stat *sbuf) { path_to_target = get_path_to_target(wide_path); if (path_to_target == nullptr) { // it is a symbolic link, but we failed to resolve it - errno = ENOENT; os::free(wide_path); + errno = ENOENT; return -1; } } @@ -4794,14 +4794,14 @@ int os::stat(const char *path, struct stat *sbuf) { // if getting attributes failed, GetLastError should be called immediately after that if (!bret) { DWORD errcode = ::GetLastError(); + log_debug(os)("os::stat() failed to GetFileAttributesExW: GetLastError->%lu.", errcode); + os::free(wide_path); + os::free(path_to_target); if (errcode == ERROR_FILE_NOT_FOUND || errcode == ERROR_PATH_NOT_FOUND) { errno = ENOENT; } else { errno = 0; } - log_debug(os)("os::stat() failed to GetFileAttributesExW: GetLastError->%lu.", errcode); - os::free(wide_path); - os::free(path_to_target); return -1; } @@ -5000,8 +5000,8 @@ int os::open(const char *path, int oflag, int mode) { path_to_target = get_path_to_target(wide_path); if (path_to_target == nullptr) { // it is a symbolic link, but we failed to resolve it - errno = ENOENT; os::free(wide_path); + errno = ENOENT; return -1; } } @@ -5275,6 +5275,7 @@ char* os::realpath(const char* filename, char* outbuf, size_t outbuflen) { } else { errno = ENAMETOOLONG; } + ErrnoPreserver ep; permit_forbidden_function::free(p); // *not* os::free } return result; From a4eb57c5ec6254e59e486042015dd00457284ef2 Mon Sep 17 00:00:00 2001 From: Emanuel Peter Date: Tue, 9 Dec 2025 12:45:36 +0000 Subject: [PATCH 227/706] 8367028: compiler/c2/irTests/TestFloat16ScalarOperations.java failing intermittently because of constant folding Reviewed-by: chagedorn, syan, rcastanedalo --- .../irTests/TestFloat16ScalarOperations.java | 25 +++++++++++++------ 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestFloat16ScalarOperations.java b/test/hotspot/jtreg/compiler/c2/irTests/TestFloat16ScalarOperations.java index c8ee5e730fa..445fef5e55a 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/TestFloat16ScalarOperations.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestFloat16ScalarOperations.java @@ -68,6 +68,15 @@ public class TestFloat16ScalarOperations { private static final Float16 RANDOM4 = Float16.valueOf(genF.next()); private static final Float16 RANDOM5 = Float16.valueOf(genF.next()); + // We have to ensure that the constants are not special values that lead the operations to + // constant fold. For example "x + 0" could constant fold to "x", so we need to avoid that + // the add constant is zero. + private static Generator genSmallRangeF = G.uniformFloats(0.1f, 0.9f); + private static final Float16 RANDOM_CON_ADD = Float16.valueOf(genSmallRangeF.next()); + private static final Float16 RANDOM_CON_SUB = Float16.valueOf(genSmallRangeF.next()); + private static final Float16 RANDOM_CON_MUL = Float16.valueOf(genSmallRangeF.next()); + private static final Float16 RANDOM_CON_DIV = Float16.valueOf(genSmallRangeF.next()); + private static Float16 RANDOM1_VAR = RANDOM1; private static Float16 RANDOM2_VAR = RANDOM2; private static Float16 RANDOM3_VAR = RANDOM3; @@ -435,10 +444,10 @@ public class TestFloat16ScalarOperations { @Warmup(10000) public short testRandomFP16ConstantPatternSet1() { short res = 0; - res += Float.floatToFloat16(RANDOM1_VAR.floatValue() + RANDOM2.floatValue()); - res += Float.floatToFloat16(RANDOM2_VAR.floatValue() - RANDOM3.floatValue()); - res += Float.floatToFloat16(RANDOM3_VAR.floatValue() * RANDOM4.floatValue()); - res += Float.floatToFloat16(RANDOM4_VAR.floatValue() / RANDOM5.floatValue()); + res += Float.floatToFloat16(RANDOM1_VAR.floatValue() + RANDOM_CON_ADD.floatValue()); + res += Float.floatToFloat16(RANDOM2_VAR.floatValue() - RANDOM_CON_SUB.floatValue()); + res += Float.floatToFloat16(RANDOM3_VAR.floatValue() * RANDOM_CON_MUL.floatValue()); + res += Float.floatToFloat16(RANDOM4_VAR.floatValue() / RANDOM_CON_DIV.floatValue()); return res; } @@ -456,10 +465,10 @@ public class TestFloat16ScalarOperations { @Warmup(10000) public short testRandomFP16ConstantPatternSet2() { short res = 0; - res += Float.floatToFloat16(RANDOM2.floatValue() + RANDOM1_VAR.floatValue()); - res += Float.floatToFloat16(RANDOM3.floatValue() - RANDOM2_VAR.floatValue()); - res += Float.floatToFloat16(RANDOM4.floatValue() * RANDOM3_VAR.floatValue()); - res += Float.floatToFloat16(RANDOM5.floatValue() / RANDOM4_VAR.floatValue()); + res += Float.floatToFloat16(RANDOM_CON_ADD.floatValue() + RANDOM1_VAR.floatValue()); + res += Float.floatToFloat16(RANDOM_CON_SUB.floatValue() - RANDOM2_VAR.floatValue()); + res += Float.floatToFloat16(RANDOM_CON_MUL.floatValue() * RANDOM3_VAR.floatValue()); + res += Float.floatToFloat16(RANDOM_CON_DIV.floatValue() / RANDOM4_VAR.floatValue()); return res; } From 8c8d21db6f5bdc35f6eddf91065b4eec462a716f Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Tue, 9 Dec 2025 16:10:13 +0000 Subject: [PATCH 228/706] 8373295: Wrong log tag for UseCompressedOops ergo setting Reviewed-by: dholmes, ysuenaga --- src/hotspot/share/runtime/arguments.cpp | 8 +- .../appcds/sharedStrings/SysDictCrash.java | 84 ------------------- 2 files changed, 4 insertions(+), 88 deletions(-) delete mode 100644 test/hotspot/jtreg/runtime/cds/appcds/sharedStrings/SysDictCrash.java diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index 4a983095593..dab3a60c650 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -1604,10 +1604,10 @@ void Arguments::set_heap_size() { // and UseCompressedOops was not specified. if (reasonable_max > max_coop_heap) { if (FLAG_IS_ERGO(UseCompressedOops) && has_ram_limit) { - aot_log_info(aot)("UseCompressedOops disabled due to " - "max heap %zu > compressed oop heap %zu. " - "Please check the setting of MaxRAMPercentage %5.2f.", - reasonable_max, (size_t)max_coop_heap, MaxRAMPercentage); + log_debug(gc, heap, coops)("UseCompressedOops disabled due to " + "max heap %zu > compressed oop heap %zu. " + "Please check the setting of MaxRAMPercentage %5.2f.", + reasonable_max, (size_t)max_coop_heap, MaxRAMPercentage); FLAG_SET_ERGO(UseCompressedOops, false); } else { reasonable_max = max_coop_heap; diff --git a/test/hotspot/jtreg/runtime/cds/appcds/sharedStrings/SysDictCrash.java b/test/hotspot/jtreg/runtime/cds/appcds/sharedStrings/SysDictCrash.java deleted file mode 100644 index 9462f4f9d0b..00000000000 --- a/test/hotspot/jtreg/runtime/cds/appcds/sharedStrings/SysDictCrash.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (c) 2015, 2025, 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 - * @summary Regression test for JDK-8098821 - * @bug 8098821 - * @requires vm.cds.write.archived.java.heap - * @requires vm.gc == null - * @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds - * @run driver SysDictCrash - */ - -import jdk.test.lib.cds.CDSOptions; -import jdk.test.lib.cds.CDSTestUtils; -import jdk.test.lib.process.OutputAnalyzer; - -public class SysDictCrash { - public static void main(String[] args) throws Exception { - SharedStringsUtils.run(args, SysDictCrash::test); - } - - public static void test(String[] args) throws Exception { - String vmOptionsPrefix[] = SharedStringsUtils.getChildVMOptionsPrefix(); - - // SharedBaseAddress=0 puts the archive at a very high address, which provokes the crash. - boolean continueTest = true; - - CDSOptions opts = (new CDSOptions()) - .addPrefix(vmOptionsPrefix, - "-XX:+UseG1GC", "-XX:MaxRAMPercentage=12.5", - "-cp", ".", - "-XX:SharedBaseAddress=0", - "-showversion", "-Xlog:cds,aot+hashtables") - .setArchiveName("./SysDictCrash.jsa"); - OutputAnalyzer output = CDSTestUtils.createArchive(opts); - try { - TestCommon.checkDump(output); - } catch (java.lang.RuntimeException re) { - if (!output.getStdout().contains("UseCompressedOops disabled due to")) { - throw re; - } else { - System.out.println("Shared archive was not created due to UseCompressedOops and UseCompressedClassPointers have been disabled."); - continueTest = false; - } - } - - if (!continueTest) { - return; - } - - opts = (new CDSOptions()) - .setArchiveName("./SysDictCrash.jsa") // prevents the assignment of a default archive name - .setUseVersion(false) // the -version must be the last arg for this test to work - .addSuffix(vmOptionsPrefix, - "-Xlog:cds", - "-XX:+UseG1GC", "-XX:MaxRAMPercentage=12.5", - "-XX:SharedArchiveFile=./SysDictCrash.jsa", - "-version"); - CDSTestUtils.run(opts) - .assertNormalExit(); - } -} From 831fe94c75c407b2399be9b89630d8d117c2996c Mon Sep 17 00:00:00 2001 From: Erik Joelsson Date: Tue, 9 Dec 2025 17:01:08 +0000 Subject: [PATCH 229/706] 8373255: Unexpected iobj and ipdb files after JDK-8370438 Reviewed-by: serb --- make/common/native/Flags.gmk | 3 +++ 1 file changed, 3 insertions(+) diff --git a/make/common/native/Flags.gmk b/make/common/native/Flags.gmk index efb4c08e74c..6353b490654 100644 --- a/make/common/native/Flags.gmk +++ b/make/common/native/Flags.gmk @@ -234,6 +234,9 @@ define SetupLinkerFlags ifeq ($(call isTargetOs, macosx), true) $1_EXTRA_LDFLAGS += -Wl,-object_path_lto,$$($1_OBJECT_DIR)/$$($1_NAME)_lto_helper.o endif + ifeq ($(TOOLCHAIN_TYPE), microsoft) + $1_EXTRA_LDFLAGS += -LTCGOUT:$$($1_OBJECT_DIR)/$$($1_NAME).iobj + endif endif $1_EXTRA_LDFLAGS += $$($1_LDFLAGS_$(OPENJDK_TARGET_OS_TYPE)) $$($1_LDFLAGS_$(OPENJDK_TARGET_OS)) \ From b99be505a5e3c8304be62a8b373d746fc52e8f0e Mon Sep 17 00:00:00 2001 From: Neha Joshi Date: Tue, 9 Dec 2025 18:06:39 +0000 Subject: [PATCH 230/706] 8368524: Tests are skipped and shown as passed in test/jdk/sun/security/pkcs11/Cipher/KeyWrap Reviewed-by: myankelevich, rhalade --- .../pkcs11/Cipher/KeyWrap/NISTWrapKAT.java | 18 ++++++++++-------- .../pkcs11/Cipher/KeyWrap/TestGeneral.java | 1 + 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/test/jdk/sun/security/pkcs11/Cipher/KeyWrap/NISTWrapKAT.java b/test/jdk/sun/security/pkcs11/Cipher/KeyWrap/NISTWrapKAT.java index e8f637e0b0c..b570a0dd030 100644 --- a/test/jdk/sun/security/pkcs11/Cipher/KeyWrap/NISTWrapKAT.java +++ b/test/jdk/sun/security/pkcs11/Cipher/KeyWrap/NISTWrapKAT.java @@ -83,7 +83,7 @@ public class NISTWrapKAT extends PKCS11Test { private static String KEK2 = "5840DF6E29B02AF1AB493B705BF16EA1AE8338F4DCC176A8"; - private static final List skippedList = new ArrayList <>(); + private static final List skippedAlgoList = new ArrayList <>(); private static byte[] toBytes(String hex, int hexLen) { if (hexLen < hex.length()) { @@ -274,8 +274,8 @@ public class NISTWrapKAT extends PKCS11Test { dataLen + "-byte key with " + 8*keyLen + "-bit KEK"); int allowed = Cipher.getMaxAllowedKeyLength("AES"); if (keyLen > allowed) { - System.out.println("=> skip, exceeds max allowed size " + allowed); - skippedList.add(algo + " Cipher with wrapping " + + System.err.println("Skip, exceeds max allowed size " + allowed); + skippedAlgoList.add(algo + " Cipher with wrapping " + dataLen + "-byte key with " + 8 * keyLen + "-bit KEK exceeds max allowed size " + allowed); return; @@ -344,8 +344,8 @@ public class NISTWrapKAT extends PKCS11Test { dataLen + "-byte data with " + 8*keyLen + "-bit KEK"); int allowed = Cipher.getMaxAllowedKeyLength("AES"); if (keyLen > allowed) { - System.out.println("=> skip, exceeds max allowed size " + allowed); - skippedList.add(algo + " Cipher with enc " + + System.err.println("Skip, exceeds max allowed size " + allowed); + skippedAlgoList.add(algo + " Cipher with enc " + dataLen + "-byte data with " + 8 * keyLen + "-bit KEK exceeds max allowed size " + allowed); return; @@ -416,7 +416,9 @@ public class NISTWrapKAT extends PKCS11Test { for (Object[] td : testDatum) { String algo = (String) td[0]; if (p.getService("Cipher", algo) == null) { - skippedList.add("No support for " + algo); + System.err.println("Skip, due to no support: " + algo); + skippedAlgoList.add("No support for " + algo); + continue; } testKeyWrap(algo, (String) td[1], (int) td[2], (String) td[3], (int) td[4], (String) td[5], p); @@ -424,9 +426,9 @@ public class NISTWrapKAT extends PKCS11Test { (int) td[4], (String) td[5], p); } - if (!skippedList.isEmpty()) { + if (!skippedAlgoList.isEmpty()) { throw new SkippedException("One or more tests skipped " - + skippedList); + + skippedAlgoList); } else { System.out.println("All Tests Passed"); } diff --git a/test/jdk/sun/security/pkcs11/Cipher/KeyWrap/TestGeneral.java b/test/jdk/sun/security/pkcs11/Cipher/KeyWrap/TestGeneral.java index f5e4494fc59..d7cdfc6c04c 100644 --- a/test/jdk/sun/security/pkcs11/Cipher/KeyWrap/TestGeneral.java +++ b/test/jdk/sun/security/pkcs11/Cipher/KeyWrap/TestGeneral.java @@ -273,6 +273,7 @@ public class TestGeneral extends PKCS11Test { for (String a : algos) { if (p.getService("Cipher", a) == null) { skippedList.add(a); + continue; } System.out.println("Testing " + a); From b2daf9de3097de4d3b3c7d565e29a48b4aae19ee Mon Sep 17 00:00:00 2001 From: Naoto Sato Date: Tue, 9 Dec 2025 18:21:12 +0000 Subject: [PATCH 231/706] 8355522: Remove the `java.locale.useOldISOCodes` system property Reviewed-by: jlu, joehw --- .../share/classes/java/util/Locale.java | 38 ++++------------ .../jdk/internal/util/StaticProperty.java | 9 ---- .../classes/sun/util/locale/BaseLocale.java | 24 +++++----- .../util/locale/provider/LocaleResources.java | 11 ----- test/jdk/java/util/Locale/LocaleTest.java | 45 ++++++------------- .../java/util/Locale/UseOldISOCodesTest.java | 15 +++---- 6 files changed, 38 insertions(+), 104 deletions(-) diff --git a/src/java.base/share/classes/java/util/Locale.java b/src/java.base/share/classes/java/util/Locale.java index 54863d58782..f45a52c14fa 100644 --- a/src/java.base/share/classes/java/util/Locale.java +++ b/src/java.base/share/classes/java/util/Locale.java @@ -535,34 +535,13 @@ import sun.util.locale.provider.TimeZoneNameUtility; * *

      Legacy language codes

      * - *

      Locale's constructors have always converted three language codes to - * their earlier, obsoleted forms: {@code he} maps to {@code iw}, - * {@code yi} maps to {@code ji}, and {@code id} maps to - * {@code in}. Since Java SE 17, this is no longer the case. Each - * language maps to its new form; {@code iw} maps to {@code he}, {@code ji} - * maps to {@code yi}, and {@code in} maps to {@code id}. - * - *

      For backwards compatible behavior, the system property - * {@systemProperty java.locale.useOldISOCodes} reverts the behavior - * back to that of before Java SE 17. If the system property is set to - * {@code true}, those three current language codes are mapped to their - * backward compatible forms. The property is only read at Java runtime - * startup and subsequent calls to {@code System.setProperty()} will - * have no effect. As of Java SE 25, the use of the - * {@code java.locale.useOldISOCodes} system property is deprecated. - * This backwards compatible behavior will be removed in a future release - * of the JDK. - * - *

      The APIs added in Java SE 7 map between the old and new language codes, - * maintaining the mapped codes internal to Locale (so that - * {@code getLanguage} and {@code toString} reflect the mapped - * code, which depends on the {@code java.locale.useOldISOCodes} system - * property), but using the new codes in the BCP 47 language tag APIs (so - * that {@code toLanguageTag} reflects the new one). This - * preserves the equivalence between Locales no matter which code or - * API is used to construct them. Java's default resource bundle - * lookup mechanism also implements this mapping, so that resources - * can be named using either convention, see {@link ResourceBundle.Control}. + *

      For compatibility, a {@code Locale} created with one of the + * three obsolete language codes, {@code iw}, {@code ji}, or {@code in}, + * will map the language to its modern equivalent, {@code he}, {@code yi}, + * or {@code id}, respectively. + *

      The default resource bundle lookup mechanism also implements + * this mapping, so that resources can be named using either convention, + * see {@link ResourceBundle.Control}. * * @spec https://www.rfc-editor.org/info/rfc4647 * RFC 4647: Matching of Language Tags @@ -2527,8 +2506,7 @@ public final class Locale implements Cloneable, Serializable { private static String convertOldISOCodes(String language) { // we accept both the old and the new ISO codes for the languages whose ISO - // codes have changed, but we always store the NEW code, unless the property - // java.locale.useOldISOCodes is set to "true" + // codes have changed, but we always store the NEW code return BaseLocale.convertOldISOCodes(LocaleUtils.toLowerString(language).intern()); } diff --git a/src/java.base/share/classes/jdk/internal/util/StaticProperty.java b/src/java.base/share/classes/jdk/internal/util/StaticProperty.java index 4fb3ae7a184..4740062dcde 100644 --- a/src/java.base/share/classes/jdk/internal/util/StaticProperty.java +++ b/src/java.base/share/classes/jdk/internal/util/StaticProperty.java @@ -53,7 +53,6 @@ public final class StaticProperty { private static final String STDOUT_ENCODING; private static final String SUN_JNU_ENCODING; private static final String JAVA_PROPERTIES_DATE; - private static final String JAVA_LOCALE_USE_OLD_ISO_CODES; private static final String OS_NAME; private static final String OS_ARCH; private static final String OS_VERSION; @@ -94,7 +93,6 @@ public final class StaticProperty { STDOUT_ENCODING = getProperty(props, "stdout.encoding"); SUN_JNU_ENCODING = getProperty(props, "sun.jnu.encoding"); JAVA_PROPERTIES_DATE = getProperty(props, "java.properties.date", null); - JAVA_LOCALE_USE_OLD_ISO_CODES = getProperty(props, "java.locale.useOldISOCodes", ""); OS_NAME = getProperty(props, "os.name"); OS_ARCH = getProperty(props, "os.arch"); OS_VERSION = getProperty(props, "os.version"); @@ -258,13 +256,6 @@ public final class StaticProperty { return JAVA_PROPERTIES_DATE; } - /** - * {@return the {@code java.locale.useOldISOCodes} system property} - */ - public static String javaLocaleUseOldISOCodes() { - return JAVA_LOCALE_USE_OLD_ISO_CODES; - } - /** * {@return the {@code os.name} system property} */ diff --git a/src/java.base/share/classes/sun/util/locale/BaseLocale.java b/src/java.base/share/classes/sun/util/locale/BaseLocale.java index 91efc61d1bf..58ec6d76aa5 100644 --- a/src/java.base/share/classes/sun/util/locale/BaseLocale.java +++ b/src/java.base/share/classes/sun/util/locale/BaseLocale.java @@ -34,7 +34,6 @@ package sun.util.locale; import jdk.internal.misc.CDS; import jdk.internal.util.ReferencedKeySet; -import jdk.internal.util.StaticProperty; import jdk.internal.vm.annotation.Stable; import java.util.StringJoiner; @@ -110,16 +109,14 @@ public final class BaseLocale { private @Stable int hash; /** - * Boolean for the old ISO language code compatibility. - * The system property "java.locale.useOldISOCodes" is not security sensitive, - * so no need to ensure privileged access here. + * Emit the warning message if the system property "java.locale.useOldISOCodes" is + * specified. */ - private static final boolean OLD_ISO_CODES = StaticProperty.javaLocaleUseOldISOCodes() - .equalsIgnoreCase("true"); static { - if (OLD_ISO_CODES) { - System.err.println("WARNING: The use of the system property \"java.locale.useOldISOCodes\"" + - " is deprecated. It will be removed in a future release of the JDK."); + if (System.getProperty("java.locale.useOldISOCodes") != null) { + System.err.println("WARNING: The system property" + + " \"java.locale.useOldISOCodes\" is no longer supported." + + " Any specified value will be ignored."); } } @@ -166,7 +163,8 @@ public final class BaseLocale { } } - // JDK uses deprecated ISO639.1 language codes for he, yi and id + // Normalize deprecated ISO 639-1 language codes for Hebrew, Yiddish, + // and Indonesian to their current standard forms. if (!language.isEmpty()) { language = convertOldISOCodes(language); } @@ -183,9 +181,9 @@ public final class BaseLocale { public static String convertOldISOCodes(String language) { return switch (language) { - case "he", "iw" -> OLD_ISO_CODES ? "iw" : "he"; - case "id", "in" -> OLD_ISO_CODES ? "in" : "id"; - case "yi", "ji" -> OLD_ISO_CODES ? "ji" : "yi"; + case "iw" -> "he"; + case "in" -> "id"; + case "ji" -> "yi"; default -> language; }; } diff --git a/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java b/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java index c539f57141e..ac43b22a3bd 100644 --- a/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java +++ b/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java @@ -62,7 +62,6 @@ import java.util.concurrent.ConcurrentMap; import java.util.regex.Pattern; import java.util.stream.Stream; -import jdk.internal.util.StaticProperty; import sun.util.resources.LocaleData; import sun.util.resources.OpenListResourceBundle; import sun.util.resources.TimeZoneNamesBundle; @@ -288,16 +287,6 @@ public class LocaleResources { } public String getLocaleName(String key) { - // Get names for old ISO codes with new ISO code resources - if (StaticProperty.javaLocaleUseOldISOCodes().equalsIgnoreCase("true")) { - key = switch (key) { - case "iw" -> "he"; - case "in" -> "id"; - case "ji" -> "yi"; - default -> key; - }; - } - Object localeName = null; String cacheKey = LOCALE_NAMES + key; diff --git a/test/jdk/java/util/Locale/LocaleTest.java b/test/jdk/java/util/Locale/LocaleTest.java index 0cf272f20a0..76fbb83c11a 100644 --- a/test/jdk/java/util/Locale/LocaleTest.java +++ b/test/jdk/java/util/Locale/LocaleTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2025, 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,7 @@ * 4118587 4118595 4122371 4126371 4126880 4135316 4135752 4139504 4139940 4143951 * 4147315 4147317 4147552 4335196 4778440 4940539 5010672 6475525 6544471 6627549 * 6786276 7066203 7085757 8008577 8030696 8170840 8174269 8255086 8263202 8287868 - * 8337603 + * 8337603 8355522 * @summary test Locales * @modules jdk.localedata * @run junit LocaleTest @@ -703,40 +703,21 @@ test commented out pending API-change approval @Test public void TestChangedISO639Codes() { Locale hebrewOld = Locale.of("iw", "IL"); - Locale hebrewNew = Locale.of("he", "IL"); Locale yiddishOld = Locale.of("ji", "IL"); - Locale yiddishNew = Locale.of("yi", "IL"); Locale indonesianOld = Locale.of("in"); - Locale indonesianNew = Locale.of("id"); - if ("true".equalsIgnoreCase(System.getProperty("java.locale.useOldISOCodes"))) { - if (!hebrewNew.getLanguage().equals("iw")) { - fail("Got back wrong language code for new Hebrew: expected \"iw\", got \"" - + hebrewNew.getLanguage() + "\""); - } - if (!yiddishNew.getLanguage().equals("ji")) { - fail("Got back wrong language code for new Yiddish: expected \"ji\", got \"" - + yiddishNew.getLanguage() + "\""); - } - if (!indonesianNew.getLanguage().equals("in")) { - fail("Got back wrong language code for new Indonesian: expected \"in\", got \"" - + indonesianNew.getLanguage() + "\""); - } - } else { - if (!hebrewOld.getLanguage().equals("he")) { - fail("Got back wrong language code for old Hebrew: expected \"he\", got \"" - + hebrewNew.getLanguage() + "\""); - } - if (!yiddishOld.getLanguage().equals("yi")) { - fail("Got back wrong language code for old Yiddish: expected \"yi\", got \"" - + yiddishNew.getLanguage() + "\""); - } - if (!indonesianOld.getLanguage().equals("id")) { - fail("Got back wrong language code for old Indonesian: expected \"id\", got \"" - + indonesianNew.getLanguage() + "\""); - } + if (!hebrewOld.getLanguage().equals("he")) { + fail("Got back wrong language code for old Hebrew: expected \"he\", got \"" + + hebrewOld.getLanguage() + "\""); + } + if (!yiddishOld.getLanguage().equals("yi")) { + fail("Got back wrong language code for old Yiddish: expected \"yi\", got \"" + + yiddishOld.getLanguage() + "\""); + } + if (!indonesianOld.getLanguage().equals("id")) { + fail("Got back wrong language code for old Indonesian: expected \"id\", got \"" + + indonesianOld.getLanguage() + "\""); } - } /** diff --git a/test/jdk/java/util/Locale/UseOldISOCodesTest.java b/test/jdk/java/util/Locale/UseOldISOCodesTest.java index 1909497535c..3e836782fc3 100644 --- a/test/jdk/java/util/Locale/UseOldISOCodesTest.java +++ b/test/jdk/java/util/Locale/UseOldISOCodesTest.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8295232 8353118 + * @bug 8295232 8353118 8355522 * @summary Tests for the "java.locale.useOldISOCodes" system property * @library /test/lib * @run junit UseOldISOCodesTest @@ -34,7 +34,7 @@ import jdk.test.lib.process.ProcessTools; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; public class UseOldISOCodesTest { @@ -44,7 +44,7 @@ public class UseOldISOCodesTest { .outputTo(System.out) .errorTo(System.err); oa.shouldHaveExitValue(0); - oa.stderrShouldMatch("WARNING: The use of the system property \"java.locale.useOldISOCodes\" is deprecated. It will be removed in a future release of the JDK."); + oa.stderrShouldMatch("WARNING: The system property \"java.locale.useOldISOCodes\" is no longer supported. Any specified value will be ignored."); } static class Runner { @@ -52,12 +52,9 @@ public class UseOldISOCodesTest { private static final String newCode = "he"; public static void main(String[] args) { - // Ensure java.locale.useOldISOCodes is only interpreted at runtime startup - // Should have no effect - System.setProperty("java.locale.useOldISOCodes", "false"); - Locale locale = Locale.of(newCode); - assertEquals(obsoleteCode, locale.getLanguage(), - "newCode 'he' was not mapped to 'iw' with useOldISOCodes=true"); + // Ensure java.locale.useOldISOCodes should have no effect + assertNotEquals(obsoleteCode, Locale.of(newCode).getLanguage(), + "newCode 'he' was mapped to 'iw' with useOldISOCodes=true"); } } } From 1ae4a6c43ea21d4b147bcfcfaf1484c6e618dce5 Mon Sep 17 00:00:00 2001 From: Matthew Donovan Date: Tue, 9 Dec 2025 18:48:33 +0000 Subject: [PATCH 232/706] 8373101: JdkClient and JdkServer test classes ignore namedGroups field Reviewed-by: rhalade --- .../javax/net/ssl/TLSCommon/interop/JdkClient.java | 13 ++++++++++++- .../javax/net/ssl/TLSCommon/interop/JdkServer.java | 14 ++++++++++++-- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/test/jdk/javax/net/ssl/TLSCommon/interop/JdkClient.java b/test/jdk/javax/net/ssl/TLSCommon/interop/JdkClient.java index 79476cbb81e..eb6ecbb12b8 100644 --- a/test/jdk/javax/net/ssl/TLSCommon/interop/JdkClient.java +++ b/test/jdk/javax/net/ssl/TLSCommon/interop/JdkClient.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, 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,7 @@ import java.io.IOException; import java.net.InetSocketAddress; import java.net.SocketException; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import javax.net.ssl.SNIHostName; @@ -86,6 +87,16 @@ public class JdkClient extends AbstractClient { if (builder.getAppProtocols() != null) { sslParams.setApplicationProtocols(builder.getAppProtocols()); } + + NamedGroup[] namedGroups = builder.getNamedGroups(); + if (namedGroups != null + && namedGroups.length > 0) { + String[] namedGroupStrs = Arrays.stream(namedGroups) + .map(NamedGroup::name) + .toArray(String[]::new); + sslParams.setNamedGroups(namedGroupStrs); + } + socket.setSSLParameters(sslParams); } diff --git a/test/jdk/javax/net/ssl/TLSCommon/interop/JdkServer.java b/test/jdk/javax/net/ssl/TLSCommon/interop/JdkServer.java index 1521325b65a..20bfffbac7d 100644 --- a/test/jdk/javax/net/ssl/TLSCommon/interop/JdkServer.java +++ b/test/jdk/javax/net/ssl/TLSCommon/interop/JdkServer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, 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,9 +22,9 @@ */ import java.io.IOException; -import java.net.InetAddress; import java.net.SocketException; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import javax.net.ssl.SNIHostName; @@ -85,6 +85,16 @@ public class JdkServer extends AbstractServer { System.out.println("appProtocol: " + appProtocol); } } + + NamedGroup[] namedGroups = builder.getNamedGroups(); + if (namedGroups != null + && namedGroups.length > 0) { + String[] namedGroupStrs = Arrays.stream(namedGroups) + .map(NamedGroup::name) + .toArray(String[]::new); + sslParams.setNamedGroups(namedGroupStrs); + } + serverSocket.setSSLParameters(sslParams); } From 7f9951a93479ac0ddd74375fdef92095fb65741b Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Wed, 10 Dec 2025 00:07:28 +0000 Subject: [PATCH 233/706] 8373207: Make DeferredStatic class template constant initializable Reviewed-by: jsjolen, stefank, iwalulya --- src/hotspot/share/utilities/deferredStatic.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/utilities/deferredStatic.hpp b/src/hotspot/share/utilities/deferredStatic.hpp index 3a32f920fe8..a37b169803a 100644 --- a/src/hotspot/share/utilities/deferredStatic.hpp +++ b/src/hotspot/share/utilities/deferredStatic.hpp @@ -35,7 +35,7 @@ // object must be explicitly initialized before use. This avoids problems // resulting from the unspecified initialization time and ordering between // different objects that comes from using undeferred objects (the so-called -// "Static Initialization Order Fiasco). +// "Static Initialization Order Fiasco"). // // Once initialized, the object is never destroyed. This avoids similar issues // with the timing and ordering of destruction on normal program exit. @@ -53,7 +53,7 @@ class DeferredStatic { public: NONCOPYABLE(DeferredStatic); - DeferredStatic() + constexpr DeferredStatic() DEBUG_ONLY(: _initialized(false)) { // Do not construct value, on purpose. } From eef9813ad42b02db5fc636e661a751d5120a639e Mon Sep 17 00:00:00 2001 From: Xueming Shen Date: Wed, 10 Dec 2025 00:50:48 +0000 Subject: [PATCH 234/706] 8371446: VectorAPI: Add unit tests for masks from various long values Reviewed-by: psandoz --- .../incubator/vector/AbstractVectorTest.java | 53 +-- .../incubator/vector/Byte128VectorTests.java | 340 +++++++++++------- .../incubator/vector/Byte256VectorTests.java | 340 +++++++++++------- .../incubator/vector/Byte512VectorTests.java | 340 +++++++++++------- .../incubator/vector/Byte64VectorTests.java | 340 +++++++++++------- .../incubator/vector/ByteMaxVectorTests.java | 324 +++++++++++------ .../vector/Double128VectorTests.java | 336 ++++++++++------- .../vector/Double256VectorTests.java | 336 ++++++++++------- .../vector/Double512VectorTests.java | 336 ++++++++++------- .../incubator/vector/Double64VectorTests.java | 336 ++++++++++------- .../vector/DoubleMaxVectorTests.java | 320 +++++++++++------ .../incubator/vector/Float128VectorTests.java | 336 ++++++++++------- .../incubator/vector/Float256VectorTests.java | 336 ++++++++++------- .../incubator/vector/Float512VectorTests.java | 336 ++++++++++------- .../incubator/vector/Float64VectorTests.java | 336 ++++++++++------- .../incubator/vector/FloatMaxVectorTests.java | 320 +++++++++++------ .../incubator/vector/Int128VectorTests.java | 340 +++++++++++------- .../incubator/vector/Int256VectorTests.java | 340 +++++++++++------- .../incubator/vector/Int512VectorTests.java | 340 +++++++++++------- .../incubator/vector/Int64VectorTests.java | 340 +++++++++++------- .../incubator/vector/IntMaxVectorTests.java | 324 +++++++++++------ .../incubator/vector/Long128VectorTests.java | 340 +++++++++++------- .../incubator/vector/Long256VectorTests.java | 340 +++++++++++------- .../incubator/vector/Long512VectorTests.java | 340 +++++++++++------- .../incubator/vector/Long64VectorTests.java | 340 +++++++++++------- .../incubator/vector/LongMaxVectorTests.java | 324 +++++++++++------ .../incubator/vector/Short128VectorTests.java | 340 +++++++++++------- .../incubator/vector/Short256VectorTests.java | 340 +++++++++++------- .../incubator/vector/Short512VectorTests.java | 340 +++++++++++------- .../incubator/vector/Short64VectorTests.java | 340 +++++++++++------- .../incubator/vector/ShortMaxVectorTests.java | 324 +++++++++++------ test/jdk/jdk/incubator/vector/gen-template.sh | 15 +- .../templates/Kernel-BoolBinary-op.template | 11 + .../templates/Kernel-BoolUnary-op.template | 9 + .../templates/Unit-BoolBinary-op.template | 10 + .../templates/Unit-BoolUnary-op.template | 10 + .../templates/Unit-Mask-FromToLong.template | 27 ++ .../templates/Unit-Miscellaneous.template | 132 +------ .../vector/templates/Unit-header.template | 49 ++- 39 files changed, 6447 insertions(+), 3933 deletions(-) create mode 100644 test/jdk/jdk/incubator/vector/templates/Kernel-BoolBinary-op.template create mode 100644 test/jdk/jdk/incubator/vector/templates/Kernel-BoolUnary-op.template create mode 100644 test/jdk/jdk/incubator/vector/templates/Unit-BoolBinary-op.template create mode 100644 test/jdk/jdk/incubator/vector/templates/Unit-BoolUnary-op.template create mode 100644 test/jdk/jdk/incubator/vector/templates/Unit-Mask-FromToLong.template diff --git a/test/jdk/jdk/incubator/vector/AbstractVectorTest.java b/test/jdk/jdk/incubator/vector/AbstractVectorTest.java index 71cabe75b76..b334e64ab80 100644 --- a/test/jdk/jdk/incubator/vector/AbstractVectorTest.java +++ b/test/jdk/jdk/incubator/vector/AbstractVectorTest.java @@ -110,19 +110,19 @@ public class AbstractVectorTest { } static final List> BOOLEAN_MASK_GENERATORS = List.of( - withToString("mask[i % 2]", (int l) -> { - boolean[] a = new boolean[l]; - for (int i = 0; i < l; i++) { - a[i] = (i % 2 == 0); - } - return a; + withToString("mask[i % 2]", (int s) -> { + return fill_boolean(s, + i -> ((i % 2) == 0)); }), - withToString("mask[true]", (int l) -> { - boolean[] a = new boolean[l]; + withToString("mask[true]", (int s) -> { + boolean[] a = new boolean[s]; Arrays.fill(a, true); return a; }), - withToString("mask[false]", boolean[]::new) + withToString("mask[false]", boolean[]::new), + withToString("mask[random]", (int s) -> { + return fill_boolean(s,_i -> RAND.nextBoolean()); + }) ); static final List>> @@ -131,6 +131,26 @@ public class AbstractVectorTest { flatMap(fa -> BOOLEAN_MASK_GENERATORS.stream().skip(1).map( fb -> List.of(fa, fb))).collect(Collectors.toList()); + static long[] pack_booleans_to_longs(boolean[] mask) { + int totalLongs = (mask.length + 63) / 64; // ceil division + long[] packed = new long[totalLongs]; + for (int i = 0; i < mask.length; i++) { + int longIndex = i / 64; + int bitIndex = i % 64; + if (mask[i]) { + packed[longIndex] |= 1L << bitIndex; + } + } + return packed; + } + + static final List> LONG_MASK_GENERATORS = BOOLEAN_MASK_GENERATORS.stream() + .map(f -> withToString( + f.toString().replace("mask", "long_mask"), + (IntFunction) (int l) -> pack_booleans_to_longs(f.apply(l)) + )) + .collect(Collectors.toList()); + static final List> INT_SHUFFLE_GENERATORS = List.of( withToStringBi("shuffle[random]", (Integer l, Integer m) -> RAND.ints(l, 0, m).toArray()) @@ -210,21 +230,6 @@ public class AbstractVectorTest { return a; } - interface FBooleanBinOp { - boolean apply(boolean a, boolean b); - } - - static void assertArraysEquals(boolean[] r, boolean[] a, boolean[] b, FBooleanBinOp f) { - int i = 0; - try { - for (; i < a.length; i++) { - Assert.assertEquals(r[i], f.apply(a[i], b[i])); - } - } catch (AssertionError e) { - Assert.assertEquals(r[i], f.apply(a[i], b[i]), "(" + a[i] + ", " + b[i] + ") at index #" + i); - } - } - // Non-optimized test partial wrap derived from the Spec: // Validation function for lane indexes which may be out of the valid range of [0..VLENGTH-1]. // The index is forced into this range by adding or subtracting a suitable multiple of VLENGTH. diff --git a/test/jdk/jdk/incubator/vector/Byte128VectorTests.java b/test/jdk/jdk/incubator/vector/Byte128VectorTests.java index bea4d541987..4980c66c02a 100644 --- a/test/jdk/jdk/incubator/vector/Byte128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Byte128VectorTests.java @@ -393,6 +393,36 @@ public class Byte128VectorTests extends AbstractVectorTest { } } + interface FBoolUnOp { + boolean apply(boolean a); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, FBoolUnOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i]), "(" + a[i] + ") at index #" + i); + } + } + + interface FBoolBinOp { + boolean apply(boolean a, boolean b); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, boolean[] b, FBoolBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b[i]), "(" + a[i] + ", " + b[i] + ") at index #" + i); + } + } + interface FBinOp { byte apply(byte a, byte b); } @@ -1095,12 +1125,6 @@ public class Byte128VectorTests extends AbstractVectorTest { .flatMap(pair -> BYTE_SATURATING_GENERATORS_ASSOC.stream().map(f -> List.of(pair.get(0), pair.get(1), f))) .collect(Collectors.toList()); - @DataProvider - public Object[][] boolUnaryOpProvider() { - return BOOL_ARRAY_GENERATORS.stream(). - map(f -> new Object[]{f}). - toArray(Object[][]::new); - } static final List>> BYTE_GENERATOR_TRIPLES = BYTE_GENERATOR_PAIRS.stream(). @@ -1232,8 +1256,23 @@ public class Byte128VectorTests extends AbstractVectorTest { } @DataProvider - public Object[][] maskCompareOpProvider() { - return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream().map(List::toArray). + public Object[][] longMaskProvider() { + return LONG_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskBinaryOpProvider() { + return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream(). + map(List::toArray). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskUnaryOpProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). toArray(Object[][]::new); } @@ -4464,7 +4503,7 @@ public class Byte128VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void anyTrueByte128VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -4488,7 +4527,7 @@ public class Byte128VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void allTrueByte128VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -6390,6 +6429,157 @@ public class Byte128VectorTests extends AbstractVectorTest { assertArraysEquals(r, a, mask, Byte128VectorTests::REVERSE_BYTES); } + static boolean band(boolean a, boolean b) { + return a & b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandByte128VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.and(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Byte128VectorTests::band); + } + + static boolean bor(boolean a, boolean b) { + return a | b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskorByte128VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.or(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Byte128VectorTests::bor); + } + + static boolean bxor(boolean a, boolean b) { + return a != b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskxorByte128VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.xor(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Byte128VectorTests::bxor); + } + + static boolean bandNot(boolean a, boolean b) { + return a & !b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandNotByte128VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.andNot(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Byte128VectorTests::bandNot); + } + + static boolean beq(boolean a, boolean b) { + return a == b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskeqByte128VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.eq(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Byte128VectorTests::beq); + } + + static boolean unot(boolean a) { + return !a; + } + + @Test(dataProvider = "boolMaskUnaryOpProvider") + static void masknotByte128VectorTests(IntFunction fa) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + av.not().intoArray(r, i); + } + } + + assertArraysEquals(r, a, Byte128VectorTests::unot); + } + + private static final long LONG_MASK_BITS = 0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length()); + + static void assertArraysEquals(long[] r, long[] a, long bits) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], a[i] & bits); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], a[i] & bits, "(" + a[i] + ") at index #" + i); + } + } + + @Test(dataProvider = "longMaskProvider") + static void maskFromToLongByte128VectorTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = new long[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i++) { + VectorMask vmask = VectorMask.fromLong(SPECIES, a[i]); + r[i] = vmask.toLong(); + } + } + assertArraysEquals(r, a, LONG_MASK_BITS); + } + @Test(dataProvider = "byteCompareOpProvider") static void ltByte128VectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { byte[] a = fa.apply(SPECIES.length()); @@ -6700,115 +6890,22 @@ public class Byte128VectorTests extends AbstractVectorTest { } } - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqualsByte128VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskEqualsByte128VectorTests(IntFunction fa, IntFunction fb) { boolean[] a = fa.apply(SPECIES.length()); boolean[] b = fb.apply(SPECIES.length()); - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - boolean equals = av.equals(bv); - int to = i + SPECIES.length(); - Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + var av = SPECIES.loadMask(a, i); + var bv = SPECIES.loadMask(b, i); + boolean equals = av.equals(bv); + int to = i + SPECIES.length(); + Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + } } } - static boolean band(boolean a, boolean b) { - return a & b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndByte128VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.and(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Byte128VectorTests::band); - } - - static boolean bor(boolean a, boolean b) { - return a | b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskOrByte128VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.or(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Byte128VectorTests::bor); - } - - static boolean bxor(boolean a, boolean b) { - return a != b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskXorByte128VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.xor(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Byte128VectorTests::bxor); - } - - static boolean bandNot(boolean a, boolean b) { - return a & !b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndNotByte128VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.andNot(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Byte128VectorTests::bandNot); - } - - static boolean beq(boolean a, boolean b) { - return (a == b); - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqByte128VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.eq(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Byte128VectorTests::beq); - } - @Test(dataProvider = "maskProvider") static void maskHashCodeByte128VectorTestsSmokeTest(IntFunction fa) { boolean[] a = fa.apply(SPECIES.length()); @@ -6913,23 +7010,6 @@ public class Byte128VectorTests extends AbstractVectorTest { } } - @DataProvider - public static Object[][] longMaskProvider() { - return new Object[][]{ - {0xFFFFFFFFFFFFFFFFL}, - {0x0000000000000000L}, - {0x5555555555555555L}, - {0x0123456789abcdefL}, - }; - } - - @Test(dataProvider = "longMaskProvider") - static void maskFromToLongByte128VectorTestsSmokeTest(long inputLong) { - var vmask = VectorMask.fromLong(SPECIES, inputLong); - long outputLong = vmask.toLong(); - Assert.assertEquals(outputLong, (inputLong & (((0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length())))))); - } - @DataProvider public static Object[][] offsetProvider() { return new Object[][]{ diff --git a/test/jdk/jdk/incubator/vector/Byte256VectorTests.java b/test/jdk/jdk/incubator/vector/Byte256VectorTests.java index be5b3cf6198..b3cad54e101 100644 --- a/test/jdk/jdk/incubator/vector/Byte256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Byte256VectorTests.java @@ -393,6 +393,36 @@ public class Byte256VectorTests extends AbstractVectorTest { } } + interface FBoolUnOp { + boolean apply(boolean a); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, FBoolUnOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i]), "(" + a[i] + ") at index #" + i); + } + } + + interface FBoolBinOp { + boolean apply(boolean a, boolean b); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, boolean[] b, FBoolBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b[i]), "(" + a[i] + ", " + b[i] + ") at index #" + i); + } + } + interface FBinOp { byte apply(byte a, byte b); } @@ -1095,12 +1125,6 @@ public class Byte256VectorTests extends AbstractVectorTest { .flatMap(pair -> BYTE_SATURATING_GENERATORS_ASSOC.stream().map(f -> List.of(pair.get(0), pair.get(1), f))) .collect(Collectors.toList()); - @DataProvider - public Object[][] boolUnaryOpProvider() { - return BOOL_ARRAY_GENERATORS.stream(). - map(f -> new Object[]{f}). - toArray(Object[][]::new); - } static final List>> BYTE_GENERATOR_TRIPLES = BYTE_GENERATOR_PAIRS.stream(). @@ -1232,8 +1256,23 @@ public class Byte256VectorTests extends AbstractVectorTest { } @DataProvider - public Object[][] maskCompareOpProvider() { - return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream().map(List::toArray). + public Object[][] longMaskProvider() { + return LONG_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskBinaryOpProvider() { + return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream(). + map(List::toArray). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskUnaryOpProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). toArray(Object[][]::new); } @@ -4464,7 +4503,7 @@ public class Byte256VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void anyTrueByte256VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -4488,7 +4527,7 @@ public class Byte256VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void allTrueByte256VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -6390,6 +6429,157 @@ public class Byte256VectorTests extends AbstractVectorTest { assertArraysEquals(r, a, mask, Byte256VectorTests::REVERSE_BYTES); } + static boolean band(boolean a, boolean b) { + return a & b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandByte256VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.and(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Byte256VectorTests::band); + } + + static boolean bor(boolean a, boolean b) { + return a | b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskorByte256VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.or(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Byte256VectorTests::bor); + } + + static boolean bxor(boolean a, boolean b) { + return a != b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskxorByte256VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.xor(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Byte256VectorTests::bxor); + } + + static boolean bandNot(boolean a, boolean b) { + return a & !b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandNotByte256VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.andNot(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Byte256VectorTests::bandNot); + } + + static boolean beq(boolean a, boolean b) { + return a == b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskeqByte256VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.eq(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Byte256VectorTests::beq); + } + + static boolean unot(boolean a) { + return !a; + } + + @Test(dataProvider = "boolMaskUnaryOpProvider") + static void masknotByte256VectorTests(IntFunction fa) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + av.not().intoArray(r, i); + } + } + + assertArraysEquals(r, a, Byte256VectorTests::unot); + } + + private static final long LONG_MASK_BITS = 0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length()); + + static void assertArraysEquals(long[] r, long[] a, long bits) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], a[i] & bits); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], a[i] & bits, "(" + a[i] + ") at index #" + i); + } + } + + @Test(dataProvider = "longMaskProvider") + static void maskFromToLongByte256VectorTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = new long[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i++) { + VectorMask vmask = VectorMask.fromLong(SPECIES, a[i]); + r[i] = vmask.toLong(); + } + } + assertArraysEquals(r, a, LONG_MASK_BITS); + } + @Test(dataProvider = "byteCompareOpProvider") static void ltByte256VectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { byte[] a = fa.apply(SPECIES.length()); @@ -6700,115 +6890,22 @@ public class Byte256VectorTests extends AbstractVectorTest { } } - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqualsByte256VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskEqualsByte256VectorTests(IntFunction fa, IntFunction fb) { boolean[] a = fa.apply(SPECIES.length()); boolean[] b = fb.apply(SPECIES.length()); - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - boolean equals = av.equals(bv); - int to = i + SPECIES.length(); - Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + var av = SPECIES.loadMask(a, i); + var bv = SPECIES.loadMask(b, i); + boolean equals = av.equals(bv); + int to = i + SPECIES.length(); + Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + } } } - static boolean band(boolean a, boolean b) { - return a & b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndByte256VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.and(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Byte256VectorTests::band); - } - - static boolean bor(boolean a, boolean b) { - return a | b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskOrByte256VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.or(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Byte256VectorTests::bor); - } - - static boolean bxor(boolean a, boolean b) { - return a != b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskXorByte256VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.xor(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Byte256VectorTests::bxor); - } - - static boolean bandNot(boolean a, boolean b) { - return a & !b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndNotByte256VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.andNot(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Byte256VectorTests::bandNot); - } - - static boolean beq(boolean a, boolean b) { - return (a == b); - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqByte256VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.eq(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Byte256VectorTests::beq); - } - @Test(dataProvider = "maskProvider") static void maskHashCodeByte256VectorTestsSmokeTest(IntFunction fa) { boolean[] a = fa.apply(SPECIES.length()); @@ -6913,23 +7010,6 @@ public class Byte256VectorTests extends AbstractVectorTest { } } - @DataProvider - public static Object[][] longMaskProvider() { - return new Object[][]{ - {0xFFFFFFFFFFFFFFFFL}, - {0x0000000000000000L}, - {0x5555555555555555L}, - {0x0123456789abcdefL}, - }; - } - - @Test(dataProvider = "longMaskProvider") - static void maskFromToLongByte256VectorTestsSmokeTest(long inputLong) { - var vmask = VectorMask.fromLong(SPECIES, inputLong); - long outputLong = vmask.toLong(); - Assert.assertEquals(outputLong, (inputLong & (((0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length())))))); - } - @DataProvider public static Object[][] offsetProvider() { return new Object[][]{ diff --git a/test/jdk/jdk/incubator/vector/Byte512VectorTests.java b/test/jdk/jdk/incubator/vector/Byte512VectorTests.java index 0fd68b6f712..83e48cd2fdc 100644 --- a/test/jdk/jdk/incubator/vector/Byte512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Byte512VectorTests.java @@ -393,6 +393,36 @@ public class Byte512VectorTests extends AbstractVectorTest { } } + interface FBoolUnOp { + boolean apply(boolean a); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, FBoolUnOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i]), "(" + a[i] + ") at index #" + i); + } + } + + interface FBoolBinOp { + boolean apply(boolean a, boolean b); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, boolean[] b, FBoolBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b[i]), "(" + a[i] + ", " + b[i] + ") at index #" + i); + } + } + interface FBinOp { byte apply(byte a, byte b); } @@ -1095,12 +1125,6 @@ public class Byte512VectorTests extends AbstractVectorTest { .flatMap(pair -> BYTE_SATURATING_GENERATORS_ASSOC.stream().map(f -> List.of(pair.get(0), pair.get(1), f))) .collect(Collectors.toList()); - @DataProvider - public Object[][] boolUnaryOpProvider() { - return BOOL_ARRAY_GENERATORS.stream(). - map(f -> new Object[]{f}). - toArray(Object[][]::new); - } static final List>> BYTE_GENERATOR_TRIPLES = BYTE_GENERATOR_PAIRS.stream(). @@ -1232,8 +1256,23 @@ public class Byte512VectorTests extends AbstractVectorTest { } @DataProvider - public Object[][] maskCompareOpProvider() { - return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream().map(List::toArray). + public Object[][] longMaskProvider() { + return LONG_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskBinaryOpProvider() { + return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream(). + map(List::toArray). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskUnaryOpProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). toArray(Object[][]::new); } @@ -4464,7 +4503,7 @@ public class Byte512VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void anyTrueByte512VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -4488,7 +4527,7 @@ public class Byte512VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void allTrueByte512VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -6390,6 +6429,157 @@ public class Byte512VectorTests extends AbstractVectorTest { assertArraysEquals(r, a, mask, Byte512VectorTests::REVERSE_BYTES); } + static boolean band(boolean a, boolean b) { + return a & b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandByte512VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.and(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Byte512VectorTests::band); + } + + static boolean bor(boolean a, boolean b) { + return a | b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskorByte512VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.or(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Byte512VectorTests::bor); + } + + static boolean bxor(boolean a, boolean b) { + return a != b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskxorByte512VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.xor(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Byte512VectorTests::bxor); + } + + static boolean bandNot(boolean a, boolean b) { + return a & !b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandNotByte512VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.andNot(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Byte512VectorTests::bandNot); + } + + static boolean beq(boolean a, boolean b) { + return a == b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskeqByte512VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.eq(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Byte512VectorTests::beq); + } + + static boolean unot(boolean a) { + return !a; + } + + @Test(dataProvider = "boolMaskUnaryOpProvider") + static void masknotByte512VectorTests(IntFunction fa) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + av.not().intoArray(r, i); + } + } + + assertArraysEquals(r, a, Byte512VectorTests::unot); + } + + private static final long LONG_MASK_BITS = 0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length()); + + static void assertArraysEquals(long[] r, long[] a, long bits) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], a[i] & bits); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], a[i] & bits, "(" + a[i] + ") at index #" + i); + } + } + + @Test(dataProvider = "longMaskProvider") + static void maskFromToLongByte512VectorTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = new long[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i++) { + VectorMask vmask = VectorMask.fromLong(SPECIES, a[i]); + r[i] = vmask.toLong(); + } + } + assertArraysEquals(r, a, LONG_MASK_BITS); + } + @Test(dataProvider = "byteCompareOpProvider") static void ltByte512VectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { byte[] a = fa.apply(SPECIES.length()); @@ -6700,115 +6890,22 @@ public class Byte512VectorTests extends AbstractVectorTest { } } - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqualsByte512VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskEqualsByte512VectorTests(IntFunction fa, IntFunction fb) { boolean[] a = fa.apply(SPECIES.length()); boolean[] b = fb.apply(SPECIES.length()); - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - boolean equals = av.equals(bv); - int to = i + SPECIES.length(); - Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + var av = SPECIES.loadMask(a, i); + var bv = SPECIES.loadMask(b, i); + boolean equals = av.equals(bv); + int to = i + SPECIES.length(); + Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + } } } - static boolean band(boolean a, boolean b) { - return a & b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndByte512VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.and(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Byte512VectorTests::band); - } - - static boolean bor(boolean a, boolean b) { - return a | b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskOrByte512VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.or(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Byte512VectorTests::bor); - } - - static boolean bxor(boolean a, boolean b) { - return a != b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskXorByte512VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.xor(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Byte512VectorTests::bxor); - } - - static boolean bandNot(boolean a, boolean b) { - return a & !b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndNotByte512VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.andNot(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Byte512VectorTests::bandNot); - } - - static boolean beq(boolean a, boolean b) { - return (a == b); - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqByte512VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.eq(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Byte512VectorTests::beq); - } - @Test(dataProvider = "maskProvider") static void maskHashCodeByte512VectorTestsSmokeTest(IntFunction fa) { boolean[] a = fa.apply(SPECIES.length()); @@ -6913,23 +7010,6 @@ public class Byte512VectorTests extends AbstractVectorTest { } } - @DataProvider - public static Object[][] longMaskProvider() { - return new Object[][]{ - {0xFFFFFFFFFFFFFFFFL}, - {0x0000000000000000L}, - {0x5555555555555555L}, - {0x0123456789abcdefL}, - }; - } - - @Test(dataProvider = "longMaskProvider") - static void maskFromToLongByte512VectorTestsSmokeTest(long inputLong) { - var vmask = VectorMask.fromLong(SPECIES, inputLong); - long outputLong = vmask.toLong(); - Assert.assertEquals(outputLong, (inputLong & (((0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length())))))); - } - @DataProvider public static Object[][] offsetProvider() { return new Object[][]{ diff --git a/test/jdk/jdk/incubator/vector/Byte64VectorTests.java b/test/jdk/jdk/incubator/vector/Byte64VectorTests.java index 112b2e56b6f..0088b3fbf8e 100644 --- a/test/jdk/jdk/incubator/vector/Byte64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Byte64VectorTests.java @@ -393,6 +393,36 @@ public class Byte64VectorTests extends AbstractVectorTest { } } + interface FBoolUnOp { + boolean apply(boolean a); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, FBoolUnOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i]), "(" + a[i] + ") at index #" + i); + } + } + + interface FBoolBinOp { + boolean apply(boolean a, boolean b); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, boolean[] b, FBoolBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b[i]), "(" + a[i] + ", " + b[i] + ") at index #" + i); + } + } + interface FBinOp { byte apply(byte a, byte b); } @@ -1095,12 +1125,6 @@ public class Byte64VectorTests extends AbstractVectorTest { .flatMap(pair -> BYTE_SATURATING_GENERATORS_ASSOC.stream().map(f -> List.of(pair.get(0), pair.get(1), f))) .collect(Collectors.toList()); - @DataProvider - public Object[][] boolUnaryOpProvider() { - return BOOL_ARRAY_GENERATORS.stream(). - map(f -> new Object[]{f}). - toArray(Object[][]::new); - } static final List>> BYTE_GENERATOR_TRIPLES = BYTE_GENERATOR_PAIRS.stream(). @@ -1232,8 +1256,23 @@ public class Byte64VectorTests extends AbstractVectorTest { } @DataProvider - public Object[][] maskCompareOpProvider() { - return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream().map(List::toArray). + public Object[][] longMaskProvider() { + return LONG_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskBinaryOpProvider() { + return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream(). + map(List::toArray). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskUnaryOpProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). toArray(Object[][]::new); } @@ -4464,7 +4503,7 @@ public class Byte64VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void anyTrueByte64VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -4488,7 +4527,7 @@ public class Byte64VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void allTrueByte64VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -6390,6 +6429,157 @@ public class Byte64VectorTests extends AbstractVectorTest { assertArraysEquals(r, a, mask, Byte64VectorTests::REVERSE_BYTES); } + static boolean band(boolean a, boolean b) { + return a & b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandByte64VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.and(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Byte64VectorTests::band); + } + + static boolean bor(boolean a, boolean b) { + return a | b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskorByte64VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.or(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Byte64VectorTests::bor); + } + + static boolean bxor(boolean a, boolean b) { + return a != b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskxorByte64VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.xor(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Byte64VectorTests::bxor); + } + + static boolean bandNot(boolean a, boolean b) { + return a & !b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandNotByte64VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.andNot(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Byte64VectorTests::bandNot); + } + + static boolean beq(boolean a, boolean b) { + return a == b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskeqByte64VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.eq(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Byte64VectorTests::beq); + } + + static boolean unot(boolean a) { + return !a; + } + + @Test(dataProvider = "boolMaskUnaryOpProvider") + static void masknotByte64VectorTests(IntFunction fa) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + av.not().intoArray(r, i); + } + } + + assertArraysEquals(r, a, Byte64VectorTests::unot); + } + + private static final long LONG_MASK_BITS = 0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length()); + + static void assertArraysEquals(long[] r, long[] a, long bits) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], a[i] & bits); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], a[i] & bits, "(" + a[i] + ") at index #" + i); + } + } + + @Test(dataProvider = "longMaskProvider") + static void maskFromToLongByte64VectorTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = new long[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i++) { + VectorMask vmask = VectorMask.fromLong(SPECIES, a[i]); + r[i] = vmask.toLong(); + } + } + assertArraysEquals(r, a, LONG_MASK_BITS); + } + @Test(dataProvider = "byteCompareOpProvider") static void ltByte64VectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { byte[] a = fa.apply(SPECIES.length()); @@ -6700,115 +6890,22 @@ public class Byte64VectorTests extends AbstractVectorTest { } } - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqualsByte64VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskEqualsByte64VectorTests(IntFunction fa, IntFunction fb) { boolean[] a = fa.apply(SPECIES.length()); boolean[] b = fb.apply(SPECIES.length()); - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - boolean equals = av.equals(bv); - int to = i + SPECIES.length(); - Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + var av = SPECIES.loadMask(a, i); + var bv = SPECIES.loadMask(b, i); + boolean equals = av.equals(bv); + int to = i + SPECIES.length(); + Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + } } } - static boolean band(boolean a, boolean b) { - return a & b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndByte64VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.and(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Byte64VectorTests::band); - } - - static boolean bor(boolean a, boolean b) { - return a | b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskOrByte64VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.or(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Byte64VectorTests::bor); - } - - static boolean bxor(boolean a, boolean b) { - return a != b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskXorByte64VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.xor(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Byte64VectorTests::bxor); - } - - static boolean bandNot(boolean a, boolean b) { - return a & !b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndNotByte64VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.andNot(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Byte64VectorTests::bandNot); - } - - static boolean beq(boolean a, boolean b) { - return (a == b); - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqByte64VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.eq(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Byte64VectorTests::beq); - } - @Test(dataProvider = "maskProvider") static void maskHashCodeByte64VectorTestsSmokeTest(IntFunction fa) { boolean[] a = fa.apply(SPECIES.length()); @@ -6913,23 +7010,6 @@ public class Byte64VectorTests extends AbstractVectorTest { } } - @DataProvider - public static Object[][] longMaskProvider() { - return new Object[][]{ - {0xFFFFFFFFFFFFFFFFL}, - {0x0000000000000000L}, - {0x5555555555555555L}, - {0x0123456789abcdefL}, - }; - } - - @Test(dataProvider = "longMaskProvider") - static void maskFromToLongByte64VectorTestsSmokeTest(long inputLong) { - var vmask = VectorMask.fromLong(SPECIES, inputLong); - long outputLong = vmask.toLong(); - Assert.assertEquals(outputLong, (inputLong & (((0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length())))))); - } - @DataProvider public static Object[][] offsetProvider() { return new Object[][]{ diff --git a/test/jdk/jdk/incubator/vector/ByteMaxVectorTests.java b/test/jdk/jdk/incubator/vector/ByteMaxVectorTests.java index 435cacc013e..6df01fb48e3 100644 --- a/test/jdk/jdk/incubator/vector/ByteMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/ByteMaxVectorTests.java @@ -398,6 +398,36 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } } + interface FBoolUnOp { + boolean apply(boolean a); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, FBoolUnOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i]), "(" + a[i] + ") at index #" + i); + } + } + + interface FBoolBinOp { + boolean apply(boolean a, boolean b); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, boolean[] b, FBoolBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b[i]), "(" + a[i] + ", " + b[i] + ") at index #" + i); + } + } + interface FBinOp { byte apply(byte a, byte b); } @@ -1100,12 +1130,6 @@ public class ByteMaxVectorTests extends AbstractVectorTest { .flatMap(pair -> BYTE_SATURATING_GENERATORS_ASSOC.stream().map(f -> List.of(pair.get(0), pair.get(1), f))) .collect(Collectors.toList()); - @DataProvider - public Object[][] boolUnaryOpProvider() { - return BOOL_ARRAY_GENERATORS.stream(). - map(f -> new Object[]{f}). - toArray(Object[][]::new); - } static final List>> BYTE_GENERATOR_TRIPLES = BYTE_GENERATOR_PAIRS.stream(). @@ -1237,8 +1261,23 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } @DataProvider - public Object[][] maskCompareOpProvider() { - return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream().map(List::toArray). + public Object[][] longMaskProvider() { + return LONG_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskBinaryOpProvider() { + return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream(). + map(List::toArray). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskUnaryOpProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). toArray(Object[][]::new); } @@ -4469,7 +4508,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void anyTrueByteMaxVectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -4493,7 +4532,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void allTrueByteMaxVectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -6395,6 +6434,157 @@ public class ByteMaxVectorTests extends AbstractVectorTest { assertArraysEquals(r, a, mask, ByteMaxVectorTests::REVERSE_BYTES); } + static boolean band(boolean a, boolean b) { + return a & b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandByteMaxVectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.and(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, ByteMaxVectorTests::band); + } + + static boolean bor(boolean a, boolean b) { + return a | b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskorByteMaxVectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.or(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, ByteMaxVectorTests::bor); + } + + static boolean bxor(boolean a, boolean b) { + return a != b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskxorByteMaxVectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.xor(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, ByteMaxVectorTests::bxor); + } + + static boolean bandNot(boolean a, boolean b) { + return a & !b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandNotByteMaxVectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.andNot(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, ByteMaxVectorTests::bandNot); + } + + static boolean beq(boolean a, boolean b) { + return a == b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskeqByteMaxVectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.eq(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, ByteMaxVectorTests::beq); + } + + static boolean unot(boolean a) { + return !a; + } + + @Test(dataProvider = "boolMaskUnaryOpProvider") + static void masknotByteMaxVectorTests(IntFunction fa) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + av.not().intoArray(r, i); + } + } + + assertArraysEquals(r, a, ByteMaxVectorTests::unot); + } + + private static final long LONG_MASK_BITS = 0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length()); + + static void assertArraysEquals(long[] r, long[] a, long bits) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], a[i] & bits); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], a[i] & bits, "(" + a[i] + ") at index #" + i); + } + } + + @Test(dataProvider = "longMaskProvider") + static void maskFromToLongByteMaxVectorTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = new long[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i++) { + VectorMask vmask = VectorMask.fromLong(SPECIES, a[i]); + r[i] = vmask.toLong(); + } + } + assertArraysEquals(r, a, LONG_MASK_BITS); + } + @Test(dataProvider = "byteCompareOpProvider") static void ltByteMaxVectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { byte[] a = fa.apply(SPECIES.length()); @@ -6705,115 +6895,22 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } } - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqualsByteMaxVectorTestsSmokeTest(IntFunction fa, IntFunction fb) { + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskEqualsByteMaxVectorTests(IntFunction fa, IntFunction fb) { boolean[] a = fa.apply(SPECIES.length()); boolean[] b = fb.apply(SPECIES.length()); - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - boolean equals = av.equals(bv); - int to = i + SPECIES.length(); - Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + var av = SPECIES.loadMask(a, i); + var bv = SPECIES.loadMask(b, i); + boolean equals = av.equals(bv); + int to = i + SPECIES.length(); + Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + } } } - static boolean band(boolean a, boolean b) { - return a & b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndByteMaxVectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.and(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, ByteMaxVectorTests::band); - } - - static boolean bor(boolean a, boolean b) { - return a | b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskOrByteMaxVectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.or(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, ByteMaxVectorTests::bor); - } - - static boolean bxor(boolean a, boolean b) { - return a != b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskXorByteMaxVectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.xor(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, ByteMaxVectorTests::bxor); - } - - static boolean bandNot(boolean a, boolean b) { - return a & !b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndNotByteMaxVectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.andNot(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, ByteMaxVectorTests::bandNot); - } - - static boolean beq(boolean a, boolean b) { - return (a == b); - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqByteMaxVectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.eq(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, ByteMaxVectorTests::beq); - } - @Test(dataProvider = "maskProvider") static void maskHashCodeByteMaxVectorTestsSmokeTest(IntFunction fa) { boolean[] a = fa.apply(SPECIES.length()); @@ -6918,7 +7015,6 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } } - @DataProvider public static Object[][] offsetProvider() { return new Object[][]{ diff --git a/test/jdk/jdk/incubator/vector/Double128VectorTests.java b/test/jdk/jdk/incubator/vector/Double128VectorTests.java index f15ce88ddb8..879dac4c966 100644 --- a/test/jdk/jdk/incubator/vector/Double128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Double128VectorTests.java @@ -411,6 +411,36 @@ relativeError)); } } + interface FBoolUnOp { + boolean apply(boolean a); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, FBoolUnOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i]), "(" + a[i] + ") at index #" + i); + } + } + + interface FBoolBinOp { + boolean apply(boolean a, boolean b); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, boolean[] b, FBoolBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b[i]), "(" + a[i] + ", " + b[i] + ") at index #" + i); + } + } + interface FBinOp { double apply(double a, double b); } @@ -1187,12 +1217,6 @@ relativeError)); flatMap(fa -> DOUBLE_GENERATORS.stream().skip(1).map(fb -> List.of(fa, fb))). collect(Collectors.toList()); - @DataProvider - public Object[][] boolUnaryOpProvider() { - return BOOL_ARRAY_GENERATORS.stream(). - map(f -> new Object[]{f}). - toArray(Object[][]::new); - } static final List>> DOUBLE_GENERATOR_TRIPLES = DOUBLE_GENERATOR_PAIRS.stream(). @@ -1291,8 +1315,23 @@ relativeError)); } @DataProvider - public Object[][] maskCompareOpProvider() { - return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream().map(List::toArray). + public Object[][] longMaskProvider() { + return LONG_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskBinaryOpProvider() { + return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream(). + map(List::toArray). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskUnaryOpProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). toArray(Object[][]::new); } @@ -4806,6 +4845,157 @@ relativeError)); assertArraysEquals(r, a, mask, Double128VectorTests::SQRT); } + static boolean band(boolean a, boolean b) { + return a & b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandDouble128VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.and(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Double128VectorTests::band); + } + + static boolean bor(boolean a, boolean b) { + return a | b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskorDouble128VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.or(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Double128VectorTests::bor); + } + + static boolean bxor(boolean a, boolean b) { + return a != b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskxorDouble128VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.xor(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Double128VectorTests::bxor); + } + + static boolean bandNot(boolean a, boolean b) { + return a & !b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandNotDouble128VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.andNot(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Double128VectorTests::bandNot); + } + + static boolean beq(boolean a, boolean b) { + return a == b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskeqDouble128VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.eq(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Double128VectorTests::beq); + } + + static boolean unot(boolean a) { + return !a; + } + + @Test(dataProvider = "boolMaskUnaryOpProvider") + static void masknotDouble128VectorTests(IntFunction fa) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + av.not().intoArray(r, i); + } + } + + assertArraysEquals(r, a, Double128VectorTests::unot); + } + + private static final long LONG_MASK_BITS = 0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length()); + + static void assertArraysEquals(long[] r, long[] a, long bits) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], a[i] & bits); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], a[i] & bits, "(" + a[i] + ") at index #" + i); + } + } + + @Test(dataProvider = "longMaskProvider") + static void maskFromToLongDouble128VectorTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = new long[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i++) { + VectorMask vmask = VectorMask.fromLong(SPECIES, a[i]); + r[i] = vmask.toLong(); + } + } + assertArraysEquals(r, a, LONG_MASK_BITS); + } + @Test(dataProvider = "doubleCompareOpProvider") static void ltDouble128VectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { double[] a = fa.apply(SPECIES.length()); @@ -5095,115 +5285,22 @@ relativeError)); } } - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqualsDouble128VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskEqualsDouble128VectorTests(IntFunction fa, IntFunction fb) { boolean[] a = fa.apply(SPECIES.length()); boolean[] b = fb.apply(SPECIES.length()); - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - boolean equals = av.equals(bv); - int to = i + SPECIES.length(); - Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + var av = SPECIES.loadMask(a, i); + var bv = SPECIES.loadMask(b, i); + boolean equals = av.equals(bv); + int to = i + SPECIES.length(); + Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + } } } - static boolean band(boolean a, boolean b) { - return a & b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndDouble128VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.and(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Double128VectorTests::band); - } - - static boolean bor(boolean a, boolean b) { - return a | b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskOrDouble128VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.or(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Double128VectorTests::bor); - } - - static boolean bxor(boolean a, boolean b) { - return a != b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskXorDouble128VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.xor(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Double128VectorTests::bxor); - } - - static boolean bandNot(boolean a, boolean b) { - return a & !b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndNotDouble128VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.andNot(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Double128VectorTests::bandNot); - } - - static boolean beq(boolean a, boolean b) { - return (a == b); - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqDouble128VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.eq(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Double128VectorTests::beq); - } - @Test(dataProvider = "maskProvider") static void maskHashCodeDouble128VectorTestsSmokeTest(IntFunction fa) { boolean[] a = fa.apply(SPECIES.length()); @@ -5308,23 +5405,6 @@ relativeError)); } } - @DataProvider - public static Object[][] longMaskProvider() { - return new Object[][]{ - {0xFFFFFFFFFFFFFFFFL}, - {0x0000000000000000L}, - {0x5555555555555555L}, - {0x0123456789abcdefL}, - }; - } - - @Test(dataProvider = "longMaskProvider") - static void maskFromToLongDouble128VectorTestsSmokeTest(long inputLong) { - var vmask = VectorMask.fromLong(SPECIES, inputLong); - long outputLong = vmask.toLong(); - Assert.assertEquals(outputLong, (inputLong & (((0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length())))))); - } - @DataProvider public static Object[][] offsetProvider() { return new Object[][]{ diff --git a/test/jdk/jdk/incubator/vector/Double256VectorTests.java b/test/jdk/jdk/incubator/vector/Double256VectorTests.java index e6c3662e0ad..87230330642 100644 --- a/test/jdk/jdk/incubator/vector/Double256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Double256VectorTests.java @@ -411,6 +411,36 @@ relativeError)); } } + interface FBoolUnOp { + boolean apply(boolean a); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, FBoolUnOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i]), "(" + a[i] + ") at index #" + i); + } + } + + interface FBoolBinOp { + boolean apply(boolean a, boolean b); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, boolean[] b, FBoolBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b[i]), "(" + a[i] + ", " + b[i] + ") at index #" + i); + } + } + interface FBinOp { double apply(double a, double b); } @@ -1187,12 +1217,6 @@ relativeError)); flatMap(fa -> DOUBLE_GENERATORS.stream().skip(1).map(fb -> List.of(fa, fb))). collect(Collectors.toList()); - @DataProvider - public Object[][] boolUnaryOpProvider() { - return BOOL_ARRAY_GENERATORS.stream(). - map(f -> new Object[]{f}). - toArray(Object[][]::new); - } static final List>> DOUBLE_GENERATOR_TRIPLES = DOUBLE_GENERATOR_PAIRS.stream(). @@ -1291,8 +1315,23 @@ relativeError)); } @DataProvider - public Object[][] maskCompareOpProvider() { - return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream().map(List::toArray). + public Object[][] longMaskProvider() { + return LONG_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskBinaryOpProvider() { + return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream(). + map(List::toArray). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskUnaryOpProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). toArray(Object[][]::new); } @@ -4806,6 +4845,157 @@ relativeError)); assertArraysEquals(r, a, mask, Double256VectorTests::SQRT); } + static boolean band(boolean a, boolean b) { + return a & b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandDouble256VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.and(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Double256VectorTests::band); + } + + static boolean bor(boolean a, boolean b) { + return a | b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskorDouble256VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.or(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Double256VectorTests::bor); + } + + static boolean bxor(boolean a, boolean b) { + return a != b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskxorDouble256VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.xor(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Double256VectorTests::bxor); + } + + static boolean bandNot(boolean a, boolean b) { + return a & !b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandNotDouble256VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.andNot(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Double256VectorTests::bandNot); + } + + static boolean beq(boolean a, boolean b) { + return a == b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskeqDouble256VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.eq(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Double256VectorTests::beq); + } + + static boolean unot(boolean a) { + return !a; + } + + @Test(dataProvider = "boolMaskUnaryOpProvider") + static void masknotDouble256VectorTests(IntFunction fa) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + av.not().intoArray(r, i); + } + } + + assertArraysEquals(r, a, Double256VectorTests::unot); + } + + private static final long LONG_MASK_BITS = 0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length()); + + static void assertArraysEquals(long[] r, long[] a, long bits) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], a[i] & bits); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], a[i] & bits, "(" + a[i] + ") at index #" + i); + } + } + + @Test(dataProvider = "longMaskProvider") + static void maskFromToLongDouble256VectorTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = new long[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i++) { + VectorMask vmask = VectorMask.fromLong(SPECIES, a[i]); + r[i] = vmask.toLong(); + } + } + assertArraysEquals(r, a, LONG_MASK_BITS); + } + @Test(dataProvider = "doubleCompareOpProvider") static void ltDouble256VectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { double[] a = fa.apply(SPECIES.length()); @@ -5095,115 +5285,22 @@ relativeError)); } } - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqualsDouble256VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskEqualsDouble256VectorTests(IntFunction fa, IntFunction fb) { boolean[] a = fa.apply(SPECIES.length()); boolean[] b = fb.apply(SPECIES.length()); - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - boolean equals = av.equals(bv); - int to = i + SPECIES.length(); - Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + var av = SPECIES.loadMask(a, i); + var bv = SPECIES.loadMask(b, i); + boolean equals = av.equals(bv); + int to = i + SPECIES.length(); + Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + } } } - static boolean band(boolean a, boolean b) { - return a & b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndDouble256VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.and(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Double256VectorTests::band); - } - - static boolean bor(boolean a, boolean b) { - return a | b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskOrDouble256VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.or(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Double256VectorTests::bor); - } - - static boolean bxor(boolean a, boolean b) { - return a != b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskXorDouble256VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.xor(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Double256VectorTests::bxor); - } - - static boolean bandNot(boolean a, boolean b) { - return a & !b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndNotDouble256VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.andNot(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Double256VectorTests::bandNot); - } - - static boolean beq(boolean a, boolean b) { - return (a == b); - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqDouble256VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.eq(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Double256VectorTests::beq); - } - @Test(dataProvider = "maskProvider") static void maskHashCodeDouble256VectorTestsSmokeTest(IntFunction fa) { boolean[] a = fa.apply(SPECIES.length()); @@ -5308,23 +5405,6 @@ relativeError)); } } - @DataProvider - public static Object[][] longMaskProvider() { - return new Object[][]{ - {0xFFFFFFFFFFFFFFFFL}, - {0x0000000000000000L}, - {0x5555555555555555L}, - {0x0123456789abcdefL}, - }; - } - - @Test(dataProvider = "longMaskProvider") - static void maskFromToLongDouble256VectorTestsSmokeTest(long inputLong) { - var vmask = VectorMask.fromLong(SPECIES, inputLong); - long outputLong = vmask.toLong(); - Assert.assertEquals(outputLong, (inputLong & (((0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length())))))); - } - @DataProvider public static Object[][] offsetProvider() { return new Object[][]{ diff --git a/test/jdk/jdk/incubator/vector/Double512VectorTests.java b/test/jdk/jdk/incubator/vector/Double512VectorTests.java index 7c37c9878e8..af8fbf5f51f 100644 --- a/test/jdk/jdk/incubator/vector/Double512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Double512VectorTests.java @@ -411,6 +411,36 @@ relativeError)); } } + interface FBoolUnOp { + boolean apply(boolean a); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, FBoolUnOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i]), "(" + a[i] + ") at index #" + i); + } + } + + interface FBoolBinOp { + boolean apply(boolean a, boolean b); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, boolean[] b, FBoolBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b[i]), "(" + a[i] + ", " + b[i] + ") at index #" + i); + } + } + interface FBinOp { double apply(double a, double b); } @@ -1187,12 +1217,6 @@ relativeError)); flatMap(fa -> DOUBLE_GENERATORS.stream().skip(1).map(fb -> List.of(fa, fb))). collect(Collectors.toList()); - @DataProvider - public Object[][] boolUnaryOpProvider() { - return BOOL_ARRAY_GENERATORS.stream(). - map(f -> new Object[]{f}). - toArray(Object[][]::new); - } static final List>> DOUBLE_GENERATOR_TRIPLES = DOUBLE_GENERATOR_PAIRS.stream(). @@ -1291,8 +1315,23 @@ relativeError)); } @DataProvider - public Object[][] maskCompareOpProvider() { - return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream().map(List::toArray). + public Object[][] longMaskProvider() { + return LONG_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskBinaryOpProvider() { + return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream(). + map(List::toArray). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskUnaryOpProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). toArray(Object[][]::new); } @@ -4806,6 +4845,157 @@ relativeError)); assertArraysEquals(r, a, mask, Double512VectorTests::SQRT); } + static boolean band(boolean a, boolean b) { + return a & b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandDouble512VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.and(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Double512VectorTests::band); + } + + static boolean bor(boolean a, boolean b) { + return a | b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskorDouble512VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.or(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Double512VectorTests::bor); + } + + static boolean bxor(boolean a, boolean b) { + return a != b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskxorDouble512VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.xor(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Double512VectorTests::bxor); + } + + static boolean bandNot(boolean a, boolean b) { + return a & !b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandNotDouble512VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.andNot(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Double512VectorTests::bandNot); + } + + static boolean beq(boolean a, boolean b) { + return a == b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskeqDouble512VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.eq(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Double512VectorTests::beq); + } + + static boolean unot(boolean a) { + return !a; + } + + @Test(dataProvider = "boolMaskUnaryOpProvider") + static void masknotDouble512VectorTests(IntFunction fa) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + av.not().intoArray(r, i); + } + } + + assertArraysEquals(r, a, Double512VectorTests::unot); + } + + private static final long LONG_MASK_BITS = 0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length()); + + static void assertArraysEquals(long[] r, long[] a, long bits) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], a[i] & bits); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], a[i] & bits, "(" + a[i] + ") at index #" + i); + } + } + + @Test(dataProvider = "longMaskProvider") + static void maskFromToLongDouble512VectorTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = new long[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i++) { + VectorMask vmask = VectorMask.fromLong(SPECIES, a[i]); + r[i] = vmask.toLong(); + } + } + assertArraysEquals(r, a, LONG_MASK_BITS); + } + @Test(dataProvider = "doubleCompareOpProvider") static void ltDouble512VectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { double[] a = fa.apply(SPECIES.length()); @@ -5095,115 +5285,22 @@ relativeError)); } } - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqualsDouble512VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskEqualsDouble512VectorTests(IntFunction fa, IntFunction fb) { boolean[] a = fa.apply(SPECIES.length()); boolean[] b = fb.apply(SPECIES.length()); - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - boolean equals = av.equals(bv); - int to = i + SPECIES.length(); - Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + var av = SPECIES.loadMask(a, i); + var bv = SPECIES.loadMask(b, i); + boolean equals = av.equals(bv); + int to = i + SPECIES.length(); + Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + } } } - static boolean band(boolean a, boolean b) { - return a & b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndDouble512VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.and(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Double512VectorTests::band); - } - - static boolean bor(boolean a, boolean b) { - return a | b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskOrDouble512VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.or(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Double512VectorTests::bor); - } - - static boolean bxor(boolean a, boolean b) { - return a != b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskXorDouble512VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.xor(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Double512VectorTests::bxor); - } - - static boolean bandNot(boolean a, boolean b) { - return a & !b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndNotDouble512VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.andNot(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Double512VectorTests::bandNot); - } - - static boolean beq(boolean a, boolean b) { - return (a == b); - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqDouble512VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.eq(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Double512VectorTests::beq); - } - @Test(dataProvider = "maskProvider") static void maskHashCodeDouble512VectorTestsSmokeTest(IntFunction fa) { boolean[] a = fa.apply(SPECIES.length()); @@ -5308,23 +5405,6 @@ relativeError)); } } - @DataProvider - public static Object[][] longMaskProvider() { - return new Object[][]{ - {0xFFFFFFFFFFFFFFFFL}, - {0x0000000000000000L}, - {0x5555555555555555L}, - {0x0123456789abcdefL}, - }; - } - - @Test(dataProvider = "longMaskProvider") - static void maskFromToLongDouble512VectorTestsSmokeTest(long inputLong) { - var vmask = VectorMask.fromLong(SPECIES, inputLong); - long outputLong = vmask.toLong(); - Assert.assertEquals(outputLong, (inputLong & (((0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length())))))); - } - @DataProvider public static Object[][] offsetProvider() { return new Object[][]{ diff --git a/test/jdk/jdk/incubator/vector/Double64VectorTests.java b/test/jdk/jdk/incubator/vector/Double64VectorTests.java index 85b96288b37..67822ae5353 100644 --- a/test/jdk/jdk/incubator/vector/Double64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Double64VectorTests.java @@ -411,6 +411,36 @@ relativeError)); } } + interface FBoolUnOp { + boolean apply(boolean a); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, FBoolUnOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i]), "(" + a[i] + ") at index #" + i); + } + } + + interface FBoolBinOp { + boolean apply(boolean a, boolean b); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, boolean[] b, FBoolBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b[i]), "(" + a[i] + ", " + b[i] + ") at index #" + i); + } + } + interface FBinOp { double apply(double a, double b); } @@ -1187,12 +1217,6 @@ relativeError)); flatMap(fa -> DOUBLE_GENERATORS.stream().skip(1).map(fb -> List.of(fa, fb))). collect(Collectors.toList()); - @DataProvider - public Object[][] boolUnaryOpProvider() { - return BOOL_ARRAY_GENERATORS.stream(). - map(f -> new Object[]{f}). - toArray(Object[][]::new); - } static final List>> DOUBLE_GENERATOR_TRIPLES = DOUBLE_GENERATOR_PAIRS.stream(). @@ -1291,8 +1315,23 @@ relativeError)); } @DataProvider - public Object[][] maskCompareOpProvider() { - return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream().map(List::toArray). + public Object[][] longMaskProvider() { + return LONG_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskBinaryOpProvider() { + return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream(). + map(List::toArray). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskUnaryOpProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). toArray(Object[][]::new); } @@ -4806,6 +4845,157 @@ relativeError)); assertArraysEquals(r, a, mask, Double64VectorTests::SQRT); } + static boolean band(boolean a, boolean b) { + return a & b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandDouble64VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.and(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Double64VectorTests::band); + } + + static boolean bor(boolean a, boolean b) { + return a | b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskorDouble64VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.or(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Double64VectorTests::bor); + } + + static boolean bxor(boolean a, boolean b) { + return a != b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskxorDouble64VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.xor(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Double64VectorTests::bxor); + } + + static boolean bandNot(boolean a, boolean b) { + return a & !b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandNotDouble64VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.andNot(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Double64VectorTests::bandNot); + } + + static boolean beq(boolean a, boolean b) { + return a == b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskeqDouble64VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.eq(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Double64VectorTests::beq); + } + + static boolean unot(boolean a) { + return !a; + } + + @Test(dataProvider = "boolMaskUnaryOpProvider") + static void masknotDouble64VectorTests(IntFunction fa) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + av.not().intoArray(r, i); + } + } + + assertArraysEquals(r, a, Double64VectorTests::unot); + } + + private static final long LONG_MASK_BITS = 0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length()); + + static void assertArraysEquals(long[] r, long[] a, long bits) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], a[i] & bits); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], a[i] & bits, "(" + a[i] + ") at index #" + i); + } + } + + @Test(dataProvider = "longMaskProvider") + static void maskFromToLongDouble64VectorTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = new long[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i++) { + VectorMask vmask = VectorMask.fromLong(SPECIES, a[i]); + r[i] = vmask.toLong(); + } + } + assertArraysEquals(r, a, LONG_MASK_BITS); + } + @Test(dataProvider = "doubleCompareOpProvider") static void ltDouble64VectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { double[] a = fa.apply(SPECIES.length()); @@ -5095,115 +5285,22 @@ relativeError)); } } - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqualsDouble64VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskEqualsDouble64VectorTests(IntFunction fa, IntFunction fb) { boolean[] a = fa.apply(SPECIES.length()); boolean[] b = fb.apply(SPECIES.length()); - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - boolean equals = av.equals(bv); - int to = i + SPECIES.length(); - Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + var av = SPECIES.loadMask(a, i); + var bv = SPECIES.loadMask(b, i); + boolean equals = av.equals(bv); + int to = i + SPECIES.length(); + Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + } } } - static boolean band(boolean a, boolean b) { - return a & b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndDouble64VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.and(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Double64VectorTests::band); - } - - static boolean bor(boolean a, boolean b) { - return a | b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskOrDouble64VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.or(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Double64VectorTests::bor); - } - - static boolean bxor(boolean a, boolean b) { - return a != b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskXorDouble64VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.xor(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Double64VectorTests::bxor); - } - - static boolean bandNot(boolean a, boolean b) { - return a & !b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndNotDouble64VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.andNot(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Double64VectorTests::bandNot); - } - - static boolean beq(boolean a, boolean b) { - return (a == b); - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqDouble64VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.eq(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Double64VectorTests::beq); - } - @Test(dataProvider = "maskProvider") static void maskHashCodeDouble64VectorTestsSmokeTest(IntFunction fa) { boolean[] a = fa.apply(SPECIES.length()); @@ -5308,23 +5405,6 @@ relativeError)); } } - @DataProvider - public static Object[][] longMaskProvider() { - return new Object[][]{ - {0xFFFFFFFFFFFFFFFFL}, - {0x0000000000000000L}, - {0x5555555555555555L}, - {0x0123456789abcdefL}, - }; - } - - @Test(dataProvider = "longMaskProvider") - static void maskFromToLongDouble64VectorTestsSmokeTest(long inputLong) { - var vmask = VectorMask.fromLong(SPECIES, inputLong); - long outputLong = vmask.toLong(); - Assert.assertEquals(outputLong, (inputLong & (((0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length())))))); - } - @DataProvider public static Object[][] offsetProvider() { return new Object[][]{ diff --git a/test/jdk/jdk/incubator/vector/DoubleMaxVectorTests.java b/test/jdk/jdk/incubator/vector/DoubleMaxVectorTests.java index 7245990d66c..5d7ae07c55a 100644 --- a/test/jdk/jdk/incubator/vector/DoubleMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/DoubleMaxVectorTests.java @@ -416,6 +416,36 @@ relativeError)); } } + interface FBoolUnOp { + boolean apply(boolean a); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, FBoolUnOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i]), "(" + a[i] + ") at index #" + i); + } + } + + interface FBoolBinOp { + boolean apply(boolean a, boolean b); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, boolean[] b, FBoolBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b[i]), "(" + a[i] + ", " + b[i] + ") at index #" + i); + } + } + interface FBinOp { double apply(double a, double b); } @@ -1192,12 +1222,6 @@ relativeError)); flatMap(fa -> DOUBLE_GENERATORS.stream().skip(1).map(fb -> List.of(fa, fb))). collect(Collectors.toList()); - @DataProvider - public Object[][] boolUnaryOpProvider() { - return BOOL_ARRAY_GENERATORS.stream(). - map(f -> new Object[]{f}). - toArray(Object[][]::new); - } static final List>> DOUBLE_GENERATOR_TRIPLES = DOUBLE_GENERATOR_PAIRS.stream(). @@ -1296,8 +1320,23 @@ relativeError)); } @DataProvider - public Object[][] maskCompareOpProvider() { - return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream().map(List::toArray). + public Object[][] longMaskProvider() { + return LONG_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskBinaryOpProvider() { + return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream(). + map(List::toArray). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskUnaryOpProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). toArray(Object[][]::new); } @@ -4811,6 +4850,157 @@ relativeError)); assertArraysEquals(r, a, mask, DoubleMaxVectorTests::SQRT); } + static boolean band(boolean a, boolean b) { + return a & b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandDoubleMaxVectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.and(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, DoubleMaxVectorTests::band); + } + + static boolean bor(boolean a, boolean b) { + return a | b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskorDoubleMaxVectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.or(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, DoubleMaxVectorTests::bor); + } + + static boolean bxor(boolean a, boolean b) { + return a != b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskxorDoubleMaxVectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.xor(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, DoubleMaxVectorTests::bxor); + } + + static boolean bandNot(boolean a, boolean b) { + return a & !b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandNotDoubleMaxVectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.andNot(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, DoubleMaxVectorTests::bandNot); + } + + static boolean beq(boolean a, boolean b) { + return a == b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskeqDoubleMaxVectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.eq(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, DoubleMaxVectorTests::beq); + } + + static boolean unot(boolean a) { + return !a; + } + + @Test(dataProvider = "boolMaskUnaryOpProvider") + static void masknotDoubleMaxVectorTests(IntFunction fa) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + av.not().intoArray(r, i); + } + } + + assertArraysEquals(r, a, DoubleMaxVectorTests::unot); + } + + private static final long LONG_MASK_BITS = 0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length()); + + static void assertArraysEquals(long[] r, long[] a, long bits) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], a[i] & bits); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], a[i] & bits, "(" + a[i] + ") at index #" + i); + } + } + + @Test(dataProvider = "longMaskProvider") + static void maskFromToLongDoubleMaxVectorTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = new long[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i++) { + VectorMask vmask = VectorMask.fromLong(SPECIES, a[i]); + r[i] = vmask.toLong(); + } + } + assertArraysEquals(r, a, LONG_MASK_BITS); + } + @Test(dataProvider = "doubleCompareOpProvider") static void ltDoubleMaxVectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { double[] a = fa.apply(SPECIES.length()); @@ -5100,115 +5290,22 @@ relativeError)); } } - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqualsDoubleMaxVectorTestsSmokeTest(IntFunction fa, IntFunction fb) { + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskEqualsDoubleMaxVectorTests(IntFunction fa, IntFunction fb) { boolean[] a = fa.apply(SPECIES.length()); boolean[] b = fb.apply(SPECIES.length()); - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - boolean equals = av.equals(bv); - int to = i + SPECIES.length(); - Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + var av = SPECIES.loadMask(a, i); + var bv = SPECIES.loadMask(b, i); + boolean equals = av.equals(bv); + int to = i + SPECIES.length(); + Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + } } } - static boolean band(boolean a, boolean b) { - return a & b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndDoubleMaxVectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.and(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, DoubleMaxVectorTests::band); - } - - static boolean bor(boolean a, boolean b) { - return a | b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskOrDoubleMaxVectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.or(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, DoubleMaxVectorTests::bor); - } - - static boolean bxor(boolean a, boolean b) { - return a != b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskXorDoubleMaxVectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.xor(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, DoubleMaxVectorTests::bxor); - } - - static boolean bandNot(boolean a, boolean b) { - return a & !b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndNotDoubleMaxVectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.andNot(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, DoubleMaxVectorTests::bandNot); - } - - static boolean beq(boolean a, boolean b) { - return (a == b); - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqDoubleMaxVectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.eq(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, DoubleMaxVectorTests::beq); - } - @Test(dataProvider = "maskProvider") static void maskHashCodeDoubleMaxVectorTestsSmokeTest(IntFunction fa) { boolean[] a = fa.apply(SPECIES.length()); @@ -5313,7 +5410,6 @@ relativeError)); } } - @DataProvider public static Object[][] offsetProvider() { return new Object[][]{ diff --git a/test/jdk/jdk/incubator/vector/Float128VectorTests.java b/test/jdk/jdk/incubator/vector/Float128VectorTests.java index c4f4ed1b966..0d3ce311a90 100644 --- a/test/jdk/jdk/incubator/vector/Float128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Float128VectorTests.java @@ -411,6 +411,36 @@ relativeError)); } } + interface FBoolUnOp { + boolean apply(boolean a); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, FBoolUnOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i]), "(" + a[i] + ") at index #" + i); + } + } + + interface FBoolBinOp { + boolean apply(boolean a, boolean b); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, boolean[] b, FBoolBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b[i]), "(" + a[i] + ", " + b[i] + ") at index #" + i); + } + } + interface FBinOp { float apply(float a, float b); } @@ -1198,12 +1228,6 @@ relativeError)); flatMap(fa -> FLOAT_GENERATORS.stream().skip(1).map(fb -> List.of(fa, fb))). collect(Collectors.toList()); - @DataProvider - public Object[][] boolUnaryOpProvider() { - return BOOL_ARRAY_GENERATORS.stream(). - map(f -> new Object[]{f}). - toArray(Object[][]::new); - } static final List>> FLOAT_GENERATOR_TRIPLES = FLOAT_GENERATOR_PAIRS.stream(). @@ -1302,8 +1326,23 @@ relativeError)); } @DataProvider - public Object[][] maskCompareOpProvider() { - return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream().map(List::toArray). + public Object[][] longMaskProvider() { + return LONG_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskBinaryOpProvider() { + return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream(). + map(List::toArray). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskUnaryOpProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). toArray(Object[][]::new); } @@ -4775,6 +4814,157 @@ relativeError)); assertArraysEquals(r, a, mask, Float128VectorTests::SQRT); } + static boolean band(boolean a, boolean b) { + return a & b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandFloat128VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.and(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Float128VectorTests::band); + } + + static boolean bor(boolean a, boolean b) { + return a | b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskorFloat128VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.or(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Float128VectorTests::bor); + } + + static boolean bxor(boolean a, boolean b) { + return a != b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskxorFloat128VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.xor(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Float128VectorTests::bxor); + } + + static boolean bandNot(boolean a, boolean b) { + return a & !b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandNotFloat128VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.andNot(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Float128VectorTests::bandNot); + } + + static boolean beq(boolean a, boolean b) { + return a == b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskeqFloat128VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.eq(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Float128VectorTests::beq); + } + + static boolean unot(boolean a) { + return !a; + } + + @Test(dataProvider = "boolMaskUnaryOpProvider") + static void masknotFloat128VectorTests(IntFunction fa) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + av.not().intoArray(r, i); + } + } + + assertArraysEquals(r, a, Float128VectorTests::unot); + } + + private static final long LONG_MASK_BITS = 0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length()); + + static void assertArraysEquals(long[] r, long[] a, long bits) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], a[i] & bits); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], a[i] & bits, "(" + a[i] + ") at index #" + i); + } + } + + @Test(dataProvider = "longMaskProvider") + static void maskFromToLongFloat128VectorTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = new long[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i++) { + VectorMask vmask = VectorMask.fromLong(SPECIES, a[i]); + r[i] = vmask.toLong(); + } + } + assertArraysEquals(r, a, LONG_MASK_BITS); + } + @Test(dataProvider = "floatCompareOpProvider") static void ltFloat128VectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { float[] a = fa.apply(SPECIES.length()); @@ -5074,115 +5264,22 @@ relativeError)); } } - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqualsFloat128VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskEqualsFloat128VectorTests(IntFunction fa, IntFunction fb) { boolean[] a = fa.apply(SPECIES.length()); boolean[] b = fb.apply(SPECIES.length()); - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - boolean equals = av.equals(bv); - int to = i + SPECIES.length(); - Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + var av = SPECIES.loadMask(a, i); + var bv = SPECIES.loadMask(b, i); + boolean equals = av.equals(bv); + int to = i + SPECIES.length(); + Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + } } } - static boolean band(boolean a, boolean b) { - return a & b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndFloat128VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.and(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Float128VectorTests::band); - } - - static boolean bor(boolean a, boolean b) { - return a | b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskOrFloat128VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.or(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Float128VectorTests::bor); - } - - static boolean bxor(boolean a, boolean b) { - return a != b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskXorFloat128VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.xor(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Float128VectorTests::bxor); - } - - static boolean bandNot(boolean a, boolean b) { - return a & !b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndNotFloat128VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.andNot(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Float128VectorTests::bandNot); - } - - static boolean beq(boolean a, boolean b) { - return (a == b); - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqFloat128VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.eq(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Float128VectorTests::beq); - } - @Test(dataProvider = "maskProvider") static void maskHashCodeFloat128VectorTestsSmokeTest(IntFunction fa) { boolean[] a = fa.apply(SPECIES.length()); @@ -5287,23 +5384,6 @@ relativeError)); } } - @DataProvider - public static Object[][] longMaskProvider() { - return new Object[][]{ - {0xFFFFFFFFFFFFFFFFL}, - {0x0000000000000000L}, - {0x5555555555555555L}, - {0x0123456789abcdefL}, - }; - } - - @Test(dataProvider = "longMaskProvider") - static void maskFromToLongFloat128VectorTestsSmokeTest(long inputLong) { - var vmask = VectorMask.fromLong(SPECIES, inputLong); - long outputLong = vmask.toLong(); - Assert.assertEquals(outputLong, (inputLong & (((0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length())))))); - } - @DataProvider public static Object[][] offsetProvider() { return new Object[][]{ diff --git a/test/jdk/jdk/incubator/vector/Float256VectorTests.java b/test/jdk/jdk/incubator/vector/Float256VectorTests.java index 87cbc165d59..88ea856f17b 100644 --- a/test/jdk/jdk/incubator/vector/Float256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Float256VectorTests.java @@ -411,6 +411,36 @@ relativeError)); } } + interface FBoolUnOp { + boolean apply(boolean a); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, FBoolUnOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i]), "(" + a[i] + ") at index #" + i); + } + } + + interface FBoolBinOp { + boolean apply(boolean a, boolean b); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, boolean[] b, FBoolBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b[i]), "(" + a[i] + ", " + b[i] + ") at index #" + i); + } + } + interface FBinOp { float apply(float a, float b); } @@ -1198,12 +1228,6 @@ relativeError)); flatMap(fa -> FLOAT_GENERATORS.stream().skip(1).map(fb -> List.of(fa, fb))). collect(Collectors.toList()); - @DataProvider - public Object[][] boolUnaryOpProvider() { - return BOOL_ARRAY_GENERATORS.stream(). - map(f -> new Object[]{f}). - toArray(Object[][]::new); - } static final List>> FLOAT_GENERATOR_TRIPLES = FLOAT_GENERATOR_PAIRS.stream(). @@ -1302,8 +1326,23 @@ relativeError)); } @DataProvider - public Object[][] maskCompareOpProvider() { - return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream().map(List::toArray). + public Object[][] longMaskProvider() { + return LONG_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskBinaryOpProvider() { + return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream(). + map(List::toArray). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskUnaryOpProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). toArray(Object[][]::new); } @@ -4775,6 +4814,157 @@ relativeError)); assertArraysEquals(r, a, mask, Float256VectorTests::SQRT); } + static boolean band(boolean a, boolean b) { + return a & b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandFloat256VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.and(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Float256VectorTests::band); + } + + static boolean bor(boolean a, boolean b) { + return a | b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskorFloat256VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.or(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Float256VectorTests::bor); + } + + static boolean bxor(boolean a, boolean b) { + return a != b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskxorFloat256VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.xor(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Float256VectorTests::bxor); + } + + static boolean bandNot(boolean a, boolean b) { + return a & !b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandNotFloat256VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.andNot(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Float256VectorTests::bandNot); + } + + static boolean beq(boolean a, boolean b) { + return a == b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskeqFloat256VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.eq(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Float256VectorTests::beq); + } + + static boolean unot(boolean a) { + return !a; + } + + @Test(dataProvider = "boolMaskUnaryOpProvider") + static void masknotFloat256VectorTests(IntFunction fa) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + av.not().intoArray(r, i); + } + } + + assertArraysEquals(r, a, Float256VectorTests::unot); + } + + private static final long LONG_MASK_BITS = 0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length()); + + static void assertArraysEquals(long[] r, long[] a, long bits) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], a[i] & bits); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], a[i] & bits, "(" + a[i] + ") at index #" + i); + } + } + + @Test(dataProvider = "longMaskProvider") + static void maskFromToLongFloat256VectorTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = new long[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i++) { + VectorMask vmask = VectorMask.fromLong(SPECIES, a[i]); + r[i] = vmask.toLong(); + } + } + assertArraysEquals(r, a, LONG_MASK_BITS); + } + @Test(dataProvider = "floatCompareOpProvider") static void ltFloat256VectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { float[] a = fa.apply(SPECIES.length()); @@ -5074,115 +5264,22 @@ relativeError)); } } - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqualsFloat256VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskEqualsFloat256VectorTests(IntFunction fa, IntFunction fb) { boolean[] a = fa.apply(SPECIES.length()); boolean[] b = fb.apply(SPECIES.length()); - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - boolean equals = av.equals(bv); - int to = i + SPECIES.length(); - Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + var av = SPECIES.loadMask(a, i); + var bv = SPECIES.loadMask(b, i); + boolean equals = av.equals(bv); + int to = i + SPECIES.length(); + Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + } } } - static boolean band(boolean a, boolean b) { - return a & b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndFloat256VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.and(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Float256VectorTests::band); - } - - static boolean bor(boolean a, boolean b) { - return a | b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskOrFloat256VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.or(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Float256VectorTests::bor); - } - - static boolean bxor(boolean a, boolean b) { - return a != b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskXorFloat256VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.xor(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Float256VectorTests::bxor); - } - - static boolean bandNot(boolean a, boolean b) { - return a & !b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndNotFloat256VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.andNot(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Float256VectorTests::bandNot); - } - - static boolean beq(boolean a, boolean b) { - return (a == b); - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqFloat256VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.eq(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Float256VectorTests::beq); - } - @Test(dataProvider = "maskProvider") static void maskHashCodeFloat256VectorTestsSmokeTest(IntFunction fa) { boolean[] a = fa.apply(SPECIES.length()); @@ -5287,23 +5384,6 @@ relativeError)); } } - @DataProvider - public static Object[][] longMaskProvider() { - return new Object[][]{ - {0xFFFFFFFFFFFFFFFFL}, - {0x0000000000000000L}, - {0x5555555555555555L}, - {0x0123456789abcdefL}, - }; - } - - @Test(dataProvider = "longMaskProvider") - static void maskFromToLongFloat256VectorTestsSmokeTest(long inputLong) { - var vmask = VectorMask.fromLong(SPECIES, inputLong); - long outputLong = vmask.toLong(); - Assert.assertEquals(outputLong, (inputLong & (((0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length())))))); - } - @DataProvider public static Object[][] offsetProvider() { return new Object[][]{ diff --git a/test/jdk/jdk/incubator/vector/Float512VectorTests.java b/test/jdk/jdk/incubator/vector/Float512VectorTests.java index beb9561d882..cdccbfdd319 100644 --- a/test/jdk/jdk/incubator/vector/Float512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Float512VectorTests.java @@ -411,6 +411,36 @@ relativeError)); } } + interface FBoolUnOp { + boolean apply(boolean a); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, FBoolUnOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i]), "(" + a[i] + ") at index #" + i); + } + } + + interface FBoolBinOp { + boolean apply(boolean a, boolean b); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, boolean[] b, FBoolBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b[i]), "(" + a[i] + ", " + b[i] + ") at index #" + i); + } + } + interface FBinOp { float apply(float a, float b); } @@ -1198,12 +1228,6 @@ relativeError)); flatMap(fa -> FLOAT_GENERATORS.stream().skip(1).map(fb -> List.of(fa, fb))). collect(Collectors.toList()); - @DataProvider - public Object[][] boolUnaryOpProvider() { - return BOOL_ARRAY_GENERATORS.stream(). - map(f -> new Object[]{f}). - toArray(Object[][]::new); - } static final List>> FLOAT_GENERATOR_TRIPLES = FLOAT_GENERATOR_PAIRS.stream(). @@ -1302,8 +1326,23 @@ relativeError)); } @DataProvider - public Object[][] maskCompareOpProvider() { - return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream().map(List::toArray). + public Object[][] longMaskProvider() { + return LONG_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskBinaryOpProvider() { + return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream(). + map(List::toArray). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskUnaryOpProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). toArray(Object[][]::new); } @@ -4775,6 +4814,157 @@ relativeError)); assertArraysEquals(r, a, mask, Float512VectorTests::SQRT); } + static boolean band(boolean a, boolean b) { + return a & b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandFloat512VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.and(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Float512VectorTests::band); + } + + static boolean bor(boolean a, boolean b) { + return a | b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskorFloat512VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.or(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Float512VectorTests::bor); + } + + static boolean bxor(boolean a, boolean b) { + return a != b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskxorFloat512VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.xor(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Float512VectorTests::bxor); + } + + static boolean bandNot(boolean a, boolean b) { + return a & !b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandNotFloat512VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.andNot(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Float512VectorTests::bandNot); + } + + static boolean beq(boolean a, boolean b) { + return a == b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskeqFloat512VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.eq(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Float512VectorTests::beq); + } + + static boolean unot(boolean a) { + return !a; + } + + @Test(dataProvider = "boolMaskUnaryOpProvider") + static void masknotFloat512VectorTests(IntFunction fa) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + av.not().intoArray(r, i); + } + } + + assertArraysEquals(r, a, Float512VectorTests::unot); + } + + private static final long LONG_MASK_BITS = 0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length()); + + static void assertArraysEquals(long[] r, long[] a, long bits) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], a[i] & bits); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], a[i] & bits, "(" + a[i] + ") at index #" + i); + } + } + + @Test(dataProvider = "longMaskProvider") + static void maskFromToLongFloat512VectorTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = new long[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i++) { + VectorMask vmask = VectorMask.fromLong(SPECIES, a[i]); + r[i] = vmask.toLong(); + } + } + assertArraysEquals(r, a, LONG_MASK_BITS); + } + @Test(dataProvider = "floatCompareOpProvider") static void ltFloat512VectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { float[] a = fa.apply(SPECIES.length()); @@ -5074,115 +5264,22 @@ relativeError)); } } - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqualsFloat512VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskEqualsFloat512VectorTests(IntFunction fa, IntFunction fb) { boolean[] a = fa.apply(SPECIES.length()); boolean[] b = fb.apply(SPECIES.length()); - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - boolean equals = av.equals(bv); - int to = i + SPECIES.length(); - Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + var av = SPECIES.loadMask(a, i); + var bv = SPECIES.loadMask(b, i); + boolean equals = av.equals(bv); + int to = i + SPECIES.length(); + Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + } } } - static boolean band(boolean a, boolean b) { - return a & b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndFloat512VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.and(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Float512VectorTests::band); - } - - static boolean bor(boolean a, boolean b) { - return a | b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskOrFloat512VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.or(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Float512VectorTests::bor); - } - - static boolean bxor(boolean a, boolean b) { - return a != b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskXorFloat512VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.xor(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Float512VectorTests::bxor); - } - - static boolean bandNot(boolean a, boolean b) { - return a & !b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndNotFloat512VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.andNot(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Float512VectorTests::bandNot); - } - - static boolean beq(boolean a, boolean b) { - return (a == b); - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqFloat512VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.eq(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Float512VectorTests::beq); - } - @Test(dataProvider = "maskProvider") static void maskHashCodeFloat512VectorTestsSmokeTest(IntFunction fa) { boolean[] a = fa.apply(SPECIES.length()); @@ -5287,23 +5384,6 @@ relativeError)); } } - @DataProvider - public static Object[][] longMaskProvider() { - return new Object[][]{ - {0xFFFFFFFFFFFFFFFFL}, - {0x0000000000000000L}, - {0x5555555555555555L}, - {0x0123456789abcdefL}, - }; - } - - @Test(dataProvider = "longMaskProvider") - static void maskFromToLongFloat512VectorTestsSmokeTest(long inputLong) { - var vmask = VectorMask.fromLong(SPECIES, inputLong); - long outputLong = vmask.toLong(); - Assert.assertEquals(outputLong, (inputLong & (((0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length())))))); - } - @DataProvider public static Object[][] offsetProvider() { return new Object[][]{ diff --git a/test/jdk/jdk/incubator/vector/Float64VectorTests.java b/test/jdk/jdk/incubator/vector/Float64VectorTests.java index ee630abd8e0..056eae1974f 100644 --- a/test/jdk/jdk/incubator/vector/Float64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Float64VectorTests.java @@ -411,6 +411,36 @@ relativeError)); } } + interface FBoolUnOp { + boolean apply(boolean a); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, FBoolUnOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i]), "(" + a[i] + ") at index #" + i); + } + } + + interface FBoolBinOp { + boolean apply(boolean a, boolean b); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, boolean[] b, FBoolBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b[i]), "(" + a[i] + ", " + b[i] + ") at index #" + i); + } + } + interface FBinOp { float apply(float a, float b); } @@ -1198,12 +1228,6 @@ relativeError)); flatMap(fa -> FLOAT_GENERATORS.stream().skip(1).map(fb -> List.of(fa, fb))). collect(Collectors.toList()); - @DataProvider - public Object[][] boolUnaryOpProvider() { - return BOOL_ARRAY_GENERATORS.stream(). - map(f -> new Object[]{f}). - toArray(Object[][]::new); - } static final List>> FLOAT_GENERATOR_TRIPLES = FLOAT_GENERATOR_PAIRS.stream(). @@ -1302,8 +1326,23 @@ relativeError)); } @DataProvider - public Object[][] maskCompareOpProvider() { - return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream().map(List::toArray). + public Object[][] longMaskProvider() { + return LONG_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskBinaryOpProvider() { + return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream(). + map(List::toArray). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskUnaryOpProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). toArray(Object[][]::new); } @@ -4775,6 +4814,157 @@ relativeError)); assertArraysEquals(r, a, mask, Float64VectorTests::SQRT); } + static boolean band(boolean a, boolean b) { + return a & b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandFloat64VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.and(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Float64VectorTests::band); + } + + static boolean bor(boolean a, boolean b) { + return a | b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskorFloat64VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.or(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Float64VectorTests::bor); + } + + static boolean bxor(boolean a, boolean b) { + return a != b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskxorFloat64VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.xor(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Float64VectorTests::bxor); + } + + static boolean bandNot(boolean a, boolean b) { + return a & !b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandNotFloat64VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.andNot(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Float64VectorTests::bandNot); + } + + static boolean beq(boolean a, boolean b) { + return a == b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskeqFloat64VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.eq(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Float64VectorTests::beq); + } + + static boolean unot(boolean a) { + return !a; + } + + @Test(dataProvider = "boolMaskUnaryOpProvider") + static void masknotFloat64VectorTests(IntFunction fa) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + av.not().intoArray(r, i); + } + } + + assertArraysEquals(r, a, Float64VectorTests::unot); + } + + private static final long LONG_MASK_BITS = 0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length()); + + static void assertArraysEquals(long[] r, long[] a, long bits) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], a[i] & bits); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], a[i] & bits, "(" + a[i] + ") at index #" + i); + } + } + + @Test(dataProvider = "longMaskProvider") + static void maskFromToLongFloat64VectorTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = new long[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i++) { + VectorMask vmask = VectorMask.fromLong(SPECIES, a[i]); + r[i] = vmask.toLong(); + } + } + assertArraysEquals(r, a, LONG_MASK_BITS); + } + @Test(dataProvider = "floatCompareOpProvider") static void ltFloat64VectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { float[] a = fa.apply(SPECIES.length()); @@ -5074,115 +5264,22 @@ relativeError)); } } - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqualsFloat64VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskEqualsFloat64VectorTests(IntFunction fa, IntFunction fb) { boolean[] a = fa.apply(SPECIES.length()); boolean[] b = fb.apply(SPECIES.length()); - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - boolean equals = av.equals(bv); - int to = i + SPECIES.length(); - Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + var av = SPECIES.loadMask(a, i); + var bv = SPECIES.loadMask(b, i); + boolean equals = av.equals(bv); + int to = i + SPECIES.length(); + Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + } } } - static boolean band(boolean a, boolean b) { - return a & b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndFloat64VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.and(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Float64VectorTests::band); - } - - static boolean bor(boolean a, boolean b) { - return a | b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskOrFloat64VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.or(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Float64VectorTests::bor); - } - - static boolean bxor(boolean a, boolean b) { - return a != b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskXorFloat64VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.xor(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Float64VectorTests::bxor); - } - - static boolean bandNot(boolean a, boolean b) { - return a & !b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndNotFloat64VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.andNot(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Float64VectorTests::bandNot); - } - - static boolean beq(boolean a, boolean b) { - return (a == b); - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqFloat64VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.eq(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Float64VectorTests::beq); - } - @Test(dataProvider = "maskProvider") static void maskHashCodeFloat64VectorTestsSmokeTest(IntFunction fa) { boolean[] a = fa.apply(SPECIES.length()); @@ -5287,23 +5384,6 @@ relativeError)); } } - @DataProvider - public static Object[][] longMaskProvider() { - return new Object[][]{ - {0xFFFFFFFFFFFFFFFFL}, - {0x0000000000000000L}, - {0x5555555555555555L}, - {0x0123456789abcdefL}, - }; - } - - @Test(dataProvider = "longMaskProvider") - static void maskFromToLongFloat64VectorTestsSmokeTest(long inputLong) { - var vmask = VectorMask.fromLong(SPECIES, inputLong); - long outputLong = vmask.toLong(); - Assert.assertEquals(outputLong, (inputLong & (((0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length())))))); - } - @DataProvider public static Object[][] offsetProvider() { return new Object[][]{ diff --git a/test/jdk/jdk/incubator/vector/FloatMaxVectorTests.java b/test/jdk/jdk/incubator/vector/FloatMaxVectorTests.java index 41e4d6e4a5d..19bd385ca1f 100644 --- a/test/jdk/jdk/incubator/vector/FloatMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/FloatMaxVectorTests.java @@ -416,6 +416,36 @@ relativeError)); } } + interface FBoolUnOp { + boolean apply(boolean a); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, FBoolUnOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i]), "(" + a[i] + ") at index #" + i); + } + } + + interface FBoolBinOp { + boolean apply(boolean a, boolean b); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, boolean[] b, FBoolBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b[i]), "(" + a[i] + ", " + b[i] + ") at index #" + i); + } + } + interface FBinOp { float apply(float a, float b); } @@ -1203,12 +1233,6 @@ relativeError)); flatMap(fa -> FLOAT_GENERATORS.stream().skip(1).map(fb -> List.of(fa, fb))). collect(Collectors.toList()); - @DataProvider - public Object[][] boolUnaryOpProvider() { - return BOOL_ARRAY_GENERATORS.stream(). - map(f -> new Object[]{f}). - toArray(Object[][]::new); - } static final List>> FLOAT_GENERATOR_TRIPLES = FLOAT_GENERATOR_PAIRS.stream(). @@ -1307,8 +1331,23 @@ relativeError)); } @DataProvider - public Object[][] maskCompareOpProvider() { - return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream().map(List::toArray). + public Object[][] longMaskProvider() { + return LONG_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskBinaryOpProvider() { + return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream(). + map(List::toArray). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskUnaryOpProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). toArray(Object[][]::new); } @@ -4780,6 +4819,157 @@ relativeError)); assertArraysEquals(r, a, mask, FloatMaxVectorTests::SQRT); } + static boolean band(boolean a, boolean b) { + return a & b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandFloatMaxVectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.and(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, FloatMaxVectorTests::band); + } + + static boolean bor(boolean a, boolean b) { + return a | b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskorFloatMaxVectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.or(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, FloatMaxVectorTests::bor); + } + + static boolean bxor(boolean a, boolean b) { + return a != b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskxorFloatMaxVectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.xor(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, FloatMaxVectorTests::bxor); + } + + static boolean bandNot(boolean a, boolean b) { + return a & !b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandNotFloatMaxVectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.andNot(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, FloatMaxVectorTests::bandNot); + } + + static boolean beq(boolean a, boolean b) { + return a == b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskeqFloatMaxVectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.eq(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, FloatMaxVectorTests::beq); + } + + static boolean unot(boolean a) { + return !a; + } + + @Test(dataProvider = "boolMaskUnaryOpProvider") + static void masknotFloatMaxVectorTests(IntFunction fa) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + av.not().intoArray(r, i); + } + } + + assertArraysEquals(r, a, FloatMaxVectorTests::unot); + } + + private static final long LONG_MASK_BITS = 0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length()); + + static void assertArraysEquals(long[] r, long[] a, long bits) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], a[i] & bits); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], a[i] & bits, "(" + a[i] + ") at index #" + i); + } + } + + @Test(dataProvider = "longMaskProvider") + static void maskFromToLongFloatMaxVectorTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = new long[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i++) { + VectorMask vmask = VectorMask.fromLong(SPECIES, a[i]); + r[i] = vmask.toLong(); + } + } + assertArraysEquals(r, a, LONG_MASK_BITS); + } + @Test(dataProvider = "floatCompareOpProvider") static void ltFloatMaxVectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { float[] a = fa.apply(SPECIES.length()); @@ -5079,115 +5269,22 @@ relativeError)); } } - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqualsFloatMaxVectorTestsSmokeTest(IntFunction fa, IntFunction fb) { + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskEqualsFloatMaxVectorTests(IntFunction fa, IntFunction fb) { boolean[] a = fa.apply(SPECIES.length()); boolean[] b = fb.apply(SPECIES.length()); - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - boolean equals = av.equals(bv); - int to = i + SPECIES.length(); - Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + var av = SPECIES.loadMask(a, i); + var bv = SPECIES.loadMask(b, i); + boolean equals = av.equals(bv); + int to = i + SPECIES.length(); + Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + } } } - static boolean band(boolean a, boolean b) { - return a & b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndFloatMaxVectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.and(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, FloatMaxVectorTests::band); - } - - static boolean bor(boolean a, boolean b) { - return a | b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskOrFloatMaxVectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.or(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, FloatMaxVectorTests::bor); - } - - static boolean bxor(boolean a, boolean b) { - return a != b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskXorFloatMaxVectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.xor(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, FloatMaxVectorTests::bxor); - } - - static boolean bandNot(boolean a, boolean b) { - return a & !b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndNotFloatMaxVectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.andNot(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, FloatMaxVectorTests::bandNot); - } - - static boolean beq(boolean a, boolean b) { - return (a == b); - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqFloatMaxVectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.eq(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, FloatMaxVectorTests::beq); - } - @Test(dataProvider = "maskProvider") static void maskHashCodeFloatMaxVectorTestsSmokeTest(IntFunction fa) { boolean[] a = fa.apply(SPECIES.length()); @@ -5292,7 +5389,6 @@ relativeError)); } } - @DataProvider public static Object[][] offsetProvider() { return new Object[][]{ diff --git a/test/jdk/jdk/incubator/vector/Int128VectorTests.java b/test/jdk/jdk/incubator/vector/Int128VectorTests.java index d6bca96ea6e..1bf3203790c 100644 --- a/test/jdk/jdk/incubator/vector/Int128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Int128VectorTests.java @@ -393,6 +393,36 @@ public class Int128VectorTests extends AbstractVectorTest { } } + interface FBoolUnOp { + boolean apply(boolean a); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, FBoolUnOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i]), "(" + a[i] + ") at index #" + i); + } + } + + interface FBoolBinOp { + boolean apply(boolean a, boolean b); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, boolean[] b, FBoolBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b[i]), "(" + a[i] + ", " + b[i] + ") at index #" + i); + } + } + interface FBinOp { int apply(int a, int b); } @@ -1085,12 +1115,6 @@ public class Int128VectorTests extends AbstractVectorTest { .flatMap(pair -> INT_SATURATING_GENERATORS_ASSOC.stream().map(f -> List.of(pair.get(0), pair.get(1), f))) .collect(Collectors.toList()); - @DataProvider - public Object[][] boolUnaryOpProvider() { - return BOOL_ARRAY_GENERATORS.stream(). - map(f -> new Object[]{f}). - toArray(Object[][]::new); - } static final List>> INT_GENERATOR_TRIPLES = INT_GENERATOR_PAIRS.stream(). @@ -1222,8 +1246,23 @@ public class Int128VectorTests extends AbstractVectorTest { } @DataProvider - public Object[][] maskCompareOpProvider() { - return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream().map(List::toArray). + public Object[][] longMaskProvider() { + return LONG_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskBinaryOpProvider() { + return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream(). + map(List::toArray). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskUnaryOpProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). toArray(Object[][]::new); } @@ -4508,7 +4547,7 @@ public class Int128VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void anyTrueInt128VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -4532,7 +4571,7 @@ public class Int128VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void allTrueInt128VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -6434,6 +6473,157 @@ public class Int128VectorTests extends AbstractVectorTest { assertArraysEquals(r, a, mask, Int128VectorTests::REVERSE_BYTES); } + static boolean band(boolean a, boolean b) { + return a & b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandInt128VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.and(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Int128VectorTests::band); + } + + static boolean bor(boolean a, boolean b) { + return a | b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskorInt128VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.or(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Int128VectorTests::bor); + } + + static boolean bxor(boolean a, boolean b) { + return a != b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskxorInt128VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.xor(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Int128VectorTests::bxor); + } + + static boolean bandNot(boolean a, boolean b) { + return a & !b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandNotInt128VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.andNot(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Int128VectorTests::bandNot); + } + + static boolean beq(boolean a, boolean b) { + return a == b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskeqInt128VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.eq(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Int128VectorTests::beq); + } + + static boolean unot(boolean a) { + return !a; + } + + @Test(dataProvider = "boolMaskUnaryOpProvider") + static void masknotInt128VectorTests(IntFunction fa) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + av.not().intoArray(r, i); + } + } + + assertArraysEquals(r, a, Int128VectorTests::unot); + } + + private static final long LONG_MASK_BITS = 0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length()); + + static void assertArraysEquals(long[] r, long[] a, long bits) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], a[i] & bits); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], a[i] & bits, "(" + a[i] + ") at index #" + i); + } + } + + @Test(dataProvider = "longMaskProvider") + static void maskFromToLongInt128VectorTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = new long[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i++) { + VectorMask vmask = VectorMask.fromLong(SPECIES, a[i]); + r[i] = vmask.toLong(); + } + } + assertArraysEquals(r, a, LONG_MASK_BITS); + } + @Test(dataProvider = "intCompareOpProvider") static void ltInt128VectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { int[] a = fa.apply(SPECIES.length()); @@ -6733,115 +6923,22 @@ public class Int128VectorTests extends AbstractVectorTest { } } - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqualsInt128VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskEqualsInt128VectorTests(IntFunction fa, IntFunction fb) { boolean[] a = fa.apply(SPECIES.length()); boolean[] b = fb.apply(SPECIES.length()); - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - boolean equals = av.equals(bv); - int to = i + SPECIES.length(); - Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + var av = SPECIES.loadMask(a, i); + var bv = SPECIES.loadMask(b, i); + boolean equals = av.equals(bv); + int to = i + SPECIES.length(); + Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + } } } - static boolean band(boolean a, boolean b) { - return a & b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndInt128VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.and(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Int128VectorTests::band); - } - - static boolean bor(boolean a, boolean b) { - return a | b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskOrInt128VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.or(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Int128VectorTests::bor); - } - - static boolean bxor(boolean a, boolean b) { - return a != b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskXorInt128VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.xor(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Int128VectorTests::bxor); - } - - static boolean bandNot(boolean a, boolean b) { - return a & !b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndNotInt128VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.andNot(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Int128VectorTests::bandNot); - } - - static boolean beq(boolean a, boolean b) { - return (a == b); - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqInt128VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.eq(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Int128VectorTests::beq); - } - @Test(dataProvider = "maskProvider") static void maskHashCodeInt128VectorTestsSmokeTest(IntFunction fa) { boolean[] a = fa.apply(SPECIES.length()); @@ -6946,23 +7043,6 @@ public class Int128VectorTests extends AbstractVectorTest { } } - @DataProvider - public static Object[][] longMaskProvider() { - return new Object[][]{ - {0xFFFFFFFFFFFFFFFFL}, - {0x0000000000000000L}, - {0x5555555555555555L}, - {0x0123456789abcdefL}, - }; - } - - @Test(dataProvider = "longMaskProvider") - static void maskFromToLongInt128VectorTestsSmokeTest(long inputLong) { - var vmask = VectorMask.fromLong(SPECIES, inputLong); - long outputLong = vmask.toLong(); - Assert.assertEquals(outputLong, (inputLong & (((0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length())))))); - } - @DataProvider public static Object[][] offsetProvider() { return new Object[][]{ diff --git a/test/jdk/jdk/incubator/vector/Int256VectorTests.java b/test/jdk/jdk/incubator/vector/Int256VectorTests.java index ac98217b714..5973fec7e57 100644 --- a/test/jdk/jdk/incubator/vector/Int256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Int256VectorTests.java @@ -393,6 +393,36 @@ public class Int256VectorTests extends AbstractVectorTest { } } + interface FBoolUnOp { + boolean apply(boolean a); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, FBoolUnOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i]), "(" + a[i] + ") at index #" + i); + } + } + + interface FBoolBinOp { + boolean apply(boolean a, boolean b); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, boolean[] b, FBoolBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b[i]), "(" + a[i] + ", " + b[i] + ") at index #" + i); + } + } + interface FBinOp { int apply(int a, int b); } @@ -1085,12 +1115,6 @@ public class Int256VectorTests extends AbstractVectorTest { .flatMap(pair -> INT_SATURATING_GENERATORS_ASSOC.stream().map(f -> List.of(pair.get(0), pair.get(1), f))) .collect(Collectors.toList()); - @DataProvider - public Object[][] boolUnaryOpProvider() { - return BOOL_ARRAY_GENERATORS.stream(). - map(f -> new Object[]{f}). - toArray(Object[][]::new); - } static final List>> INT_GENERATOR_TRIPLES = INT_GENERATOR_PAIRS.stream(). @@ -1222,8 +1246,23 @@ public class Int256VectorTests extends AbstractVectorTest { } @DataProvider - public Object[][] maskCompareOpProvider() { - return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream().map(List::toArray). + public Object[][] longMaskProvider() { + return LONG_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskBinaryOpProvider() { + return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream(). + map(List::toArray). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskUnaryOpProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). toArray(Object[][]::new); } @@ -4508,7 +4547,7 @@ public class Int256VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void anyTrueInt256VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -4532,7 +4571,7 @@ public class Int256VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void allTrueInt256VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -6434,6 +6473,157 @@ public class Int256VectorTests extends AbstractVectorTest { assertArraysEquals(r, a, mask, Int256VectorTests::REVERSE_BYTES); } + static boolean band(boolean a, boolean b) { + return a & b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandInt256VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.and(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Int256VectorTests::band); + } + + static boolean bor(boolean a, boolean b) { + return a | b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskorInt256VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.or(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Int256VectorTests::bor); + } + + static boolean bxor(boolean a, boolean b) { + return a != b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskxorInt256VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.xor(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Int256VectorTests::bxor); + } + + static boolean bandNot(boolean a, boolean b) { + return a & !b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandNotInt256VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.andNot(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Int256VectorTests::bandNot); + } + + static boolean beq(boolean a, boolean b) { + return a == b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskeqInt256VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.eq(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Int256VectorTests::beq); + } + + static boolean unot(boolean a) { + return !a; + } + + @Test(dataProvider = "boolMaskUnaryOpProvider") + static void masknotInt256VectorTests(IntFunction fa) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + av.not().intoArray(r, i); + } + } + + assertArraysEquals(r, a, Int256VectorTests::unot); + } + + private static final long LONG_MASK_BITS = 0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length()); + + static void assertArraysEquals(long[] r, long[] a, long bits) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], a[i] & bits); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], a[i] & bits, "(" + a[i] + ") at index #" + i); + } + } + + @Test(dataProvider = "longMaskProvider") + static void maskFromToLongInt256VectorTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = new long[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i++) { + VectorMask vmask = VectorMask.fromLong(SPECIES, a[i]); + r[i] = vmask.toLong(); + } + } + assertArraysEquals(r, a, LONG_MASK_BITS); + } + @Test(dataProvider = "intCompareOpProvider") static void ltInt256VectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { int[] a = fa.apply(SPECIES.length()); @@ -6733,115 +6923,22 @@ public class Int256VectorTests extends AbstractVectorTest { } } - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqualsInt256VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskEqualsInt256VectorTests(IntFunction fa, IntFunction fb) { boolean[] a = fa.apply(SPECIES.length()); boolean[] b = fb.apply(SPECIES.length()); - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - boolean equals = av.equals(bv); - int to = i + SPECIES.length(); - Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + var av = SPECIES.loadMask(a, i); + var bv = SPECIES.loadMask(b, i); + boolean equals = av.equals(bv); + int to = i + SPECIES.length(); + Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + } } } - static boolean band(boolean a, boolean b) { - return a & b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndInt256VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.and(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Int256VectorTests::band); - } - - static boolean bor(boolean a, boolean b) { - return a | b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskOrInt256VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.or(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Int256VectorTests::bor); - } - - static boolean bxor(boolean a, boolean b) { - return a != b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskXorInt256VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.xor(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Int256VectorTests::bxor); - } - - static boolean bandNot(boolean a, boolean b) { - return a & !b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndNotInt256VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.andNot(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Int256VectorTests::bandNot); - } - - static boolean beq(boolean a, boolean b) { - return (a == b); - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqInt256VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.eq(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Int256VectorTests::beq); - } - @Test(dataProvider = "maskProvider") static void maskHashCodeInt256VectorTestsSmokeTest(IntFunction fa) { boolean[] a = fa.apply(SPECIES.length()); @@ -6946,23 +7043,6 @@ public class Int256VectorTests extends AbstractVectorTest { } } - @DataProvider - public static Object[][] longMaskProvider() { - return new Object[][]{ - {0xFFFFFFFFFFFFFFFFL}, - {0x0000000000000000L}, - {0x5555555555555555L}, - {0x0123456789abcdefL}, - }; - } - - @Test(dataProvider = "longMaskProvider") - static void maskFromToLongInt256VectorTestsSmokeTest(long inputLong) { - var vmask = VectorMask.fromLong(SPECIES, inputLong); - long outputLong = vmask.toLong(); - Assert.assertEquals(outputLong, (inputLong & (((0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length())))))); - } - @DataProvider public static Object[][] offsetProvider() { return new Object[][]{ diff --git a/test/jdk/jdk/incubator/vector/Int512VectorTests.java b/test/jdk/jdk/incubator/vector/Int512VectorTests.java index b56236db322..a1e969fc852 100644 --- a/test/jdk/jdk/incubator/vector/Int512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Int512VectorTests.java @@ -393,6 +393,36 @@ public class Int512VectorTests extends AbstractVectorTest { } } + interface FBoolUnOp { + boolean apply(boolean a); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, FBoolUnOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i]), "(" + a[i] + ") at index #" + i); + } + } + + interface FBoolBinOp { + boolean apply(boolean a, boolean b); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, boolean[] b, FBoolBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b[i]), "(" + a[i] + ", " + b[i] + ") at index #" + i); + } + } + interface FBinOp { int apply(int a, int b); } @@ -1085,12 +1115,6 @@ public class Int512VectorTests extends AbstractVectorTest { .flatMap(pair -> INT_SATURATING_GENERATORS_ASSOC.stream().map(f -> List.of(pair.get(0), pair.get(1), f))) .collect(Collectors.toList()); - @DataProvider - public Object[][] boolUnaryOpProvider() { - return BOOL_ARRAY_GENERATORS.stream(). - map(f -> new Object[]{f}). - toArray(Object[][]::new); - } static final List>> INT_GENERATOR_TRIPLES = INT_GENERATOR_PAIRS.stream(). @@ -1222,8 +1246,23 @@ public class Int512VectorTests extends AbstractVectorTest { } @DataProvider - public Object[][] maskCompareOpProvider() { - return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream().map(List::toArray). + public Object[][] longMaskProvider() { + return LONG_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskBinaryOpProvider() { + return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream(). + map(List::toArray). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskUnaryOpProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). toArray(Object[][]::new); } @@ -4508,7 +4547,7 @@ public class Int512VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void anyTrueInt512VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -4532,7 +4571,7 @@ public class Int512VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void allTrueInt512VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -6434,6 +6473,157 @@ public class Int512VectorTests extends AbstractVectorTest { assertArraysEquals(r, a, mask, Int512VectorTests::REVERSE_BYTES); } + static boolean band(boolean a, boolean b) { + return a & b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandInt512VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.and(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Int512VectorTests::band); + } + + static boolean bor(boolean a, boolean b) { + return a | b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskorInt512VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.or(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Int512VectorTests::bor); + } + + static boolean bxor(boolean a, boolean b) { + return a != b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskxorInt512VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.xor(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Int512VectorTests::bxor); + } + + static boolean bandNot(boolean a, boolean b) { + return a & !b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandNotInt512VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.andNot(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Int512VectorTests::bandNot); + } + + static boolean beq(boolean a, boolean b) { + return a == b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskeqInt512VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.eq(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Int512VectorTests::beq); + } + + static boolean unot(boolean a) { + return !a; + } + + @Test(dataProvider = "boolMaskUnaryOpProvider") + static void masknotInt512VectorTests(IntFunction fa) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + av.not().intoArray(r, i); + } + } + + assertArraysEquals(r, a, Int512VectorTests::unot); + } + + private static final long LONG_MASK_BITS = 0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length()); + + static void assertArraysEquals(long[] r, long[] a, long bits) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], a[i] & bits); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], a[i] & bits, "(" + a[i] + ") at index #" + i); + } + } + + @Test(dataProvider = "longMaskProvider") + static void maskFromToLongInt512VectorTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = new long[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i++) { + VectorMask vmask = VectorMask.fromLong(SPECIES, a[i]); + r[i] = vmask.toLong(); + } + } + assertArraysEquals(r, a, LONG_MASK_BITS); + } + @Test(dataProvider = "intCompareOpProvider") static void ltInt512VectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { int[] a = fa.apply(SPECIES.length()); @@ -6733,115 +6923,22 @@ public class Int512VectorTests extends AbstractVectorTest { } } - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqualsInt512VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskEqualsInt512VectorTests(IntFunction fa, IntFunction fb) { boolean[] a = fa.apply(SPECIES.length()); boolean[] b = fb.apply(SPECIES.length()); - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - boolean equals = av.equals(bv); - int to = i + SPECIES.length(); - Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + var av = SPECIES.loadMask(a, i); + var bv = SPECIES.loadMask(b, i); + boolean equals = av.equals(bv); + int to = i + SPECIES.length(); + Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + } } } - static boolean band(boolean a, boolean b) { - return a & b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndInt512VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.and(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Int512VectorTests::band); - } - - static boolean bor(boolean a, boolean b) { - return a | b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskOrInt512VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.or(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Int512VectorTests::bor); - } - - static boolean bxor(boolean a, boolean b) { - return a != b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskXorInt512VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.xor(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Int512VectorTests::bxor); - } - - static boolean bandNot(boolean a, boolean b) { - return a & !b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndNotInt512VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.andNot(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Int512VectorTests::bandNot); - } - - static boolean beq(boolean a, boolean b) { - return (a == b); - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqInt512VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.eq(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Int512VectorTests::beq); - } - @Test(dataProvider = "maskProvider") static void maskHashCodeInt512VectorTestsSmokeTest(IntFunction fa) { boolean[] a = fa.apply(SPECIES.length()); @@ -6946,23 +7043,6 @@ public class Int512VectorTests extends AbstractVectorTest { } } - @DataProvider - public static Object[][] longMaskProvider() { - return new Object[][]{ - {0xFFFFFFFFFFFFFFFFL}, - {0x0000000000000000L}, - {0x5555555555555555L}, - {0x0123456789abcdefL}, - }; - } - - @Test(dataProvider = "longMaskProvider") - static void maskFromToLongInt512VectorTestsSmokeTest(long inputLong) { - var vmask = VectorMask.fromLong(SPECIES, inputLong); - long outputLong = vmask.toLong(); - Assert.assertEquals(outputLong, (inputLong & (((0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length())))))); - } - @DataProvider public static Object[][] offsetProvider() { return new Object[][]{ diff --git a/test/jdk/jdk/incubator/vector/Int64VectorTests.java b/test/jdk/jdk/incubator/vector/Int64VectorTests.java index f87a0eb458c..15b3b68820e 100644 --- a/test/jdk/jdk/incubator/vector/Int64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Int64VectorTests.java @@ -393,6 +393,36 @@ public class Int64VectorTests extends AbstractVectorTest { } } + interface FBoolUnOp { + boolean apply(boolean a); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, FBoolUnOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i]), "(" + a[i] + ") at index #" + i); + } + } + + interface FBoolBinOp { + boolean apply(boolean a, boolean b); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, boolean[] b, FBoolBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b[i]), "(" + a[i] + ", " + b[i] + ") at index #" + i); + } + } + interface FBinOp { int apply(int a, int b); } @@ -1085,12 +1115,6 @@ public class Int64VectorTests extends AbstractVectorTest { .flatMap(pair -> INT_SATURATING_GENERATORS_ASSOC.stream().map(f -> List.of(pair.get(0), pair.get(1), f))) .collect(Collectors.toList()); - @DataProvider - public Object[][] boolUnaryOpProvider() { - return BOOL_ARRAY_GENERATORS.stream(). - map(f -> new Object[]{f}). - toArray(Object[][]::new); - } static final List>> INT_GENERATOR_TRIPLES = INT_GENERATOR_PAIRS.stream(). @@ -1222,8 +1246,23 @@ public class Int64VectorTests extends AbstractVectorTest { } @DataProvider - public Object[][] maskCompareOpProvider() { - return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream().map(List::toArray). + public Object[][] longMaskProvider() { + return LONG_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskBinaryOpProvider() { + return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream(). + map(List::toArray). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskUnaryOpProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). toArray(Object[][]::new); } @@ -4508,7 +4547,7 @@ public class Int64VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void anyTrueInt64VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -4532,7 +4571,7 @@ public class Int64VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void allTrueInt64VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -6434,6 +6473,157 @@ public class Int64VectorTests extends AbstractVectorTest { assertArraysEquals(r, a, mask, Int64VectorTests::REVERSE_BYTES); } + static boolean band(boolean a, boolean b) { + return a & b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandInt64VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.and(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Int64VectorTests::band); + } + + static boolean bor(boolean a, boolean b) { + return a | b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskorInt64VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.or(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Int64VectorTests::bor); + } + + static boolean bxor(boolean a, boolean b) { + return a != b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskxorInt64VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.xor(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Int64VectorTests::bxor); + } + + static boolean bandNot(boolean a, boolean b) { + return a & !b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandNotInt64VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.andNot(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Int64VectorTests::bandNot); + } + + static boolean beq(boolean a, boolean b) { + return a == b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskeqInt64VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.eq(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Int64VectorTests::beq); + } + + static boolean unot(boolean a) { + return !a; + } + + @Test(dataProvider = "boolMaskUnaryOpProvider") + static void masknotInt64VectorTests(IntFunction fa) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + av.not().intoArray(r, i); + } + } + + assertArraysEquals(r, a, Int64VectorTests::unot); + } + + private static final long LONG_MASK_BITS = 0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length()); + + static void assertArraysEquals(long[] r, long[] a, long bits) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], a[i] & bits); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], a[i] & bits, "(" + a[i] + ") at index #" + i); + } + } + + @Test(dataProvider = "longMaskProvider") + static void maskFromToLongInt64VectorTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = new long[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i++) { + VectorMask vmask = VectorMask.fromLong(SPECIES, a[i]); + r[i] = vmask.toLong(); + } + } + assertArraysEquals(r, a, LONG_MASK_BITS); + } + @Test(dataProvider = "intCompareOpProvider") static void ltInt64VectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { int[] a = fa.apply(SPECIES.length()); @@ -6733,115 +6923,22 @@ public class Int64VectorTests extends AbstractVectorTest { } } - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqualsInt64VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskEqualsInt64VectorTests(IntFunction fa, IntFunction fb) { boolean[] a = fa.apply(SPECIES.length()); boolean[] b = fb.apply(SPECIES.length()); - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - boolean equals = av.equals(bv); - int to = i + SPECIES.length(); - Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + var av = SPECIES.loadMask(a, i); + var bv = SPECIES.loadMask(b, i); + boolean equals = av.equals(bv); + int to = i + SPECIES.length(); + Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + } } } - static boolean band(boolean a, boolean b) { - return a & b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndInt64VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.and(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Int64VectorTests::band); - } - - static boolean bor(boolean a, boolean b) { - return a | b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskOrInt64VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.or(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Int64VectorTests::bor); - } - - static boolean bxor(boolean a, boolean b) { - return a != b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskXorInt64VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.xor(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Int64VectorTests::bxor); - } - - static boolean bandNot(boolean a, boolean b) { - return a & !b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndNotInt64VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.andNot(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Int64VectorTests::bandNot); - } - - static boolean beq(boolean a, boolean b) { - return (a == b); - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqInt64VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.eq(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Int64VectorTests::beq); - } - @Test(dataProvider = "maskProvider") static void maskHashCodeInt64VectorTestsSmokeTest(IntFunction fa) { boolean[] a = fa.apply(SPECIES.length()); @@ -6946,23 +7043,6 @@ public class Int64VectorTests extends AbstractVectorTest { } } - @DataProvider - public static Object[][] longMaskProvider() { - return new Object[][]{ - {0xFFFFFFFFFFFFFFFFL}, - {0x0000000000000000L}, - {0x5555555555555555L}, - {0x0123456789abcdefL}, - }; - } - - @Test(dataProvider = "longMaskProvider") - static void maskFromToLongInt64VectorTestsSmokeTest(long inputLong) { - var vmask = VectorMask.fromLong(SPECIES, inputLong); - long outputLong = vmask.toLong(); - Assert.assertEquals(outputLong, (inputLong & (((0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length())))))); - } - @DataProvider public static Object[][] offsetProvider() { return new Object[][]{ diff --git a/test/jdk/jdk/incubator/vector/IntMaxVectorTests.java b/test/jdk/jdk/incubator/vector/IntMaxVectorTests.java index c61aab0013e..67368e0f70e 100644 --- a/test/jdk/jdk/incubator/vector/IntMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/IntMaxVectorTests.java @@ -398,6 +398,36 @@ public class IntMaxVectorTests extends AbstractVectorTest { } } + interface FBoolUnOp { + boolean apply(boolean a); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, FBoolUnOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i]), "(" + a[i] + ") at index #" + i); + } + } + + interface FBoolBinOp { + boolean apply(boolean a, boolean b); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, boolean[] b, FBoolBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b[i]), "(" + a[i] + ", " + b[i] + ") at index #" + i); + } + } + interface FBinOp { int apply(int a, int b); } @@ -1090,12 +1120,6 @@ public class IntMaxVectorTests extends AbstractVectorTest { .flatMap(pair -> INT_SATURATING_GENERATORS_ASSOC.stream().map(f -> List.of(pair.get(0), pair.get(1), f))) .collect(Collectors.toList()); - @DataProvider - public Object[][] boolUnaryOpProvider() { - return BOOL_ARRAY_GENERATORS.stream(). - map(f -> new Object[]{f}). - toArray(Object[][]::new); - } static final List>> INT_GENERATOR_TRIPLES = INT_GENERATOR_PAIRS.stream(). @@ -1227,8 +1251,23 @@ public class IntMaxVectorTests extends AbstractVectorTest { } @DataProvider - public Object[][] maskCompareOpProvider() { - return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream().map(List::toArray). + public Object[][] longMaskProvider() { + return LONG_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskBinaryOpProvider() { + return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream(). + map(List::toArray). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskUnaryOpProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). toArray(Object[][]::new); } @@ -4513,7 +4552,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void anyTrueIntMaxVectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -4537,7 +4576,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void allTrueIntMaxVectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -6439,6 +6478,157 @@ public class IntMaxVectorTests extends AbstractVectorTest { assertArraysEquals(r, a, mask, IntMaxVectorTests::REVERSE_BYTES); } + static boolean band(boolean a, boolean b) { + return a & b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandIntMaxVectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.and(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, IntMaxVectorTests::band); + } + + static boolean bor(boolean a, boolean b) { + return a | b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskorIntMaxVectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.or(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, IntMaxVectorTests::bor); + } + + static boolean bxor(boolean a, boolean b) { + return a != b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskxorIntMaxVectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.xor(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, IntMaxVectorTests::bxor); + } + + static boolean bandNot(boolean a, boolean b) { + return a & !b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandNotIntMaxVectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.andNot(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, IntMaxVectorTests::bandNot); + } + + static boolean beq(boolean a, boolean b) { + return a == b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskeqIntMaxVectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.eq(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, IntMaxVectorTests::beq); + } + + static boolean unot(boolean a) { + return !a; + } + + @Test(dataProvider = "boolMaskUnaryOpProvider") + static void masknotIntMaxVectorTests(IntFunction fa) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + av.not().intoArray(r, i); + } + } + + assertArraysEquals(r, a, IntMaxVectorTests::unot); + } + + private static final long LONG_MASK_BITS = 0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length()); + + static void assertArraysEquals(long[] r, long[] a, long bits) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], a[i] & bits); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], a[i] & bits, "(" + a[i] + ") at index #" + i); + } + } + + @Test(dataProvider = "longMaskProvider") + static void maskFromToLongIntMaxVectorTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = new long[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i++) { + VectorMask vmask = VectorMask.fromLong(SPECIES, a[i]); + r[i] = vmask.toLong(); + } + } + assertArraysEquals(r, a, LONG_MASK_BITS); + } + @Test(dataProvider = "intCompareOpProvider") static void ltIntMaxVectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { int[] a = fa.apply(SPECIES.length()); @@ -6738,115 +6928,22 @@ public class IntMaxVectorTests extends AbstractVectorTest { } } - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqualsIntMaxVectorTestsSmokeTest(IntFunction fa, IntFunction fb) { + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskEqualsIntMaxVectorTests(IntFunction fa, IntFunction fb) { boolean[] a = fa.apply(SPECIES.length()); boolean[] b = fb.apply(SPECIES.length()); - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - boolean equals = av.equals(bv); - int to = i + SPECIES.length(); - Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + var av = SPECIES.loadMask(a, i); + var bv = SPECIES.loadMask(b, i); + boolean equals = av.equals(bv); + int to = i + SPECIES.length(); + Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + } } } - static boolean band(boolean a, boolean b) { - return a & b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndIntMaxVectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.and(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, IntMaxVectorTests::band); - } - - static boolean bor(boolean a, boolean b) { - return a | b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskOrIntMaxVectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.or(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, IntMaxVectorTests::bor); - } - - static boolean bxor(boolean a, boolean b) { - return a != b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskXorIntMaxVectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.xor(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, IntMaxVectorTests::bxor); - } - - static boolean bandNot(boolean a, boolean b) { - return a & !b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndNotIntMaxVectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.andNot(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, IntMaxVectorTests::bandNot); - } - - static boolean beq(boolean a, boolean b) { - return (a == b); - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqIntMaxVectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.eq(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, IntMaxVectorTests::beq); - } - @Test(dataProvider = "maskProvider") static void maskHashCodeIntMaxVectorTestsSmokeTest(IntFunction fa) { boolean[] a = fa.apply(SPECIES.length()); @@ -6951,7 +7048,6 @@ public class IntMaxVectorTests extends AbstractVectorTest { } } - @DataProvider public static Object[][] offsetProvider() { return new Object[][]{ diff --git a/test/jdk/jdk/incubator/vector/Long128VectorTests.java b/test/jdk/jdk/incubator/vector/Long128VectorTests.java index a8cf38c003a..6f91fb9ffbf 100644 --- a/test/jdk/jdk/incubator/vector/Long128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Long128VectorTests.java @@ -350,6 +350,36 @@ public class Long128VectorTests extends AbstractVectorTest { } } + interface FBoolUnOp { + boolean apply(boolean a); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, FBoolUnOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i]), "(" + a[i] + ") at index #" + i); + } + } + + interface FBoolBinOp { + boolean apply(boolean a, boolean b); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, boolean[] b, FBoolBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b[i]), "(" + a[i] + ", " + b[i] + ") at index #" + i); + } + } + interface FBinOp { long apply(long a, long b); } @@ -1075,12 +1105,6 @@ public class Long128VectorTests extends AbstractVectorTest { .flatMap(pair -> LONG_SATURATING_GENERATORS_ASSOC.stream().map(f -> List.of(pair.get(0), pair.get(1), f))) .collect(Collectors.toList()); - @DataProvider - public Object[][] boolUnaryOpProvider() { - return BOOL_ARRAY_GENERATORS.stream(). - map(f -> new Object[]{f}). - toArray(Object[][]::new); - } static final List>> LONG_GENERATOR_TRIPLES = LONG_GENERATOR_PAIRS.stream(). @@ -1219,8 +1243,23 @@ public class Long128VectorTests extends AbstractVectorTest { } @DataProvider - public Object[][] maskCompareOpProvider() { - return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream().map(List::toArray). + public Object[][] longMaskProvider() { + return LONG_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskBinaryOpProvider() { + return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream(). + map(List::toArray). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskUnaryOpProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). toArray(Object[][]::new); } @@ -4530,7 +4569,7 @@ public class Long128VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void anyTrueLong128VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -4554,7 +4593,7 @@ public class Long128VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void allTrueLong128VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -6386,6 +6425,157 @@ public class Long128VectorTests extends AbstractVectorTest { assertArraysEquals(r, a, mask, Long128VectorTests::REVERSE_BYTES); } + static boolean band(boolean a, boolean b) { + return a & b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandLong128VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.and(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Long128VectorTests::band); + } + + static boolean bor(boolean a, boolean b) { + return a | b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskorLong128VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.or(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Long128VectorTests::bor); + } + + static boolean bxor(boolean a, boolean b) { + return a != b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskxorLong128VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.xor(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Long128VectorTests::bxor); + } + + static boolean bandNot(boolean a, boolean b) { + return a & !b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandNotLong128VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.andNot(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Long128VectorTests::bandNot); + } + + static boolean beq(boolean a, boolean b) { + return a == b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskeqLong128VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.eq(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Long128VectorTests::beq); + } + + static boolean unot(boolean a) { + return !a; + } + + @Test(dataProvider = "boolMaskUnaryOpProvider") + static void masknotLong128VectorTests(IntFunction fa) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + av.not().intoArray(r, i); + } + } + + assertArraysEquals(r, a, Long128VectorTests::unot); + } + + private static final long LONG_MASK_BITS = 0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length()); + + static void assertArraysEquals(long[] r, long[] a, long bits) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], a[i] & bits); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], a[i] & bits, "(" + a[i] + ") at index #" + i); + } + } + + @Test(dataProvider = "longMaskProvider") + static void maskFromToLongLong128VectorTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = new long[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i++) { + VectorMask vmask = VectorMask.fromLong(SPECIES, a[i]); + r[i] = vmask.toLong(); + } + } + assertArraysEquals(r, a, LONG_MASK_BITS); + } + @Test(dataProvider = "longCompareOpProvider") static void ltLong128VectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { long[] a = fa.apply(SPECIES.length()); @@ -6619,115 +6809,22 @@ public class Long128VectorTests extends AbstractVectorTest { } } - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqualsLong128VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskEqualsLong128VectorTests(IntFunction fa, IntFunction fb) { boolean[] a = fa.apply(SPECIES.length()); boolean[] b = fb.apply(SPECIES.length()); - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - boolean equals = av.equals(bv); - int to = i + SPECIES.length(); - Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + var av = SPECIES.loadMask(a, i); + var bv = SPECIES.loadMask(b, i); + boolean equals = av.equals(bv); + int to = i + SPECIES.length(); + Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + } } } - static boolean band(boolean a, boolean b) { - return a & b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndLong128VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.and(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Long128VectorTests::band); - } - - static boolean bor(boolean a, boolean b) { - return a | b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskOrLong128VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.or(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Long128VectorTests::bor); - } - - static boolean bxor(boolean a, boolean b) { - return a != b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskXorLong128VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.xor(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Long128VectorTests::bxor); - } - - static boolean bandNot(boolean a, boolean b) { - return a & !b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndNotLong128VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.andNot(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Long128VectorTests::bandNot); - } - - static boolean beq(boolean a, boolean b) { - return (a == b); - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqLong128VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.eq(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Long128VectorTests::beq); - } - @Test(dataProvider = "maskProvider") static void maskHashCodeLong128VectorTestsSmokeTest(IntFunction fa) { boolean[] a = fa.apply(SPECIES.length()); @@ -6832,23 +6929,6 @@ public class Long128VectorTests extends AbstractVectorTest { } } - @DataProvider - public static Object[][] longMaskProvider() { - return new Object[][]{ - {0xFFFFFFFFFFFFFFFFL}, - {0x0000000000000000L}, - {0x5555555555555555L}, - {0x0123456789abcdefL}, - }; - } - - @Test(dataProvider = "longMaskProvider") - static void maskFromToLongLong128VectorTestsSmokeTest(long inputLong) { - var vmask = VectorMask.fromLong(SPECIES, inputLong); - long outputLong = vmask.toLong(); - Assert.assertEquals(outputLong, (inputLong & (((0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length())))))); - } - @DataProvider public static Object[][] offsetProvider() { return new Object[][]{ diff --git a/test/jdk/jdk/incubator/vector/Long256VectorTests.java b/test/jdk/jdk/incubator/vector/Long256VectorTests.java index a394a59699f..118c955ad24 100644 --- a/test/jdk/jdk/incubator/vector/Long256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Long256VectorTests.java @@ -350,6 +350,36 @@ public class Long256VectorTests extends AbstractVectorTest { } } + interface FBoolUnOp { + boolean apply(boolean a); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, FBoolUnOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i]), "(" + a[i] + ") at index #" + i); + } + } + + interface FBoolBinOp { + boolean apply(boolean a, boolean b); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, boolean[] b, FBoolBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b[i]), "(" + a[i] + ", " + b[i] + ") at index #" + i); + } + } + interface FBinOp { long apply(long a, long b); } @@ -1075,12 +1105,6 @@ public class Long256VectorTests extends AbstractVectorTest { .flatMap(pair -> LONG_SATURATING_GENERATORS_ASSOC.stream().map(f -> List.of(pair.get(0), pair.get(1), f))) .collect(Collectors.toList()); - @DataProvider - public Object[][] boolUnaryOpProvider() { - return BOOL_ARRAY_GENERATORS.stream(). - map(f -> new Object[]{f}). - toArray(Object[][]::new); - } static final List>> LONG_GENERATOR_TRIPLES = LONG_GENERATOR_PAIRS.stream(). @@ -1219,8 +1243,23 @@ public class Long256VectorTests extends AbstractVectorTest { } @DataProvider - public Object[][] maskCompareOpProvider() { - return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream().map(List::toArray). + public Object[][] longMaskProvider() { + return LONG_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskBinaryOpProvider() { + return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream(). + map(List::toArray). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskUnaryOpProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). toArray(Object[][]::new); } @@ -4530,7 +4569,7 @@ public class Long256VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void anyTrueLong256VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -4554,7 +4593,7 @@ public class Long256VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void allTrueLong256VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -6386,6 +6425,157 @@ public class Long256VectorTests extends AbstractVectorTest { assertArraysEquals(r, a, mask, Long256VectorTests::REVERSE_BYTES); } + static boolean band(boolean a, boolean b) { + return a & b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandLong256VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.and(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Long256VectorTests::band); + } + + static boolean bor(boolean a, boolean b) { + return a | b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskorLong256VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.or(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Long256VectorTests::bor); + } + + static boolean bxor(boolean a, boolean b) { + return a != b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskxorLong256VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.xor(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Long256VectorTests::bxor); + } + + static boolean bandNot(boolean a, boolean b) { + return a & !b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandNotLong256VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.andNot(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Long256VectorTests::bandNot); + } + + static boolean beq(boolean a, boolean b) { + return a == b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskeqLong256VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.eq(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Long256VectorTests::beq); + } + + static boolean unot(boolean a) { + return !a; + } + + @Test(dataProvider = "boolMaskUnaryOpProvider") + static void masknotLong256VectorTests(IntFunction fa) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + av.not().intoArray(r, i); + } + } + + assertArraysEquals(r, a, Long256VectorTests::unot); + } + + private static final long LONG_MASK_BITS = 0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length()); + + static void assertArraysEquals(long[] r, long[] a, long bits) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], a[i] & bits); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], a[i] & bits, "(" + a[i] + ") at index #" + i); + } + } + + @Test(dataProvider = "longMaskProvider") + static void maskFromToLongLong256VectorTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = new long[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i++) { + VectorMask vmask = VectorMask.fromLong(SPECIES, a[i]); + r[i] = vmask.toLong(); + } + } + assertArraysEquals(r, a, LONG_MASK_BITS); + } + @Test(dataProvider = "longCompareOpProvider") static void ltLong256VectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { long[] a = fa.apply(SPECIES.length()); @@ -6619,115 +6809,22 @@ public class Long256VectorTests extends AbstractVectorTest { } } - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqualsLong256VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskEqualsLong256VectorTests(IntFunction fa, IntFunction fb) { boolean[] a = fa.apply(SPECIES.length()); boolean[] b = fb.apply(SPECIES.length()); - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - boolean equals = av.equals(bv); - int to = i + SPECIES.length(); - Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + var av = SPECIES.loadMask(a, i); + var bv = SPECIES.loadMask(b, i); + boolean equals = av.equals(bv); + int to = i + SPECIES.length(); + Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + } } } - static boolean band(boolean a, boolean b) { - return a & b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndLong256VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.and(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Long256VectorTests::band); - } - - static boolean bor(boolean a, boolean b) { - return a | b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskOrLong256VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.or(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Long256VectorTests::bor); - } - - static boolean bxor(boolean a, boolean b) { - return a != b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskXorLong256VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.xor(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Long256VectorTests::bxor); - } - - static boolean bandNot(boolean a, boolean b) { - return a & !b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndNotLong256VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.andNot(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Long256VectorTests::bandNot); - } - - static boolean beq(boolean a, boolean b) { - return (a == b); - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqLong256VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.eq(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Long256VectorTests::beq); - } - @Test(dataProvider = "maskProvider") static void maskHashCodeLong256VectorTestsSmokeTest(IntFunction fa) { boolean[] a = fa.apply(SPECIES.length()); @@ -6832,23 +6929,6 @@ public class Long256VectorTests extends AbstractVectorTest { } } - @DataProvider - public static Object[][] longMaskProvider() { - return new Object[][]{ - {0xFFFFFFFFFFFFFFFFL}, - {0x0000000000000000L}, - {0x5555555555555555L}, - {0x0123456789abcdefL}, - }; - } - - @Test(dataProvider = "longMaskProvider") - static void maskFromToLongLong256VectorTestsSmokeTest(long inputLong) { - var vmask = VectorMask.fromLong(SPECIES, inputLong); - long outputLong = vmask.toLong(); - Assert.assertEquals(outputLong, (inputLong & (((0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length())))))); - } - @DataProvider public static Object[][] offsetProvider() { return new Object[][]{ diff --git a/test/jdk/jdk/incubator/vector/Long512VectorTests.java b/test/jdk/jdk/incubator/vector/Long512VectorTests.java index 2f12ea98399..1bca0ef0ebd 100644 --- a/test/jdk/jdk/incubator/vector/Long512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Long512VectorTests.java @@ -350,6 +350,36 @@ public class Long512VectorTests extends AbstractVectorTest { } } + interface FBoolUnOp { + boolean apply(boolean a); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, FBoolUnOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i]), "(" + a[i] + ") at index #" + i); + } + } + + interface FBoolBinOp { + boolean apply(boolean a, boolean b); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, boolean[] b, FBoolBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b[i]), "(" + a[i] + ", " + b[i] + ") at index #" + i); + } + } + interface FBinOp { long apply(long a, long b); } @@ -1075,12 +1105,6 @@ public class Long512VectorTests extends AbstractVectorTest { .flatMap(pair -> LONG_SATURATING_GENERATORS_ASSOC.stream().map(f -> List.of(pair.get(0), pair.get(1), f))) .collect(Collectors.toList()); - @DataProvider - public Object[][] boolUnaryOpProvider() { - return BOOL_ARRAY_GENERATORS.stream(). - map(f -> new Object[]{f}). - toArray(Object[][]::new); - } static final List>> LONG_GENERATOR_TRIPLES = LONG_GENERATOR_PAIRS.stream(). @@ -1219,8 +1243,23 @@ public class Long512VectorTests extends AbstractVectorTest { } @DataProvider - public Object[][] maskCompareOpProvider() { - return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream().map(List::toArray). + public Object[][] longMaskProvider() { + return LONG_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskBinaryOpProvider() { + return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream(). + map(List::toArray). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskUnaryOpProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). toArray(Object[][]::new); } @@ -4530,7 +4569,7 @@ public class Long512VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void anyTrueLong512VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -4554,7 +4593,7 @@ public class Long512VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void allTrueLong512VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -6386,6 +6425,157 @@ public class Long512VectorTests extends AbstractVectorTest { assertArraysEquals(r, a, mask, Long512VectorTests::REVERSE_BYTES); } + static boolean band(boolean a, boolean b) { + return a & b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandLong512VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.and(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Long512VectorTests::band); + } + + static boolean bor(boolean a, boolean b) { + return a | b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskorLong512VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.or(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Long512VectorTests::bor); + } + + static boolean bxor(boolean a, boolean b) { + return a != b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskxorLong512VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.xor(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Long512VectorTests::bxor); + } + + static boolean bandNot(boolean a, boolean b) { + return a & !b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandNotLong512VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.andNot(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Long512VectorTests::bandNot); + } + + static boolean beq(boolean a, boolean b) { + return a == b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskeqLong512VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.eq(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Long512VectorTests::beq); + } + + static boolean unot(boolean a) { + return !a; + } + + @Test(dataProvider = "boolMaskUnaryOpProvider") + static void masknotLong512VectorTests(IntFunction fa) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + av.not().intoArray(r, i); + } + } + + assertArraysEquals(r, a, Long512VectorTests::unot); + } + + private static final long LONG_MASK_BITS = 0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length()); + + static void assertArraysEquals(long[] r, long[] a, long bits) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], a[i] & bits); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], a[i] & bits, "(" + a[i] + ") at index #" + i); + } + } + + @Test(dataProvider = "longMaskProvider") + static void maskFromToLongLong512VectorTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = new long[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i++) { + VectorMask vmask = VectorMask.fromLong(SPECIES, a[i]); + r[i] = vmask.toLong(); + } + } + assertArraysEquals(r, a, LONG_MASK_BITS); + } + @Test(dataProvider = "longCompareOpProvider") static void ltLong512VectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { long[] a = fa.apply(SPECIES.length()); @@ -6619,115 +6809,22 @@ public class Long512VectorTests extends AbstractVectorTest { } } - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqualsLong512VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskEqualsLong512VectorTests(IntFunction fa, IntFunction fb) { boolean[] a = fa.apply(SPECIES.length()); boolean[] b = fb.apply(SPECIES.length()); - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - boolean equals = av.equals(bv); - int to = i + SPECIES.length(); - Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + var av = SPECIES.loadMask(a, i); + var bv = SPECIES.loadMask(b, i); + boolean equals = av.equals(bv); + int to = i + SPECIES.length(); + Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + } } } - static boolean band(boolean a, boolean b) { - return a & b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndLong512VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.and(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Long512VectorTests::band); - } - - static boolean bor(boolean a, boolean b) { - return a | b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskOrLong512VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.or(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Long512VectorTests::bor); - } - - static boolean bxor(boolean a, boolean b) { - return a != b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskXorLong512VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.xor(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Long512VectorTests::bxor); - } - - static boolean bandNot(boolean a, boolean b) { - return a & !b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndNotLong512VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.andNot(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Long512VectorTests::bandNot); - } - - static boolean beq(boolean a, boolean b) { - return (a == b); - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqLong512VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.eq(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Long512VectorTests::beq); - } - @Test(dataProvider = "maskProvider") static void maskHashCodeLong512VectorTestsSmokeTest(IntFunction fa) { boolean[] a = fa.apply(SPECIES.length()); @@ -6832,23 +6929,6 @@ public class Long512VectorTests extends AbstractVectorTest { } } - @DataProvider - public static Object[][] longMaskProvider() { - return new Object[][]{ - {0xFFFFFFFFFFFFFFFFL}, - {0x0000000000000000L}, - {0x5555555555555555L}, - {0x0123456789abcdefL}, - }; - } - - @Test(dataProvider = "longMaskProvider") - static void maskFromToLongLong512VectorTestsSmokeTest(long inputLong) { - var vmask = VectorMask.fromLong(SPECIES, inputLong); - long outputLong = vmask.toLong(); - Assert.assertEquals(outputLong, (inputLong & (((0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length())))))); - } - @DataProvider public static Object[][] offsetProvider() { return new Object[][]{ diff --git a/test/jdk/jdk/incubator/vector/Long64VectorTests.java b/test/jdk/jdk/incubator/vector/Long64VectorTests.java index 0fda0abed58..212bbb5047c 100644 --- a/test/jdk/jdk/incubator/vector/Long64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Long64VectorTests.java @@ -350,6 +350,36 @@ public class Long64VectorTests extends AbstractVectorTest { } } + interface FBoolUnOp { + boolean apply(boolean a); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, FBoolUnOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i]), "(" + a[i] + ") at index #" + i); + } + } + + interface FBoolBinOp { + boolean apply(boolean a, boolean b); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, boolean[] b, FBoolBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b[i]), "(" + a[i] + ", " + b[i] + ") at index #" + i); + } + } + interface FBinOp { long apply(long a, long b); } @@ -1075,12 +1105,6 @@ public class Long64VectorTests extends AbstractVectorTest { .flatMap(pair -> LONG_SATURATING_GENERATORS_ASSOC.stream().map(f -> List.of(pair.get(0), pair.get(1), f))) .collect(Collectors.toList()); - @DataProvider - public Object[][] boolUnaryOpProvider() { - return BOOL_ARRAY_GENERATORS.stream(). - map(f -> new Object[]{f}). - toArray(Object[][]::new); - } static final List>> LONG_GENERATOR_TRIPLES = LONG_GENERATOR_PAIRS.stream(). @@ -1219,8 +1243,23 @@ public class Long64VectorTests extends AbstractVectorTest { } @DataProvider - public Object[][] maskCompareOpProvider() { - return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream().map(List::toArray). + public Object[][] longMaskProvider() { + return LONG_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskBinaryOpProvider() { + return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream(). + map(List::toArray). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskUnaryOpProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). toArray(Object[][]::new); } @@ -4530,7 +4569,7 @@ public class Long64VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void anyTrueLong64VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -4554,7 +4593,7 @@ public class Long64VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void allTrueLong64VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -6386,6 +6425,157 @@ public class Long64VectorTests extends AbstractVectorTest { assertArraysEquals(r, a, mask, Long64VectorTests::REVERSE_BYTES); } + static boolean band(boolean a, boolean b) { + return a & b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandLong64VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.and(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Long64VectorTests::band); + } + + static boolean bor(boolean a, boolean b) { + return a | b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskorLong64VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.or(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Long64VectorTests::bor); + } + + static boolean bxor(boolean a, boolean b) { + return a != b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskxorLong64VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.xor(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Long64VectorTests::bxor); + } + + static boolean bandNot(boolean a, boolean b) { + return a & !b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandNotLong64VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.andNot(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Long64VectorTests::bandNot); + } + + static boolean beq(boolean a, boolean b) { + return a == b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskeqLong64VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.eq(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Long64VectorTests::beq); + } + + static boolean unot(boolean a) { + return !a; + } + + @Test(dataProvider = "boolMaskUnaryOpProvider") + static void masknotLong64VectorTests(IntFunction fa) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + av.not().intoArray(r, i); + } + } + + assertArraysEquals(r, a, Long64VectorTests::unot); + } + + private static final long LONG_MASK_BITS = 0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length()); + + static void assertArraysEquals(long[] r, long[] a, long bits) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], a[i] & bits); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], a[i] & bits, "(" + a[i] + ") at index #" + i); + } + } + + @Test(dataProvider = "longMaskProvider") + static void maskFromToLongLong64VectorTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = new long[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i++) { + VectorMask vmask = VectorMask.fromLong(SPECIES, a[i]); + r[i] = vmask.toLong(); + } + } + assertArraysEquals(r, a, LONG_MASK_BITS); + } + @Test(dataProvider = "longCompareOpProvider") static void ltLong64VectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { long[] a = fa.apply(SPECIES.length()); @@ -6619,115 +6809,22 @@ public class Long64VectorTests extends AbstractVectorTest { } } - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqualsLong64VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskEqualsLong64VectorTests(IntFunction fa, IntFunction fb) { boolean[] a = fa.apply(SPECIES.length()); boolean[] b = fb.apply(SPECIES.length()); - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - boolean equals = av.equals(bv); - int to = i + SPECIES.length(); - Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + var av = SPECIES.loadMask(a, i); + var bv = SPECIES.loadMask(b, i); + boolean equals = av.equals(bv); + int to = i + SPECIES.length(); + Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + } } } - static boolean band(boolean a, boolean b) { - return a & b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndLong64VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.and(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Long64VectorTests::band); - } - - static boolean bor(boolean a, boolean b) { - return a | b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskOrLong64VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.or(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Long64VectorTests::bor); - } - - static boolean bxor(boolean a, boolean b) { - return a != b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskXorLong64VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.xor(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Long64VectorTests::bxor); - } - - static boolean bandNot(boolean a, boolean b) { - return a & !b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndNotLong64VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.andNot(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Long64VectorTests::bandNot); - } - - static boolean beq(boolean a, boolean b) { - return (a == b); - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqLong64VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.eq(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Long64VectorTests::beq); - } - @Test(dataProvider = "maskProvider") static void maskHashCodeLong64VectorTestsSmokeTest(IntFunction fa) { boolean[] a = fa.apply(SPECIES.length()); @@ -6832,23 +6929,6 @@ public class Long64VectorTests extends AbstractVectorTest { } } - @DataProvider - public static Object[][] longMaskProvider() { - return new Object[][]{ - {0xFFFFFFFFFFFFFFFFL}, - {0x0000000000000000L}, - {0x5555555555555555L}, - {0x0123456789abcdefL}, - }; - } - - @Test(dataProvider = "longMaskProvider") - static void maskFromToLongLong64VectorTestsSmokeTest(long inputLong) { - var vmask = VectorMask.fromLong(SPECIES, inputLong); - long outputLong = vmask.toLong(); - Assert.assertEquals(outputLong, (inputLong & (((0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length())))))); - } - @DataProvider public static Object[][] offsetProvider() { return new Object[][]{ diff --git a/test/jdk/jdk/incubator/vector/LongMaxVectorTests.java b/test/jdk/jdk/incubator/vector/LongMaxVectorTests.java index 7aa2bc4c510..3eba905e4f8 100644 --- a/test/jdk/jdk/incubator/vector/LongMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/LongMaxVectorTests.java @@ -355,6 +355,36 @@ public class LongMaxVectorTests extends AbstractVectorTest { } } + interface FBoolUnOp { + boolean apply(boolean a); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, FBoolUnOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i]), "(" + a[i] + ") at index #" + i); + } + } + + interface FBoolBinOp { + boolean apply(boolean a, boolean b); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, boolean[] b, FBoolBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b[i]), "(" + a[i] + ", " + b[i] + ") at index #" + i); + } + } + interface FBinOp { long apply(long a, long b); } @@ -1080,12 +1110,6 @@ public class LongMaxVectorTests extends AbstractVectorTest { .flatMap(pair -> LONG_SATURATING_GENERATORS_ASSOC.stream().map(f -> List.of(pair.get(0), pair.get(1), f))) .collect(Collectors.toList()); - @DataProvider - public Object[][] boolUnaryOpProvider() { - return BOOL_ARRAY_GENERATORS.stream(). - map(f -> new Object[]{f}). - toArray(Object[][]::new); - } static final List>> LONG_GENERATOR_TRIPLES = LONG_GENERATOR_PAIRS.stream(). @@ -1224,8 +1248,23 @@ public class LongMaxVectorTests extends AbstractVectorTest { } @DataProvider - public Object[][] maskCompareOpProvider() { - return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream().map(List::toArray). + public Object[][] longMaskProvider() { + return LONG_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskBinaryOpProvider() { + return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream(). + map(List::toArray). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskUnaryOpProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). toArray(Object[][]::new); } @@ -4535,7 +4574,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void anyTrueLongMaxVectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -4559,7 +4598,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void allTrueLongMaxVectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -6391,6 +6430,157 @@ public class LongMaxVectorTests extends AbstractVectorTest { assertArraysEquals(r, a, mask, LongMaxVectorTests::REVERSE_BYTES); } + static boolean band(boolean a, boolean b) { + return a & b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandLongMaxVectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.and(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, LongMaxVectorTests::band); + } + + static boolean bor(boolean a, boolean b) { + return a | b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskorLongMaxVectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.or(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, LongMaxVectorTests::bor); + } + + static boolean bxor(boolean a, boolean b) { + return a != b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskxorLongMaxVectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.xor(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, LongMaxVectorTests::bxor); + } + + static boolean bandNot(boolean a, boolean b) { + return a & !b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandNotLongMaxVectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.andNot(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, LongMaxVectorTests::bandNot); + } + + static boolean beq(boolean a, boolean b) { + return a == b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskeqLongMaxVectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.eq(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, LongMaxVectorTests::beq); + } + + static boolean unot(boolean a) { + return !a; + } + + @Test(dataProvider = "boolMaskUnaryOpProvider") + static void masknotLongMaxVectorTests(IntFunction fa) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + av.not().intoArray(r, i); + } + } + + assertArraysEquals(r, a, LongMaxVectorTests::unot); + } + + private static final long LONG_MASK_BITS = 0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length()); + + static void assertArraysEquals(long[] r, long[] a, long bits) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], a[i] & bits); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], a[i] & bits, "(" + a[i] + ") at index #" + i); + } + } + + @Test(dataProvider = "longMaskProvider") + static void maskFromToLongLongMaxVectorTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = new long[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i++) { + VectorMask vmask = VectorMask.fromLong(SPECIES, a[i]); + r[i] = vmask.toLong(); + } + } + assertArraysEquals(r, a, LONG_MASK_BITS); + } + @Test(dataProvider = "longCompareOpProvider") static void ltLongMaxVectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { long[] a = fa.apply(SPECIES.length()); @@ -6624,115 +6814,22 @@ public class LongMaxVectorTests extends AbstractVectorTest { } } - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqualsLongMaxVectorTestsSmokeTest(IntFunction fa, IntFunction fb) { + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskEqualsLongMaxVectorTests(IntFunction fa, IntFunction fb) { boolean[] a = fa.apply(SPECIES.length()); boolean[] b = fb.apply(SPECIES.length()); - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - boolean equals = av.equals(bv); - int to = i + SPECIES.length(); - Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + var av = SPECIES.loadMask(a, i); + var bv = SPECIES.loadMask(b, i); + boolean equals = av.equals(bv); + int to = i + SPECIES.length(); + Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + } } } - static boolean band(boolean a, boolean b) { - return a & b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndLongMaxVectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.and(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, LongMaxVectorTests::band); - } - - static boolean bor(boolean a, boolean b) { - return a | b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskOrLongMaxVectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.or(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, LongMaxVectorTests::bor); - } - - static boolean bxor(boolean a, boolean b) { - return a != b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskXorLongMaxVectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.xor(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, LongMaxVectorTests::bxor); - } - - static boolean bandNot(boolean a, boolean b) { - return a & !b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndNotLongMaxVectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.andNot(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, LongMaxVectorTests::bandNot); - } - - static boolean beq(boolean a, boolean b) { - return (a == b); - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqLongMaxVectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.eq(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, LongMaxVectorTests::beq); - } - @Test(dataProvider = "maskProvider") static void maskHashCodeLongMaxVectorTestsSmokeTest(IntFunction fa) { boolean[] a = fa.apply(SPECIES.length()); @@ -6837,7 +6934,6 @@ public class LongMaxVectorTests extends AbstractVectorTest { } } - @DataProvider public static Object[][] offsetProvider() { return new Object[][]{ diff --git a/test/jdk/jdk/incubator/vector/Short128VectorTests.java b/test/jdk/jdk/incubator/vector/Short128VectorTests.java index 5f4c54bb708..50be26b163a 100644 --- a/test/jdk/jdk/incubator/vector/Short128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Short128VectorTests.java @@ -393,6 +393,36 @@ public class Short128VectorTests extends AbstractVectorTest { } } + interface FBoolUnOp { + boolean apply(boolean a); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, FBoolUnOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i]), "(" + a[i] + ") at index #" + i); + } + } + + interface FBoolBinOp { + boolean apply(boolean a, boolean b); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, boolean[] b, FBoolBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b[i]), "(" + a[i] + ", " + b[i] + ") at index #" + i); + } + } + interface FBinOp { short apply(short a, short b); } @@ -1085,12 +1115,6 @@ public class Short128VectorTests extends AbstractVectorTest { .flatMap(pair -> SHORT_SATURATING_GENERATORS_ASSOC.stream().map(f -> List.of(pair.get(0), pair.get(1), f))) .collect(Collectors.toList()); - @DataProvider - public Object[][] boolUnaryOpProvider() { - return BOOL_ARRAY_GENERATORS.stream(). - map(f -> new Object[]{f}). - toArray(Object[][]::new); - } static final List>> SHORT_GENERATOR_TRIPLES = SHORT_GENERATOR_PAIRS.stream(). @@ -1222,8 +1246,23 @@ public class Short128VectorTests extends AbstractVectorTest { } @DataProvider - public Object[][] maskCompareOpProvider() { - return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream().map(List::toArray). + public Object[][] longMaskProvider() { + return LONG_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskBinaryOpProvider() { + return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream(). + map(List::toArray). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskUnaryOpProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). toArray(Object[][]::new); } @@ -4455,7 +4494,7 @@ public class Short128VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void anyTrueShort128VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -4479,7 +4518,7 @@ public class Short128VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void allTrueShort128VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -6381,6 +6420,157 @@ public class Short128VectorTests extends AbstractVectorTest { assertArraysEquals(r, a, mask, Short128VectorTests::REVERSE_BYTES); } + static boolean band(boolean a, boolean b) { + return a & b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandShort128VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.and(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Short128VectorTests::band); + } + + static boolean bor(boolean a, boolean b) { + return a | b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskorShort128VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.or(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Short128VectorTests::bor); + } + + static boolean bxor(boolean a, boolean b) { + return a != b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskxorShort128VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.xor(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Short128VectorTests::bxor); + } + + static boolean bandNot(boolean a, boolean b) { + return a & !b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandNotShort128VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.andNot(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Short128VectorTests::bandNot); + } + + static boolean beq(boolean a, boolean b) { + return a == b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskeqShort128VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.eq(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Short128VectorTests::beq); + } + + static boolean unot(boolean a) { + return !a; + } + + @Test(dataProvider = "boolMaskUnaryOpProvider") + static void masknotShort128VectorTests(IntFunction fa) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + av.not().intoArray(r, i); + } + } + + assertArraysEquals(r, a, Short128VectorTests::unot); + } + + private static final long LONG_MASK_BITS = 0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length()); + + static void assertArraysEquals(long[] r, long[] a, long bits) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], a[i] & bits); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], a[i] & bits, "(" + a[i] + ") at index #" + i); + } + } + + @Test(dataProvider = "longMaskProvider") + static void maskFromToLongShort128VectorTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = new long[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i++) { + VectorMask vmask = VectorMask.fromLong(SPECIES, a[i]); + r[i] = vmask.toLong(); + } + } + assertArraysEquals(r, a, LONG_MASK_BITS); + } + @Test(dataProvider = "shortCompareOpProvider") static void ltShort128VectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { short[] a = fa.apply(SPECIES.length()); @@ -6680,115 +6870,22 @@ public class Short128VectorTests extends AbstractVectorTest { } } - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqualsShort128VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskEqualsShort128VectorTests(IntFunction fa, IntFunction fb) { boolean[] a = fa.apply(SPECIES.length()); boolean[] b = fb.apply(SPECIES.length()); - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - boolean equals = av.equals(bv); - int to = i + SPECIES.length(); - Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + var av = SPECIES.loadMask(a, i); + var bv = SPECIES.loadMask(b, i); + boolean equals = av.equals(bv); + int to = i + SPECIES.length(); + Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + } } } - static boolean band(boolean a, boolean b) { - return a & b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndShort128VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.and(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Short128VectorTests::band); - } - - static boolean bor(boolean a, boolean b) { - return a | b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskOrShort128VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.or(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Short128VectorTests::bor); - } - - static boolean bxor(boolean a, boolean b) { - return a != b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskXorShort128VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.xor(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Short128VectorTests::bxor); - } - - static boolean bandNot(boolean a, boolean b) { - return a & !b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndNotShort128VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.andNot(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Short128VectorTests::bandNot); - } - - static boolean beq(boolean a, boolean b) { - return (a == b); - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqShort128VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.eq(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Short128VectorTests::beq); - } - @Test(dataProvider = "maskProvider") static void maskHashCodeShort128VectorTestsSmokeTest(IntFunction fa) { boolean[] a = fa.apply(SPECIES.length()); @@ -6893,23 +6990,6 @@ public class Short128VectorTests extends AbstractVectorTest { } } - @DataProvider - public static Object[][] longMaskProvider() { - return new Object[][]{ - {0xFFFFFFFFFFFFFFFFL}, - {0x0000000000000000L}, - {0x5555555555555555L}, - {0x0123456789abcdefL}, - }; - } - - @Test(dataProvider = "longMaskProvider") - static void maskFromToLongShort128VectorTestsSmokeTest(long inputLong) { - var vmask = VectorMask.fromLong(SPECIES, inputLong); - long outputLong = vmask.toLong(); - Assert.assertEquals(outputLong, (inputLong & (((0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length())))))); - } - @DataProvider public static Object[][] offsetProvider() { return new Object[][]{ diff --git a/test/jdk/jdk/incubator/vector/Short256VectorTests.java b/test/jdk/jdk/incubator/vector/Short256VectorTests.java index 88986575f60..5f63164755b 100644 --- a/test/jdk/jdk/incubator/vector/Short256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Short256VectorTests.java @@ -393,6 +393,36 @@ public class Short256VectorTests extends AbstractVectorTest { } } + interface FBoolUnOp { + boolean apply(boolean a); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, FBoolUnOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i]), "(" + a[i] + ") at index #" + i); + } + } + + interface FBoolBinOp { + boolean apply(boolean a, boolean b); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, boolean[] b, FBoolBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b[i]), "(" + a[i] + ", " + b[i] + ") at index #" + i); + } + } + interface FBinOp { short apply(short a, short b); } @@ -1085,12 +1115,6 @@ public class Short256VectorTests extends AbstractVectorTest { .flatMap(pair -> SHORT_SATURATING_GENERATORS_ASSOC.stream().map(f -> List.of(pair.get(0), pair.get(1), f))) .collect(Collectors.toList()); - @DataProvider - public Object[][] boolUnaryOpProvider() { - return BOOL_ARRAY_GENERATORS.stream(). - map(f -> new Object[]{f}). - toArray(Object[][]::new); - } static final List>> SHORT_GENERATOR_TRIPLES = SHORT_GENERATOR_PAIRS.stream(). @@ -1222,8 +1246,23 @@ public class Short256VectorTests extends AbstractVectorTest { } @DataProvider - public Object[][] maskCompareOpProvider() { - return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream().map(List::toArray). + public Object[][] longMaskProvider() { + return LONG_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskBinaryOpProvider() { + return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream(). + map(List::toArray). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskUnaryOpProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). toArray(Object[][]::new); } @@ -4455,7 +4494,7 @@ public class Short256VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void anyTrueShort256VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -4479,7 +4518,7 @@ public class Short256VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void allTrueShort256VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -6381,6 +6420,157 @@ public class Short256VectorTests extends AbstractVectorTest { assertArraysEquals(r, a, mask, Short256VectorTests::REVERSE_BYTES); } + static boolean band(boolean a, boolean b) { + return a & b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandShort256VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.and(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Short256VectorTests::band); + } + + static boolean bor(boolean a, boolean b) { + return a | b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskorShort256VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.or(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Short256VectorTests::bor); + } + + static boolean bxor(boolean a, boolean b) { + return a != b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskxorShort256VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.xor(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Short256VectorTests::bxor); + } + + static boolean bandNot(boolean a, boolean b) { + return a & !b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandNotShort256VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.andNot(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Short256VectorTests::bandNot); + } + + static boolean beq(boolean a, boolean b) { + return a == b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskeqShort256VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.eq(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Short256VectorTests::beq); + } + + static boolean unot(boolean a) { + return !a; + } + + @Test(dataProvider = "boolMaskUnaryOpProvider") + static void masknotShort256VectorTests(IntFunction fa) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + av.not().intoArray(r, i); + } + } + + assertArraysEquals(r, a, Short256VectorTests::unot); + } + + private static final long LONG_MASK_BITS = 0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length()); + + static void assertArraysEquals(long[] r, long[] a, long bits) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], a[i] & bits); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], a[i] & bits, "(" + a[i] + ") at index #" + i); + } + } + + @Test(dataProvider = "longMaskProvider") + static void maskFromToLongShort256VectorTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = new long[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i++) { + VectorMask vmask = VectorMask.fromLong(SPECIES, a[i]); + r[i] = vmask.toLong(); + } + } + assertArraysEquals(r, a, LONG_MASK_BITS); + } + @Test(dataProvider = "shortCompareOpProvider") static void ltShort256VectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { short[] a = fa.apply(SPECIES.length()); @@ -6680,115 +6870,22 @@ public class Short256VectorTests extends AbstractVectorTest { } } - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqualsShort256VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskEqualsShort256VectorTests(IntFunction fa, IntFunction fb) { boolean[] a = fa.apply(SPECIES.length()); boolean[] b = fb.apply(SPECIES.length()); - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - boolean equals = av.equals(bv); - int to = i + SPECIES.length(); - Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + var av = SPECIES.loadMask(a, i); + var bv = SPECIES.loadMask(b, i); + boolean equals = av.equals(bv); + int to = i + SPECIES.length(); + Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + } } } - static boolean band(boolean a, boolean b) { - return a & b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndShort256VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.and(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Short256VectorTests::band); - } - - static boolean bor(boolean a, boolean b) { - return a | b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskOrShort256VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.or(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Short256VectorTests::bor); - } - - static boolean bxor(boolean a, boolean b) { - return a != b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskXorShort256VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.xor(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Short256VectorTests::bxor); - } - - static boolean bandNot(boolean a, boolean b) { - return a & !b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndNotShort256VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.andNot(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Short256VectorTests::bandNot); - } - - static boolean beq(boolean a, boolean b) { - return (a == b); - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqShort256VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.eq(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Short256VectorTests::beq); - } - @Test(dataProvider = "maskProvider") static void maskHashCodeShort256VectorTestsSmokeTest(IntFunction fa) { boolean[] a = fa.apply(SPECIES.length()); @@ -6893,23 +6990,6 @@ public class Short256VectorTests extends AbstractVectorTest { } } - @DataProvider - public static Object[][] longMaskProvider() { - return new Object[][]{ - {0xFFFFFFFFFFFFFFFFL}, - {0x0000000000000000L}, - {0x5555555555555555L}, - {0x0123456789abcdefL}, - }; - } - - @Test(dataProvider = "longMaskProvider") - static void maskFromToLongShort256VectorTestsSmokeTest(long inputLong) { - var vmask = VectorMask.fromLong(SPECIES, inputLong); - long outputLong = vmask.toLong(); - Assert.assertEquals(outputLong, (inputLong & (((0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length())))))); - } - @DataProvider public static Object[][] offsetProvider() { return new Object[][]{ diff --git a/test/jdk/jdk/incubator/vector/Short512VectorTests.java b/test/jdk/jdk/incubator/vector/Short512VectorTests.java index 0f474375a47..5044f8db482 100644 --- a/test/jdk/jdk/incubator/vector/Short512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Short512VectorTests.java @@ -393,6 +393,36 @@ public class Short512VectorTests extends AbstractVectorTest { } } + interface FBoolUnOp { + boolean apply(boolean a); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, FBoolUnOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i]), "(" + a[i] + ") at index #" + i); + } + } + + interface FBoolBinOp { + boolean apply(boolean a, boolean b); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, boolean[] b, FBoolBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b[i]), "(" + a[i] + ", " + b[i] + ") at index #" + i); + } + } + interface FBinOp { short apply(short a, short b); } @@ -1085,12 +1115,6 @@ public class Short512VectorTests extends AbstractVectorTest { .flatMap(pair -> SHORT_SATURATING_GENERATORS_ASSOC.stream().map(f -> List.of(pair.get(0), pair.get(1), f))) .collect(Collectors.toList()); - @DataProvider - public Object[][] boolUnaryOpProvider() { - return BOOL_ARRAY_GENERATORS.stream(). - map(f -> new Object[]{f}). - toArray(Object[][]::new); - } static final List>> SHORT_GENERATOR_TRIPLES = SHORT_GENERATOR_PAIRS.stream(). @@ -1222,8 +1246,23 @@ public class Short512VectorTests extends AbstractVectorTest { } @DataProvider - public Object[][] maskCompareOpProvider() { - return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream().map(List::toArray). + public Object[][] longMaskProvider() { + return LONG_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskBinaryOpProvider() { + return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream(). + map(List::toArray). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskUnaryOpProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). toArray(Object[][]::new); } @@ -4455,7 +4494,7 @@ public class Short512VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void anyTrueShort512VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -4479,7 +4518,7 @@ public class Short512VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void allTrueShort512VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -6381,6 +6420,157 @@ public class Short512VectorTests extends AbstractVectorTest { assertArraysEquals(r, a, mask, Short512VectorTests::REVERSE_BYTES); } + static boolean band(boolean a, boolean b) { + return a & b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandShort512VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.and(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Short512VectorTests::band); + } + + static boolean bor(boolean a, boolean b) { + return a | b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskorShort512VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.or(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Short512VectorTests::bor); + } + + static boolean bxor(boolean a, boolean b) { + return a != b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskxorShort512VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.xor(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Short512VectorTests::bxor); + } + + static boolean bandNot(boolean a, boolean b) { + return a & !b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandNotShort512VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.andNot(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Short512VectorTests::bandNot); + } + + static boolean beq(boolean a, boolean b) { + return a == b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskeqShort512VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.eq(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Short512VectorTests::beq); + } + + static boolean unot(boolean a) { + return !a; + } + + @Test(dataProvider = "boolMaskUnaryOpProvider") + static void masknotShort512VectorTests(IntFunction fa) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + av.not().intoArray(r, i); + } + } + + assertArraysEquals(r, a, Short512VectorTests::unot); + } + + private static final long LONG_MASK_BITS = 0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length()); + + static void assertArraysEquals(long[] r, long[] a, long bits) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], a[i] & bits); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], a[i] & bits, "(" + a[i] + ") at index #" + i); + } + } + + @Test(dataProvider = "longMaskProvider") + static void maskFromToLongShort512VectorTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = new long[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i++) { + VectorMask vmask = VectorMask.fromLong(SPECIES, a[i]); + r[i] = vmask.toLong(); + } + } + assertArraysEquals(r, a, LONG_MASK_BITS); + } + @Test(dataProvider = "shortCompareOpProvider") static void ltShort512VectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { short[] a = fa.apply(SPECIES.length()); @@ -6680,115 +6870,22 @@ public class Short512VectorTests extends AbstractVectorTest { } } - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqualsShort512VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskEqualsShort512VectorTests(IntFunction fa, IntFunction fb) { boolean[] a = fa.apply(SPECIES.length()); boolean[] b = fb.apply(SPECIES.length()); - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - boolean equals = av.equals(bv); - int to = i + SPECIES.length(); - Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + var av = SPECIES.loadMask(a, i); + var bv = SPECIES.loadMask(b, i); + boolean equals = av.equals(bv); + int to = i + SPECIES.length(); + Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + } } } - static boolean band(boolean a, boolean b) { - return a & b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndShort512VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.and(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Short512VectorTests::band); - } - - static boolean bor(boolean a, boolean b) { - return a | b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskOrShort512VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.or(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Short512VectorTests::bor); - } - - static boolean bxor(boolean a, boolean b) { - return a != b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskXorShort512VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.xor(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Short512VectorTests::bxor); - } - - static boolean bandNot(boolean a, boolean b) { - return a & !b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndNotShort512VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.andNot(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Short512VectorTests::bandNot); - } - - static boolean beq(boolean a, boolean b) { - return (a == b); - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqShort512VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.eq(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Short512VectorTests::beq); - } - @Test(dataProvider = "maskProvider") static void maskHashCodeShort512VectorTestsSmokeTest(IntFunction fa) { boolean[] a = fa.apply(SPECIES.length()); @@ -6893,23 +6990,6 @@ public class Short512VectorTests extends AbstractVectorTest { } } - @DataProvider - public static Object[][] longMaskProvider() { - return new Object[][]{ - {0xFFFFFFFFFFFFFFFFL}, - {0x0000000000000000L}, - {0x5555555555555555L}, - {0x0123456789abcdefL}, - }; - } - - @Test(dataProvider = "longMaskProvider") - static void maskFromToLongShort512VectorTestsSmokeTest(long inputLong) { - var vmask = VectorMask.fromLong(SPECIES, inputLong); - long outputLong = vmask.toLong(); - Assert.assertEquals(outputLong, (inputLong & (((0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length())))))); - } - @DataProvider public static Object[][] offsetProvider() { return new Object[][]{ diff --git a/test/jdk/jdk/incubator/vector/Short64VectorTests.java b/test/jdk/jdk/incubator/vector/Short64VectorTests.java index 4b99ed6d84c..bc12c3f0938 100644 --- a/test/jdk/jdk/incubator/vector/Short64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Short64VectorTests.java @@ -393,6 +393,36 @@ public class Short64VectorTests extends AbstractVectorTest { } } + interface FBoolUnOp { + boolean apply(boolean a); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, FBoolUnOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i]), "(" + a[i] + ") at index #" + i); + } + } + + interface FBoolBinOp { + boolean apply(boolean a, boolean b); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, boolean[] b, FBoolBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b[i]), "(" + a[i] + ", " + b[i] + ") at index #" + i); + } + } + interface FBinOp { short apply(short a, short b); } @@ -1085,12 +1115,6 @@ public class Short64VectorTests extends AbstractVectorTest { .flatMap(pair -> SHORT_SATURATING_GENERATORS_ASSOC.stream().map(f -> List.of(pair.get(0), pair.get(1), f))) .collect(Collectors.toList()); - @DataProvider - public Object[][] boolUnaryOpProvider() { - return BOOL_ARRAY_GENERATORS.stream(). - map(f -> new Object[]{f}). - toArray(Object[][]::new); - } static final List>> SHORT_GENERATOR_TRIPLES = SHORT_GENERATOR_PAIRS.stream(). @@ -1222,8 +1246,23 @@ public class Short64VectorTests extends AbstractVectorTest { } @DataProvider - public Object[][] maskCompareOpProvider() { - return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream().map(List::toArray). + public Object[][] longMaskProvider() { + return LONG_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskBinaryOpProvider() { + return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream(). + map(List::toArray). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskUnaryOpProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). toArray(Object[][]::new); } @@ -4455,7 +4494,7 @@ public class Short64VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void anyTrueShort64VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -4479,7 +4518,7 @@ public class Short64VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void allTrueShort64VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -6381,6 +6420,157 @@ public class Short64VectorTests extends AbstractVectorTest { assertArraysEquals(r, a, mask, Short64VectorTests::REVERSE_BYTES); } + static boolean band(boolean a, boolean b) { + return a & b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandShort64VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.and(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Short64VectorTests::band); + } + + static boolean bor(boolean a, boolean b) { + return a | b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskorShort64VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.or(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Short64VectorTests::bor); + } + + static boolean bxor(boolean a, boolean b) { + return a != b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskxorShort64VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.xor(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Short64VectorTests::bxor); + } + + static boolean bandNot(boolean a, boolean b) { + return a & !b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandNotShort64VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.andNot(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Short64VectorTests::bandNot); + } + + static boolean beq(boolean a, boolean b) { + return a == b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskeqShort64VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.eq(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Short64VectorTests::beq); + } + + static boolean unot(boolean a) { + return !a; + } + + @Test(dataProvider = "boolMaskUnaryOpProvider") + static void masknotShort64VectorTests(IntFunction fa) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + av.not().intoArray(r, i); + } + } + + assertArraysEquals(r, a, Short64VectorTests::unot); + } + + private static final long LONG_MASK_BITS = 0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length()); + + static void assertArraysEquals(long[] r, long[] a, long bits) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], a[i] & bits); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], a[i] & bits, "(" + a[i] + ") at index #" + i); + } + } + + @Test(dataProvider = "longMaskProvider") + static void maskFromToLongShort64VectorTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = new long[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i++) { + VectorMask vmask = VectorMask.fromLong(SPECIES, a[i]); + r[i] = vmask.toLong(); + } + } + assertArraysEquals(r, a, LONG_MASK_BITS); + } + @Test(dataProvider = "shortCompareOpProvider") static void ltShort64VectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { short[] a = fa.apply(SPECIES.length()); @@ -6680,115 +6870,22 @@ public class Short64VectorTests extends AbstractVectorTest { } } - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqualsShort64VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskEqualsShort64VectorTests(IntFunction fa, IntFunction fb) { boolean[] a = fa.apply(SPECIES.length()); boolean[] b = fb.apply(SPECIES.length()); - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - boolean equals = av.equals(bv); - int to = i + SPECIES.length(); - Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + var av = SPECIES.loadMask(a, i); + var bv = SPECIES.loadMask(b, i); + boolean equals = av.equals(bv); + int to = i + SPECIES.length(); + Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + } } } - static boolean band(boolean a, boolean b) { - return a & b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndShort64VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.and(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Short64VectorTests::band); - } - - static boolean bor(boolean a, boolean b) { - return a | b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskOrShort64VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.or(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Short64VectorTests::bor); - } - - static boolean bxor(boolean a, boolean b) { - return a != b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskXorShort64VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.xor(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Short64VectorTests::bxor); - } - - static boolean bandNot(boolean a, boolean b) { - return a & !b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndNotShort64VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.andNot(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Short64VectorTests::bandNot); - } - - static boolean beq(boolean a, boolean b) { - return (a == b); - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqShort64VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.eq(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Short64VectorTests::beq); - } - @Test(dataProvider = "maskProvider") static void maskHashCodeShort64VectorTestsSmokeTest(IntFunction fa) { boolean[] a = fa.apply(SPECIES.length()); @@ -6893,23 +6990,6 @@ public class Short64VectorTests extends AbstractVectorTest { } } - @DataProvider - public static Object[][] longMaskProvider() { - return new Object[][]{ - {0xFFFFFFFFFFFFFFFFL}, - {0x0000000000000000L}, - {0x5555555555555555L}, - {0x0123456789abcdefL}, - }; - } - - @Test(dataProvider = "longMaskProvider") - static void maskFromToLongShort64VectorTestsSmokeTest(long inputLong) { - var vmask = VectorMask.fromLong(SPECIES, inputLong); - long outputLong = vmask.toLong(); - Assert.assertEquals(outputLong, (inputLong & (((0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length())))))); - } - @DataProvider public static Object[][] offsetProvider() { return new Object[][]{ diff --git a/test/jdk/jdk/incubator/vector/ShortMaxVectorTests.java b/test/jdk/jdk/incubator/vector/ShortMaxVectorTests.java index 2bb3b9c1557..ec2df02b171 100644 --- a/test/jdk/jdk/incubator/vector/ShortMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/ShortMaxVectorTests.java @@ -398,6 +398,36 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } } + interface FBoolUnOp { + boolean apply(boolean a); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, FBoolUnOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i]), "(" + a[i] + ") at index #" + i); + } + } + + interface FBoolBinOp { + boolean apply(boolean a, boolean b); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, boolean[] b, FBoolBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b[i]), "(" + a[i] + ", " + b[i] + ") at index #" + i); + } + } + interface FBinOp { short apply(short a, short b); } @@ -1090,12 +1120,6 @@ public class ShortMaxVectorTests extends AbstractVectorTest { .flatMap(pair -> SHORT_SATURATING_GENERATORS_ASSOC.stream().map(f -> List.of(pair.get(0), pair.get(1), f))) .collect(Collectors.toList()); - @DataProvider - public Object[][] boolUnaryOpProvider() { - return BOOL_ARRAY_GENERATORS.stream(). - map(f -> new Object[]{f}). - toArray(Object[][]::new); - } static final List>> SHORT_GENERATOR_TRIPLES = SHORT_GENERATOR_PAIRS.stream(). @@ -1227,8 +1251,23 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } @DataProvider - public Object[][] maskCompareOpProvider() { - return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream().map(List::toArray). + public Object[][] longMaskProvider() { + return LONG_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskBinaryOpProvider() { + return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream(). + map(List::toArray). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskUnaryOpProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). toArray(Object[][]::new); } @@ -4460,7 +4499,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void anyTrueShortMaxVectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -4484,7 +4523,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void allTrueShortMaxVectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -6386,6 +6425,157 @@ public class ShortMaxVectorTests extends AbstractVectorTest { assertArraysEquals(r, a, mask, ShortMaxVectorTests::REVERSE_BYTES); } + static boolean band(boolean a, boolean b) { + return a & b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandShortMaxVectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.and(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, ShortMaxVectorTests::band); + } + + static boolean bor(boolean a, boolean b) { + return a | b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskorShortMaxVectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.or(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, ShortMaxVectorTests::bor); + } + + static boolean bxor(boolean a, boolean b) { + return a != b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskxorShortMaxVectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.xor(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, ShortMaxVectorTests::bxor); + } + + static boolean bandNot(boolean a, boolean b) { + return a & !b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandNotShortMaxVectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.andNot(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, ShortMaxVectorTests::bandNot); + } + + static boolean beq(boolean a, boolean b) { + return a == b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskeqShortMaxVectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.eq(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, ShortMaxVectorTests::beq); + } + + static boolean unot(boolean a) { + return !a; + } + + @Test(dataProvider = "boolMaskUnaryOpProvider") + static void masknotShortMaxVectorTests(IntFunction fa) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + av.not().intoArray(r, i); + } + } + + assertArraysEquals(r, a, ShortMaxVectorTests::unot); + } + + private static final long LONG_MASK_BITS = 0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length()); + + static void assertArraysEquals(long[] r, long[] a, long bits) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], a[i] & bits); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], a[i] & bits, "(" + a[i] + ") at index #" + i); + } + } + + @Test(dataProvider = "longMaskProvider") + static void maskFromToLongShortMaxVectorTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = new long[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i++) { + VectorMask vmask = VectorMask.fromLong(SPECIES, a[i]); + r[i] = vmask.toLong(); + } + } + assertArraysEquals(r, a, LONG_MASK_BITS); + } + @Test(dataProvider = "shortCompareOpProvider") static void ltShortMaxVectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { short[] a = fa.apply(SPECIES.length()); @@ -6685,115 +6875,22 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } } - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqualsShortMaxVectorTestsSmokeTest(IntFunction fa, IntFunction fb) { + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskEqualsShortMaxVectorTests(IntFunction fa, IntFunction fb) { boolean[] a = fa.apply(SPECIES.length()); boolean[] b = fb.apply(SPECIES.length()); - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - boolean equals = av.equals(bv); - int to = i + SPECIES.length(); - Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + var av = SPECIES.loadMask(a, i); + var bv = SPECIES.loadMask(b, i); + boolean equals = av.equals(bv); + int to = i + SPECIES.length(); + Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + } } } - static boolean band(boolean a, boolean b) { - return a & b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndShortMaxVectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.and(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, ShortMaxVectorTests::band); - } - - static boolean bor(boolean a, boolean b) { - return a | b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskOrShortMaxVectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.or(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, ShortMaxVectorTests::bor); - } - - static boolean bxor(boolean a, boolean b) { - return a != b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskXorShortMaxVectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.xor(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, ShortMaxVectorTests::bxor); - } - - static boolean bandNot(boolean a, boolean b) { - return a & !b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndNotShortMaxVectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.andNot(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, ShortMaxVectorTests::bandNot); - } - - static boolean beq(boolean a, boolean b) { - return (a == b); - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqShortMaxVectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.eq(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, ShortMaxVectorTests::beq); - } - @Test(dataProvider = "maskProvider") static void maskHashCodeShortMaxVectorTestsSmokeTest(IntFunction fa) { boolean[] a = fa.apply(SPECIES.length()); @@ -6898,7 +6995,6 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } } - @DataProvider public static Object[][] offsetProvider() { return new Object[][]{ diff --git a/test/jdk/jdk/incubator/vector/gen-template.sh b/test/jdk/jdk/incubator/vector/gen-template.sh index a6f794a5559..46ccc0c8550 100644 --- a/test/jdk/jdk/incubator/vector/gen-template.sh +++ b/test/jdk/jdk/incubator/vector/gen-template.sh @@ -73,6 +73,9 @@ binary_math_template="Binary-op-math" binary_math_broadcast_template="Binary-Broadcast-op-math" bool_reduction_scalar="BoolReduction-Scalar-op" bool_reduction_template="BoolReduction-op" +bool_binary_template="BoolBinary-op" +bool_unary_template="BoolUnary-op" +mask_fromtolong_template="Mask-FromToLong" with_op_template="With-Op" shift_template="Shift-op" shift_masked_template="Shift-Masked-op" @@ -230,7 +233,8 @@ function gen_op_tmpl { local gen_perf_tests=$generate_perf_tests if [[ $template == *"-Broadcast-"* ]] || [[ $template == "Miscellaneous" ]] || - [[ $template == *"Compare-Masked"* ]] || [[ $template == *"Compare-Broadcast"* ]]; then + [[ $template == *"Compare-Masked"* ]] || [[ $template == *"Compare-Broadcast"* ]] || + [[ $template == *"Mask-Binary"* ]]; then gen_perf_tests=false fi if [ $gen_perf_tests == true ]; then @@ -625,6 +629,15 @@ gen_unary_alu_op "REVERSE_BYTES" "\$Boxtype\$.reverseBytes(a)" "intOrLong" gen_unary_alu_op "REVERSE_BYTES" "\$Boxtype\$.reverseBytes(a)" "short" gen_unary_alu_op "REVERSE_BYTES" "a" "byte" +# Mask operations +gen_op_tmpl $bool_binary_template "and" "a \& b" +gen_op_tmpl $bool_binary_template "or" "a | b" +gen_op_tmpl $bool_binary_template "xor" "a != b" +gen_op_tmpl $bool_binary_template "andNot" "a \& !b" +gen_op_tmpl $bool_binary_template "eq" "a == b" +gen_op_tmpl $bool_unary_template "not" "!a" +gen_op_tmpl $mask_fromtolong_template "FromToLong" "" + # Miscellaneous Smoke Tests gen_op_tmpl $miscellaneous_template "MISC" "" "" diff --git a/test/jdk/jdk/incubator/vector/templates/Kernel-BoolBinary-op.template b/test/jdk/jdk/incubator/vector/templates/Kernel-BoolBinary-op.template new file mode 100644 index 00000000000..3f5bc428cdd --- /dev/null +++ b/test/jdk/jdk/incubator/vector/templates/Kernel-BoolBinary-op.template @@ -0,0 +1,11 @@ + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.[[TEST]](bv).intoArray(r, i); + } + } diff --git a/test/jdk/jdk/incubator/vector/templates/Kernel-BoolUnary-op.template b/test/jdk/jdk/incubator/vector/templates/Kernel-BoolUnary-op.template new file mode 100644 index 00000000000..836db281c1b --- /dev/null +++ b/test/jdk/jdk/incubator/vector/templates/Kernel-BoolUnary-op.template @@ -0,0 +1,9 @@ + boolean[] a = fa.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + av.[[TEST]]().intoArray(r, i); + } + } diff --git a/test/jdk/jdk/incubator/vector/templates/Unit-BoolBinary-op.template b/test/jdk/jdk/incubator/vector/templates/Unit-BoolBinary-op.template new file mode 100644 index 00000000000..9ee79e05363 --- /dev/null +++ b/test/jdk/jdk/incubator/vector/templates/Unit-BoolBinary-op.template @@ -0,0 +1,10 @@ + + static boolean b[[TEST]](boolean a, boolean b) { + return [[TEST_OP]]; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void mask[[TEST]]$vectorteststype$(IntFunction fa, IntFunction fb) { +[[KERNEL]] + assertArraysEquals(r, a, b, $vectorteststype$::b[[TEST]]); + } diff --git a/test/jdk/jdk/incubator/vector/templates/Unit-BoolUnary-op.template b/test/jdk/jdk/incubator/vector/templates/Unit-BoolUnary-op.template new file mode 100644 index 00000000000..6b1f2185528 --- /dev/null +++ b/test/jdk/jdk/incubator/vector/templates/Unit-BoolUnary-op.template @@ -0,0 +1,10 @@ + + static boolean u[[TEST]](boolean a) { + return [[TEST_OP]]; + } + + @Test(dataProvider = "boolMaskUnaryOpProvider") + static void mask[[TEST]]$vectorteststype$(IntFunction fa) { +[[KERNEL]] + assertArraysEquals(r, a, $vectorteststype$::u[[TEST]]); + } diff --git a/test/jdk/jdk/incubator/vector/templates/Unit-Mask-FromToLong.template b/test/jdk/jdk/incubator/vector/templates/Unit-Mask-FromToLong.template new file mode 100644 index 00000000000..784ef5f81b9 --- /dev/null +++ b/test/jdk/jdk/incubator/vector/templates/Unit-Mask-FromToLong.template @@ -0,0 +1,27 @@ + + private static final long LONG_MASK_BITS = 0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length()); + + static void assertArraysEquals(long[] r, long[] a, long bits) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], a[i] & bits); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], a[i] & bits, "(" + a[i] + ") at index #" + i); + } + } + + @Test(dataProvider = "longMaskProvider") + static void mask[[TEST]]$vectorteststype$(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = new long[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i++) { + VectorMask vmask = VectorMask.fromLong(SPECIES, a[i]); + r[i] = vmask.toLong(); + } + } + assertArraysEquals(r, a, LONG_MASK_BITS); + } diff --git a/test/jdk/jdk/incubator/vector/templates/Unit-Miscellaneous.template b/test/jdk/jdk/incubator/vector/templates/Unit-Miscellaneous.template index 9a020c66d52..460f7624f2c 100644 --- a/test/jdk/jdk/incubator/vector/templates/Unit-Miscellaneous.template +++ b/test/jdk/jdk/incubator/vector/templates/Unit-Miscellaneous.template @@ -382,115 +382,22 @@ } } - @Test(dataProvider = "maskCompareOpProvider") - static void maskEquals$vectorteststype$SmokeTest(IntFunction fa, IntFunction fb) { + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskEquals$vectorteststype$(IntFunction fa, IntFunction fb) { boolean[] a = fa.apply(SPECIES.length()); boolean[] b = fb.apply(SPECIES.length()); - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - boolean equals = av.equals(bv); - int to = i + SPECIES.length(); - Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + var av = SPECIES.loadMask(a, i); + var bv = SPECIES.loadMask(b, i); + boolean equals = av.equals(bv); + int to = i + SPECIES.length(); + Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + } } } - static boolean band(boolean a, boolean b) { - return a & b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAnd$vectorteststype$SmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.and(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, $vectorteststype$::band); - } - - static boolean bor(boolean a, boolean b) { - return a | b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskOr$vectorteststype$SmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.or(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, $vectorteststype$::bor); - } - - static boolean bxor(boolean a, boolean b) { - return a != b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskXor$vectorteststype$SmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.xor(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, $vectorteststype$::bxor); - } - - static boolean bandNot(boolean a, boolean b) { - return a & !b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndNot$vectorteststype$SmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.andNot(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, $vectorteststype$::bandNot); - } - - static boolean beq(boolean a, boolean b) { - return (a == b); - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskEq$vectorteststype$SmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.eq(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, $vectorteststype$::beq); - } - @Test(dataProvider = "maskProvider") static void maskHashCode$vectorteststype$SmokeTest(IntFunction fa) { boolean[] a = fa.apply(SPECIES.length()); @@ -595,25 +502,6 @@ } } -#if[!MaxBit] - @DataProvider - public static Object[][] longMaskProvider() { - return new Object[][]{ - {0xFFFFFFFFFFFFFFFFL}, - {0x0000000000000000L}, - {0x5555555555555555L}, - {0x0123456789abcdefL}, - }; - } - - @Test(dataProvider = "longMaskProvider") - static void maskFromToLong$vectorteststype$SmokeTest(long inputLong) { - var vmask = VectorMask.fromLong(SPECIES, inputLong); - long outputLong = vmask.toLong(); - Assert.assertEquals(outputLong, (inputLong & (((0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length())))))); - } -#end[!MaxBit] - @DataProvider public static Object[][] offsetProvider() { return new Object[][]{ diff --git a/test/jdk/jdk/incubator/vector/templates/Unit-header.template b/test/jdk/jdk/incubator/vector/templates/Unit-header.template index 33c52f18c1c..328a8335df3 100644 --- a/test/jdk/jdk/incubator/vector/templates/Unit-header.template +++ b/test/jdk/jdk/incubator/vector/templates/Unit-header.template @@ -490,6 +490,36 @@ relativeError)); } } + interface FBoolUnOp { + boolean apply(boolean a); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, FBoolUnOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i]), "(" + a[i] + ") at index #" + i); + } + } + + interface FBoolBinOp { + boolean apply(boolean a, boolean b); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, boolean[] b, FBoolBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b[i]), "(" + a[i] + ", " + b[i] + ") at index #" + i); + } + } + interface FBinOp { $type$ apply($type$ a, $type$ b); } @@ -1521,8 +1551,23 @@ relativeError)); } @DataProvider - public Object[][] maskCompareOpProvider() { - return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream().map(List::toArray). + public Object[][] longMaskProvider() { + return LONG_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskBinaryOpProvider() { + return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream(). + map(List::toArray). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskUnaryOpProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). toArray(Object[][]::new); } From a26221299e657b64379d2d56ed3b073f12b227d1 Mon Sep 17 00:00:00 2001 From: Jaikiran Pai Date: Wed, 10 Dec 2025 02:04:12 +0000 Subject: [PATCH 235/706] 8255463: java/nio/channels/spi/SelectorProvider/inheritedChannel/InheritedChannelTest.java failed with ThreadTimeoutException Reviewed-by: dfuchs, djelinski, bpb --- .../inheritedChannel/InheritedChannelTest.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/jdk/java/nio/channels/spi/SelectorProvider/inheritedChannel/InheritedChannelTest.java b/test/jdk/java/nio/channels/spi/SelectorProvider/inheritedChannel/InheritedChannelTest.java index 99a127ca5ad..934bf509d88 100644 --- a/test/jdk/java/nio/channels/spi/SelectorProvider/inheritedChannel/InheritedChannelTest.java +++ b/test/jdk/java/nio/channels/spi/SelectorProvider/inheritedChannel/InheritedChannelTest.java @@ -40,7 +40,6 @@ * @key intermittent */ -import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; @@ -77,7 +76,7 @@ public class InheritedChannelTest { }; } - @Test(dataProvider = "testCases", timeOut=30000) + @Test(dataProvider = "testCases") public void test(String desc, List opts) throws Throwable { String pathVar = Platform.sharedLibraryPathVariableName(); System.out.println(pathVar + "=" + libraryPath); From b6732d6048259de68a3dd5b4f66ac82f87270404 Mon Sep 17 00:00:00 2001 From: Xiaohong Gong Date: Wed, 10 Dec 2025 02:09:49 +0000 Subject: [PATCH 236/706] 8371603: C2: Missing Ideal optimizations for load and store vectors on SVE Co-authored-by: Emanuel Peter Reviewed-by: epeter, erfang, haosun --- src/hotspot/cpu/aarch64/aarch64_vector.ad | 29 +- src/hotspot/cpu/aarch64/aarch64_vector_ad.m4 | 29 +- src/hotspot/share/opto/matcher.hpp | 4 + src/hotspot/share/opto/vectornode.cpp | 65 ++- src/hotspot/share/opto/vectornode.hpp | 1 - .../compiler/lib/ir_framework/IRNode.java | 10 + .../TestVectorLoadStoreOptimization.java | 105 +++++ .../TestVectorOperationsWithPartialSize.java | 432 ++++++++++++++++++ 8 files changed, 619 insertions(+), 56 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/vectorapi/TestVectorLoadStoreOptimization.java create mode 100644 test/hotspot/jtreg/compiler/vectorapi/TestVectorOperationsWithPartialSize.java diff --git a/src/hotspot/cpu/aarch64/aarch64_vector.ad b/src/hotspot/cpu/aarch64/aarch64_vector.ad index 842784d1a29..78ef121bd29 100644 --- a/src/hotspot/cpu/aarch64/aarch64_vector.ad +++ b/src/hotspot/cpu/aarch64/aarch64_vector.ad @@ -346,8 +346,14 @@ source %{ } bool Matcher::vector_needs_partial_operations(Node* node, const TypeVect* vt) { - // Only SVE has partial vector operations - if (UseSVE == 0) { + // 1. Only SVE requires partial vector operations. + // 2. The vector size in bytes must be smaller than MaxVectorSize. + // 3. Predicated vectors have a mask input, which guarantees that + // out-of-bounds lanes remain inactive. + int length_in_bytes = vt->length_in_bytes(); + if (UseSVE == 0 || + length_in_bytes == MaxVectorSize || + node->is_predicated_vector()) { return false; } @@ -370,21 +376,22 @@ source %{ return !node->in(1)->is_Con(); case Op_LoadVector: case Op_StoreVector: - // We use NEON load/store instructions if the vector length is <= 128 bits. - return vt->length_in_bytes() > 16; case Op_AddReductionVI: case Op_AddReductionVL: - // We may prefer using NEON instructions rather than SVE partial operations. - return !VM_Version::use_neon_for_vector(vt->length_in_bytes()); + // For these ops, we prefer using NEON instructions rather than SVE + // predicated instructions for better performance. + return !VM_Version::use_neon_for_vector(length_in_bytes); case Op_MinReductionV: case Op_MaxReductionV: - // For BYTE/SHORT/INT/FLOAT/DOUBLE types, we may prefer using NEON - // instructions rather than SVE partial operations. + // For BYTE/SHORT/INT/FLOAT/DOUBLE types, we prefer using NEON + // instructions rather than SVE predicated instructions for + // better performance. return vt->element_basic_type() == T_LONG || - !VM_Version::use_neon_for_vector(vt->length_in_bytes()); + !VM_Version::use_neon_for_vector(length_in_bytes); default: - // For other ops whose vector size is smaller than the max vector size, a - // full-sized unpredicated operation does not impact the final vector result. + // For other ops whose vector size is smaller than the max vector + // size, a full-sized unpredicated operation does not impact the + // vector result. return false; } } diff --git a/src/hotspot/cpu/aarch64/aarch64_vector_ad.m4 b/src/hotspot/cpu/aarch64/aarch64_vector_ad.m4 index dff82ce95ac..66dc22c3758 100644 --- a/src/hotspot/cpu/aarch64/aarch64_vector_ad.m4 +++ b/src/hotspot/cpu/aarch64/aarch64_vector_ad.m4 @@ -336,8 +336,14 @@ source %{ } bool Matcher::vector_needs_partial_operations(Node* node, const TypeVect* vt) { - // Only SVE has partial vector operations - if (UseSVE == 0) { + // 1. Only SVE requires partial vector operations. + // 2. The vector size in bytes must be smaller than MaxVectorSize. + // 3. Predicated vectors have a mask input, which guarantees that + // out-of-bounds lanes remain inactive. + int length_in_bytes = vt->length_in_bytes(); + if (UseSVE == 0 || + length_in_bytes == MaxVectorSize || + node->is_predicated_vector()) { return false; } @@ -360,21 +366,22 @@ source %{ return !node->in(1)->is_Con(); case Op_LoadVector: case Op_StoreVector: - // We use NEON load/store instructions if the vector length is <= 128 bits. - return vt->length_in_bytes() > 16; case Op_AddReductionVI: case Op_AddReductionVL: - // We may prefer using NEON instructions rather than SVE partial operations. - return !VM_Version::use_neon_for_vector(vt->length_in_bytes()); + // For these ops, we prefer using NEON instructions rather than SVE + // predicated instructions for better performance. + return !VM_Version::use_neon_for_vector(length_in_bytes); case Op_MinReductionV: case Op_MaxReductionV: - // For BYTE/SHORT/INT/FLOAT/DOUBLE types, we may prefer using NEON - // instructions rather than SVE partial operations. + // For BYTE/SHORT/INT/FLOAT/DOUBLE types, we prefer using NEON + // instructions rather than SVE predicated instructions for + // better performance. return vt->element_basic_type() == T_LONG || - !VM_Version::use_neon_for_vector(vt->length_in_bytes()); + !VM_Version::use_neon_for_vector(length_in_bytes); default: - // For other ops whose vector size is smaller than the max vector size, a - // full-sized unpredicated operation does not impact the final vector result. + // For other ops whose vector size is smaller than the max vector + // size, a full-sized unpredicated operation does not impact the + // vector result. return false; } } diff --git a/src/hotspot/share/opto/matcher.hpp b/src/hotspot/share/opto/matcher.hpp index ca13d0166a1..a071cff9e3c 100644 --- a/src/hotspot/share/opto/matcher.hpp +++ b/src/hotspot/share/opto/matcher.hpp @@ -329,6 +329,10 @@ public: static bool match_rule_supported_vector_masked(int opcode, int vlen, BasicType bt); + // Determines if a vector operation needs to be partially implemented with a mask + // controlling only the lanes in range [0, vector_length) are processed. This applies + // to operations whose vector length is less than the hardware-supported maximum + // vector length. Returns true if the operation requires masking, false otherwise. static bool vector_needs_partial_operations(Node* node, const TypeVect* vt); static bool vector_rearrange_requires_load_shuffle(BasicType elem_bt, int vlen); diff --git a/src/hotspot/share/opto/vectornode.cpp b/src/hotspot/share/opto/vectornode.cpp index 57b94205e5e..271dc901dcb 100644 --- a/src/hotspot/share/opto/vectornode.cpp +++ b/src/hotspot/share/opto/vectornode.cpp @@ -936,28 +936,26 @@ bool VectorNode::is_scalar_op_that_returns_int_but_vector_op_returns_long(int op } } +// Idealize vector operations whose vector size is less than the hardware supported +// max vector size. Generate a vector mask for the operation. Lanes with indices +// inside of the vector size are set to true, while the remaining lanes are set to +// false. Returns the corresponding masked vector node. +static Node* ideal_partial_operations(PhaseGVN* phase, Node* node, const TypeVect* vt) { + if (!Matcher::vector_needs_partial_operations(node, vt)) { + return nullptr; + } -Node* VectorNode::try_to_gen_masked_vector(PhaseGVN* gvn, Node* node, const TypeVect* vt) { int vopc = node->Opcode(); uint vlen = vt->length(); BasicType bt = vt->element_basic_type(); + assert(Matcher::match_rule_supported_vector_masked(vopc, vlen, bt), + "The masked feature is required for the vector operation"); + assert(Matcher::match_rule_supported_vector(Op_VectorMaskGen, vlen, bt), + "'VectorMaskGen' is required to generate a vector mask"); - // Predicated vectors do not need to add another mask input - if (node->is_predicated_vector() || !Matcher::has_predicated_vectors() || - !Matcher::match_rule_supported_vector_masked(vopc, vlen, bt) || - !Matcher::match_rule_supported_vector(Op_VectorMaskGen, vlen, bt)) { - return nullptr; - } - - Node* mask = nullptr; - // Generate a vector mask for vector operation whose vector length is lower than the - // hardware supported max vector length. - if (vt->length_in_bytes() < (uint)MaxVectorSize) { - Node* length = gvn->transform(new ConvI2LNode(gvn->makecon(TypeInt::make(vlen)))); - mask = gvn->transform(VectorMaskGenNode::make(length, bt, vlen)); - } else { - return nullptr; - } + // Generate a vector mask, with lanes inside of the vector length set to true. + Node* length = phase->transform(new ConvI2LNode(phase->makecon(TypeInt::make(vlen)))); + Node* mask = phase->transform(VectorMaskGenNode::make(length, bt, vlen)); // Generate the related masked op for vector load/store/load_gather/store_scatter. // Or append the mask to the vector op's input list by default. @@ -1037,8 +1035,9 @@ bool VectorNode::should_swap_inputs_to_help_global_value_numbering() { } Node* VectorNode::Ideal(PhaseGVN* phase, bool can_reshape) { - if (Matcher::vector_needs_partial_operations(this, vect_type())) { - return try_to_gen_masked_vector(phase, this, vect_type()); + Node* n = ideal_partial_operations(phase, this, vect_type()); + if (n != nullptr) { + return n; } // Sort inputs of commutative non-predicated vector operations to help value numbering. @@ -1119,9 +1118,9 @@ LoadVectorNode* LoadVectorNode::make(int opc, Node* ctl, Node* mem, } Node* LoadVectorNode::Ideal(PhaseGVN* phase, bool can_reshape) { - const TypeVect* vt = vect_type(); - if (Matcher::vector_needs_partial_operations(this, vt)) { - return VectorNode::try_to_gen_masked_vector(phase, this, vt); + Node* n = ideal_partial_operations(phase, this, vect_type()); + if (n != nullptr) { + return n; } return LoadNode::Ideal(phase, can_reshape); } @@ -1133,9 +1132,9 @@ StoreVectorNode* StoreVectorNode::make(int opc, Node* ctl, Node* mem, Node* adr, } Node* StoreVectorNode::Ideal(PhaseGVN* phase, bool can_reshape) { - const TypeVect* vt = vect_type(); - if (Matcher::vector_needs_partial_operations(this, vt)) { - return VectorNode::try_to_gen_masked_vector(phase, this, vt); + Node* n = ideal_partial_operations(phase, this, vect_type()); + if (n != nullptr) { + return n; } return StoreNode::Ideal(phase, can_reshape); } @@ -1411,11 +1410,11 @@ ReductionNode* ReductionNode::make(int opc, Node* ctrl, Node* n1, Node* n2, Basi } Node* ReductionNode::Ideal(PhaseGVN* phase, bool can_reshape) { - const TypeVect* vt = vect_type(); - if (Matcher::vector_needs_partial_operations(this, vt)) { - return VectorNode::try_to_gen_masked_vector(phase, this, vt); + Node* n = ideal_partial_operations(phase, this, vect_type()); + if (n != nullptr) { + return n; } - return nullptr; + return Node::Ideal(phase, can_reshape); } // Convert fromLong to maskAll if the input sets or unsets all lanes. @@ -1893,11 +1892,11 @@ Node* VectorMaskOpNode::make(Node* mask, const Type* ty, int mopc) { } Node* VectorMaskOpNode::Ideal(PhaseGVN* phase, bool can_reshape) { - const TypeVect* vt = vect_type(); - if (Matcher::vector_needs_partial_operations(this, vt)) { - return VectorNode::try_to_gen_masked_vector(phase, this, vt); + Node* n = ideal_partial_operations(phase, this, vect_type()); + if (n != nullptr) { + return n; } - return nullptr; + return TypeNode::Ideal(phase, can_reshape); } Node* VectorMaskCastNode::Identity(PhaseGVN* phase) { diff --git a/src/hotspot/share/opto/vectornode.hpp b/src/hotspot/share/opto/vectornode.hpp index 427aeff53fc..dc7aa13cf36 100644 --- a/src/hotspot/share/opto/vectornode.hpp +++ b/src/hotspot/share/opto/vectornode.hpp @@ -117,7 +117,6 @@ class VectorNode : public TypeNode { static bool is_vector_bitwise_not_pattern(Node* n); static Node* degenerate_vector_rotate(Node* n1, Node* n2, bool is_rotate_left, int vlen, BasicType bt, PhaseGVN* phase); - static Node* try_to_gen_masked_vector(PhaseGVN* gvn, Node* node, const TypeVect* vt); // [Start, end) half-open range defining which operands are vectors static void vector_operands(Node* n, uint* start, uint* end); diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java index 41f185f3686..608027e7ee1 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java @@ -1478,6 +1478,16 @@ public class IRNode { beforeMatchingNameRegex(VECTOR_MASK_LANE_IS_SET, "ExtractUB"); } + public static final String VECTOR_MASK_GEN = PREFIX + "VECTOR_MASK_GEN" + POSTFIX; + static { + beforeMatchingNameRegex(VECTOR_MASK_GEN, "VectorMaskGen"); + } + + public static final String VECTOR_MASK_FIRST_TRUE = PREFIX + "VECTOR_MASK_FIRST_TRUE" + POSTFIX; + static { + beforeMatchingNameRegex(VECTOR_MASK_FIRST_TRUE, "VectorMaskFirstTrue"); + } + // Can only be used if avx512_vnni is available. public static final String MUL_ADD_VS2VI_VNNI = PREFIX + "MUL_ADD_VS2VI_VNNI" + POSTFIX; static { diff --git a/test/hotspot/jtreg/compiler/vectorapi/TestVectorLoadStoreOptimization.java b/test/hotspot/jtreg/compiler/vectorapi/TestVectorLoadStoreOptimization.java new file mode 100644 index 00000000000..c603f450d0c --- /dev/null +++ b/test/hotspot/jtreg/compiler/vectorapi/TestVectorLoadStoreOptimization.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2025, NVIDIA CORPORATION & 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 compiler.vectorapi; + +import compiler.lib.generators.*; +import compiler.lib.ir_framework.*; +import jdk.incubator.vector.*; +import jdk.test.lib.Asserts; + +/** + * @test 8371603 + * @key randomness + * @library /test/lib / + * @summary Test the missing optimization issues for vector load/store caused by JDK-8286941 + * @modules jdk.incubator.vector + * + * @run driver ${test.main.class} + */ +public class TestVectorLoadStoreOptimization { + private static final int LENGTH = 1024; + private static final Generators random = Generators.G; + + private static final VectorSpecies SPECIES = IntVector.SPECIES_PREFERRED; + + private static int[] a; + + static { + a = new int[LENGTH]; + random.fill(random.ints(), a); + } + + // Test that "LoadVectorNode::Ideal()" calls "LoadNode::Ideal()" as expected, + // which sees the previous stores that go to the same position in-dependently, + // and optimize out the load with matched store values. + @Test + @IR(counts = { IRNode.LOAD_VECTOR_I, "1" }, + applyIfCPUFeatureOr = {"asimd", "true", "avx", "true", "rvv", "true"}) + public static void testLoadVector() { + IntVector v1 = IntVector.fromArray(SPECIES, a, 0); + v1.intoArray(a, SPECIES.length()); + v1.intoArray(a, 2 * SPECIES.length()); + // The second load vector equals to the first one and should be optimized + // out by "LoadNode::Ideal()". + IntVector v2 = IntVector.fromArray(SPECIES, a, SPECIES.length()); + v2.intoArray(a, 3 * SPECIES.length()); + } + + @Check(test = "testLoadVector") + public static void testLoadVectorVerify() { + for (int i = SPECIES.length(); i < 4 * SPECIES.length(); i += SPECIES.length()) { + for (int j = 0; j < SPECIES.length(); j++) { + Asserts.assertEquals(a[i + j], a[j]); + } + } + } + + // Test that "StoreVectorNode::Ideal()" calls "StoreNode::Ideal()" as expected, + // which can get rid of previous stores that go to the same position. + @Test + @IR(counts = { IRNode.STORE_VECTOR, "1" }, + applyIfCPUFeatureOr = {"asimd", "true", "avx", "true", "rvv", "true"}) + public static void testStoreVector() { + IntVector v1 = IntVector.fromArray(SPECIES, a, 0 * SPECIES.length()); + IntVector v2 = IntVector.fromArray(SPECIES, a, 1 * SPECIES.length()); + // Useless store to same position as below, which should be optimized out by + // "StoreNode::Ideal()". + v1.intoArray(a, 3 * SPECIES.length()); + v2.intoArray(a, 3 * SPECIES.length()); + } + + @Check(test = "testStoreVector") + public static void testStoreVectorVerify() { + for (int i = 3 * SPECIES.length(); i < 4 * SPECIES.length(); i++) { + Asserts.assertEquals(a[i], a[i - 2 * SPECIES.length()]); + } + } + + public static void main(String[] args) { + TestFramework testFramework = new TestFramework(); + testFramework.setDefaultWarmup(10000) + .addFlags("--add-modules=jdk.incubator.vector") + .start(); + } +} \ No newline at end of file diff --git a/test/hotspot/jtreg/compiler/vectorapi/TestVectorOperationsWithPartialSize.java b/test/hotspot/jtreg/compiler/vectorapi/TestVectorOperationsWithPartialSize.java new file mode 100644 index 00000000000..6fd20b7e2fb --- /dev/null +++ b/test/hotspot/jtreg/compiler/vectorapi/TestVectorOperationsWithPartialSize.java @@ -0,0 +1,432 @@ +/* + * Copyright (c) 2025, NVIDIA CORPORATION & 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 compiler.vectorapi; + +import compiler.lib.generators.*; +import compiler.lib.ir_framework.*; +import jdk.incubator.vector.*; +import jdk.test.lib.Asserts; + +/** + * @test 8371603 + * @key randomness + * @library /test/lib / + * @summary Test vector operations with vector size less than MaxVectorSize + * @modules jdk.incubator.vector + * + * @run driver ${test.main.class} + */ + +public class TestVectorOperationsWithPartialSize { + private static final int SIZE = 1024; + private static final Generators random = Generators.G; + + private static final VectorSpecies ISPEC_128 = IntVector.SPECIES_128; + private static final VectorSpecies LSPEC_128 = LongVector.SPECIES_128; + private static final VectorSpecies FSPEC_128 = FloatVector.SPECIES_128; + private static final VectorSpecies DSPEC_128 = DoubleVector.SPECIES_128; + private static final VectorSpecies ISPEC_256 = IntVector.SPECIES_256; + private static final VectorSpecies LSPEC_256 = LongVector.SPECIES_256; + + private static int[] ia; + private static int[] ib; + private static long[] la; + private static long[] lb; + private static float[] fa; + private static float[] fb; + private static double[] da; + private static double[] db; + private static boolean[] m; + private static boolean[] mr; + private static int[] indices; + + static { + ia = new int[SIZE]; + ib = new int[SIZE]; + la = new long[SIZE]; + lb = new long[SIZE]; + fa = new float[SIZE]; + fb = new float[SIZE]; + da = new double[SIZE]; + db = new double[SIZE]; + m = new boolean[SIZE]; + mr = new boolean[SIZE]; + indices = new int[SIZE]; + + random.fill(random.ints(), ia); + random.fill(random.longs(), la); + random.fill(random.floats(), fa); + random.fill(random.doubles(), da); + random.fill(random.uniformInts(0, ISPEC_128.length()), indices); + for (int i = 0; i < SIZE; i++) { + m[i] = i % 2 == 0; + } + } + + // ================ Load/Store/Gather/Scatter Tests ================== + + private static void verifyLoadStore(int[] expected, int[] actual, int vlen) { + for (int i = 0; i < vlen; i++) { + Asserts.assertEquals(expected[i], actual[i]); + } + } + + private static void verifyLoadGatherStoreScatter(int[] expected, int[] actual, int[] indices, int vlen) { + for (int i = 0; i < vlen; i++) { + Asserts.assertEquals(expected[indices[i]], actual[indices[i]]); + } + } + + @Test + @IR(counts = {IRNode.VECTOR_MASK_GEN, "0", + IRNode.LOAD_VECTOR_I, IRNode.VECTOR_SIZE_4, "1", + IRNode.STORE_VECTOR, "1"}, + applyIfCPUFeature = {"sve", "true"}, applyIf = {"MaxVectorSize", ">=32"}) + public void testLoadStore_128() { + IntVector v = IntVector.fromArray(ISPEC_128, ia, 0); + v.intoArray(ib, 0); + verifyLoadStore(ia, ib, ISPEC_128.length()); + } + + @Test + @IR(counts = {IRNode.VECTOR_MASK_GEN, "1", + IRNode.LOAD_VECTOR_MASKED, "1", + IRNode.STORE_VECTOR_MASKED, "1"}, + applyIfCPUFeature = {"sve", "true"}, applyIf = {"MaxVectorSize", ">=64"}) + public void testLoadStore_256() { + IntVector v = IntVector.fromArray(ISPEC_256, ia, 0); + v.intoArray(ib, 0); + verifyLoadStore(ia, ib, ISPEC_256.length()); + } + + @Test + @IR(counts = {IRNode.VECTOR_MASK_GEN, "1", + IRNode.LOAD_VECTOR_GATHER_MASKED, "1", + IRNode.STORE_VECTOR_SCATTER_MASKED, "1"}, + applyIfCPUFeature = {"sve", "true"}, applyIf = {"MaxVectorSize", ">=32"}) + public void testLoadGatherStoreScatter_128() { + IntVector v = IntVector.fromArray(ISPEC_128, ia, 0, indices, 0); + v.intoArray(ib, 0, indices, 0); + verifyLoadGatherStoreScatter(ia, ib, indices, ISPEC_128.length()); + } + + @Test + @IR(counts = {IRNode.VECTOR_MASK_GEN, "1", + IRNode.LOAD_VECTOR_GATHER_MASKED, "1", + IRNode.STORE_VECTOR_SCATTER_MASKED, "1"}, + applyIfCPUFeature = {"sve", "true"}, applyIf = {"MaxVectorSize", ">=64"}) + public void testLoadGatherStoreScatter_256() { + IntVector v = IntVector.fromArray(ISPEC_256, ia, 0, indices, 0); + v.intoArray(ib, 0, indices, 0); + verifyLoadGatherStoreScatter(ia, ib, indices, ISPEC_256.length()); + } + + // ===================== Reduction Tests - Add ===================== + + interface binOpInt { + int apply(int a, int b); + } + + interface binOpLong { + long apply(long a, long b); + } + + private static int reduceLanes(int init, int[] arr, int vlen, binOpInt f) { + int result = init; + for (int i = 0; i < vlen; i++) { + result = f.apply(arr[i], result); + } + return result; + } + + private static long reduceLanes(long init, long[] arr, int vlen,binOpLong f) { + long result = init; + for (int i = 0; i < vlen; i++) { + result = f.apply(arr[i], result); + } + return result; + } + + // Reduction add operations with integer types are implemented with NEON SIMD instructions + // when the vector size is less than or equal to 128-bit. + @Test + @IR(counts = {IRNode.VECTOR_MASK_GEN, "0", + IRNode.ADD_REDUCTION_VI, "1"}, + applyIfCPUFeature = {"sve", "true"}, applyIf = {"MaxVectorSize", ">=32"}) + public int testAddReductionInt_128() { + IntVector v = IntVector.fromArray(ISPEC_128, ia, 0); + int result = v.reduceLanes(VectorOperators.ADD); + Asserts.assertEquals(reduceLanes(0, ia, ISPEC_128.length(), (a, b) -> (a + b)), result); + return result; + } + + @Test + @IR(counts = {IRNode.VECTOR_MASK_GEN, "1", + IRNode.ADD_REDUCTION_VI, "1"}, + applyIfCPUFeature = {"sve", "true"}, applyIf = {"MaxVectorSize", ">=64"}) + public int testAddReductionInt_256() { + IntVector v = IntVector.fromArray(ISPEC_256, ia, 0); + int result = v.reduceLanes(VectorOperators.ADD); + Asserts.assertEquals(reduceLanes(0, ia, ISPEC_256.length(), (a, b) -> (a + b)), result); + return result; + } + + // Reduction add operations with long types are implemented with NEON SIMD instructions + // when the vector size is less than or equal to 128-bit. + @Test + @IR(counts = {IRNode.VECTOR_MASK_GEN, "0", + IRNode.ADD_REDUCTION_VL, "1"}, + applyIfCPUFeature = {"sve", "true"}, applyIf = {"MaxVectorSize", ">=32"}) + public long testAddReductionLong_128() { + LongVector v = LongVector.fromArray(LSPEC_128, la, 0); + long result = v.reduceLanes(VectorOperators.ADD); + Asserts.assertEquals(reduceLanes(0L, la, LSPEC_128.length(), (a, b) -> (a + b)), result); + return result; + } + + @Test + @IR(counts = {IRNode.VECTOR_MASK_GEN, "1", + IRNode.ADD_REDUCTION_VL, "1"}, + applyIfCPUFeature = {"sve", "true"}, applyIf = {"MaxVectorSize", ">=64"}) + public long testAddReductionLong_256() { + LongVector v = LongVector.fromArray(LSPEC_256, la, 0); + long result = v.reduceLanes(VectorOperators.ADD); + Asserts.assertEquals(reduceLanes(0L, la, LSPEC_256.length(), (a, b) -> (a + b)), result); + return result; + } + + private static void verifyAddReductionFloat(float actual, float[] arr, int vlen) { + float expected = 0.0f; + for (int i = 0; i < vlen; i++) { + expected += arr[i]; + } + // Floating point addition reduction ops may introduce rounding errors. + float ROUNDING_ERROR_FACTOR_ADD = 10.0f; + float tolerance = Math.ulp(expected) * ROUNDING_ERROR_FACTOR_ADD; + if (Math.abs(expected - actual) > tolerance) { + throw new RuntimeException( + "assertEqualsWithTolerance" + + ": expected " + expected + " but was " + actual + + " (tolerance: " + tolerance + ", diff: " + Math.abs(expected - actual) + ")" + ); + } + } + + private static void verifyAddReductionDouble(double actual, double[] arr, int vlen) { + double expected = 0.0; + for (int i = 0; i < vlen; i++) { + expected += arr[i]; + } + // Floating point addition reduction ops may introduce rounding errors. + double ROUNDING_ERROR_FACTOR_ADD = 10.0; + double tolerance = Math.ulp(expected) * ROUNDING_ERROR_FACTOR_ADD; + if (Math.abs(expected - actual) > tolerance) { + throw new RuntimeException( + "assertEqualsWithTolerance" + + ": expected " + expected + " but was " + actual + + " (tolerance: " + tolerance + ", diff: " + Math.abs(expected - actual) + ")" + ); + } + } + + @Test + @IR(counts = {IRNode.VECTOR_MASK_GEN, "1", + IRNode.ADD_REDUCTION_VF, "1"}, + applyIfCPUFeature = {"sve", "true"}, applyIf = {"MaxVectorSize", ">=32"}) + public float testAddReductionFloat() { + FloatVector v = FloatVector.fromArray(FSPEC_128, fa, 0); + float result = v.reduceLanes(VectorOperators.ADD); + verifyAddReductionFloat(result, fa, FSPEC_128.length()); + return result; + } + + + @Test + @IR(counts = {IRNode.VECTOR_MASK_GEN, "1", + IRNode.ADD_REDUCTION_VD, "1"}, + applyIfCPUFeature = {"sve", "true"}, applyIf = {"MaxVectorSize", ">=32"}) + public double testAddReductionDouble() { + DoubleVector v = DoubleVector.fromArray(DSPEC_128, da, 0); + double result = v.reduceLanes(VectorOperators.ADD); + verifyAddReductionDouble(result, da, DSPEC_128.length()); + return result; + } + + // ============== Reduction Tests - Logical ============== + + @Test + @IR(counts = {IRNode.VECTOR_MASK_GEN, "1", + IRNode.AND_REDUCTION_V, "1"}, + applyIfCPUFeature = {"sve", "true"}, applyIf = {"MaxVectorSize", ">=32"}) + public int testAndReduction() { + IntVector v = IntVector.fromArray(ISPEC_128, ia, 0); + int result = v.reduceLanes(VectorOperators.AND); + Asserts.assertEquals(reduceLanes(-1, ia, ISPEC_128.length(), (a, b) -> (a & b)), result); + return result; + } + + @Test + @IR(counts = {IRNode.VECTOR_MASK_GEN, "1", + IRNode.OR_REDUCTION_V, "1"}, + applyIfCPUFeature = {"sve", "true"}, applyIf = {"MaxVectorSize", ">=32"}) + public int testOrReduction() { + IntVector v = IntVector.fromArray(ISPEC_128, ia, 0); + int result = v.reduceLanes(VectorOperators.OR); + Asserts.assertEquals(reduceLanes(0, ia, ISPEC_128.length(), (a, b) -> (a | b)), result); + return result; + } + + @Test + @IR(counts = {IRNode.VECTOR_MASK_GEN, "1", + IRNode.XOR_REDUCTION_V, "1"}, + applyIfCPUFeature = {"sve", "true"}, applyIf = {"MaxVectorSize", ">=32"}) + public int testXorReduction() { + IntVector v = IntVector.fromArray(ISPEC_128, ia, 0); + int result = v.reduceLanes(VectorOperators.XOR); + Asserts.assertEquals(reduceLanes(0, ia, ISPEC_128.length(), (a, b) -> (a ^ b)), result); + return result; + } + + // ===================== Reduction Tests - Min/Max ===================== + + // Reduction min operations with non-long types are implemented with NEON SIMD instructions + // when the vector size is less than or equal to 128-bit. + @Test + @IR(counts = {IRNode.VECTOR_MASK_GEN, "0", + IRNode.MIN_REDUCTION_V, "1"}, + applyIfCPUFeature = {"sve", "true"}, applyIf = {"MaxVectorSize", ">= 32"}) + public int testMinReductionInt_128() { + IntVector v = IntVector.fromArray(ISPEC_128, ia, 0); + int result = v.reduceLanes(VectorOperators.MIN); + Asserts.assertEquals(reduceLanes(Integer.MAX_VALUE, ia, ISPEC_128.length(), (a, b) -> Math.min(a, b)), result); + return result; + } + + @Test + @IR(counts = {IRNode.VECTOR_MASK_GEN, "1", + IRNode.MIN_REDUCTION_V, "1"}, + applyIfCPUFeature = {"sve", "true"}, applyIf = {"MaxVectorSize", ">= 64"}) + public int testMinReductionInt_256() { + IntVector v = IntVector.fromArray(ISPEC_256, ia, 0); + int result = v.reduceLanes(VectorOperators.MIN); + Asserts.assertEquals(reduceLanes(Integer.MAX_VALUE, ia, ISPEC_256.length(), (a, b) -> Math.min(a, b)), result); + return result; + } + + // Reduction max operations with non-long types are implemented with NEON SIMD instructions + // when the vector size is less than or equal to 128-bit. + @Test + @IR(counts = {IRNode.VECTOR_MASK_GEN, "0", + IRNode.MAX_REDUCTION_V, "1"}, + applyIfCPUFeature = {"sve", "true"}, applyIf = {"MaxVectorSize", ">= 32"}) + public int testMaxReductionInt_128() { + IntVector v = IntVector.fromArray(ISPEC_128, ia, 0); + int result = v.reduceLanes(VectorOperators.MAX); + Asserts.assertEquals(reduceLanes(Integer.MIN_VALUE, ia, ISPEC_128.length(), (a, b) -> Math.max(a, b)), result); + return result; + } + + @Test + @IR(counts = {IRNode.VECTOR_MASK_GEN, "1", + IRNode.MAX_REDUCTION_V, "1"}, + applyIfCPUFeature = {"sve", "true"}, applyIf = {"MaxVectorSize", ">= 64"}) + public int testMaxReductionInt_256() { + IntVector v = IntVector.fromArray(ISPEC_256, ia, 0); + int result = v.reduceLanes(VectorOperators.MAX); + Asserts.assertEquals(reduceLanes(Integer.MIN_VALUE, ia, ISPEC_256.length(), (a, b) -> Math.max(a, b)), result); + return result; + } + + @Test + @IR(counts = {IRNode.VECTOR_MASK_GEN, "1", + IRNode.MIN_REDUCTION_V, "1"}, + applyIfCPUFeature = {"sve", "true"}, applyIf = {"MaxVectorSize", ">= 32"}) + public static long testMinReductionLong() { + LongVector v = LongVector.fromArray(LSPEC_128, la, 0); + long result = v.reduceLanes(VectorOperators.MIN); + Asserts.assertEquals(reduceLanes(Long.MAX_VALUE, la, LSPEC_128.length(), (a, b) -> Math.min(a, b)), result); + return result; + } + + @Test + @IR(counts = {IRNode.VECTOR_MASK_GEN, "1", + IRNode.MAX_REDUCTION_V, "1"}, + applyIfCPUFeature = {"sve", "true"}, applyIf = {"MaxVectorSize", ">= 32"}) + public static long testMaxReductionLong() { + LongVector v = LongVector.fromArray(LSPEC_128, la, 0); + long result = v.reduceLanes(VectorOperators.MAX); + Asserts.assertEquals(reduceLanes(Long.MIN_VALUE, la, LSPEC_128.length(), (a, b) -> Math.max(a, b)), result); + return result; + } + + // ====================== VectorMask Tests ====================== + + @Test + @IR(counts = {IRNode.VECTOR_MASK_GEN, "1", + IRNode.VECTOR_LOAD_MASK, "1"}, + applyIfCPUFeature = {"sve", "true"}, applyIf = {"MaxVectorSize", ">= 32"}) + public static void testLoadMask() { + VectorMask vm = VectorMask.fromArray(ISPEC_128, m, 0); + vm.not().intoArray(mr, 0); + // Verify that the mask is loaded correctly. + for (int i = 0; i < ISPEC_128.length(); i++) { + Asserts.assertEquals(!m[i], mr[i]); + } + } + + @Test + @IR(counts = {IRNode.VECTOR_MASK_GEN, "1", + IRNode.VECTOR_MASK_CMP, "1"}, + applyIfCPUFeature = {"sve", "true"}, applyIf = {"MaxVectorSize", ">= 32"}) + public static void testVectorMaskCmp() { + IntVector v1 = IntVector.fromArray(ISPEC_128, ia, 0); + IntVector v2 = IntVector.fromArray(ISPEC_128, ib, 0); + VectorMask vm = v1.compare(VectorOperators.LT, v2); + vm.intoArray(mr, 0); + // Verify that the mask is generated correctly. + for (int i = 0; i < ISPEC_128.length(); i++) { + Asserts.assertEquals(ia[i] < ib[i], mr[i]); + } + } + + @Test + @IR(counts = {IRNode.VECTOR_MASK_GEN, "1", + IRNode.VECTOR_MASK_FIRST_TRUE, "1"}, + applyIfCPUFeature = {"sve", "true"}, applyIf = {"MaxVectorSize", ">= 32"}) + public static int testFirstTrue() { + VectorMask vm = ISPEC_128.maskAll(false); + int result = vm.firstTrue(); + // The result is the vector length if no lane is true. + // This is the default behavior of the firstTrue method. + Asserts.assertEquals(ISPEC_128.length(), result); + return result; + } + + public static void main(String[] args) { + TestFramework testFramework = new TestFramework(); + testFramework.setDefaultWarmup(10000) + .addFlags("--add-modules=jdk.incubator.vector") + .start(); + } +} From d36a234c1228fdb12eb5931506ba1e03ebae95fc Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Wed, 10 Dec 2025 02:26:04 +0000 Subject: [PATCH 237/706] 8368701: CDS VerifierTest_1A.java failed on machines with 512 GB RAM Reviewed-by: dholmes, lmesnik --- test/hotspot/jtreg/runtime/cds/appcds/VerifierTest.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/hotspot/jtreg/runtime/cds/appcds/VerifierTest.java b/test/hotspot/jtreg/runtime/cds/appcds/VerifierTest.java index 3ff5da98b42..e0001e021ad 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/VerifierTest.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/VerifierTest.java @@ -221,6 +221,8 @@ public class VerifierTest implements Opcodes { runtime_arg1 = runtime_arg2 = runtime_arg3 = runtime_setting; } TestCommon.run("-cp", jar, + "-Xms256m", + "-Xmx256m", "-Xlog:cds", runtime_arg1, runtime_arg2, runtime_arg3, "VerifierTest0") @@ -302,6 +304,8 @@ public class VerifierTest implements Opcodes { runtime_arg1 = runtime_arg2 = runtime_arg3 = runtime_setting; } TestCommon.run("-cp", jar, + "-Xms256m", + "-Xmx256m", "-Xlog:cds", runtime_arg1, runtime_arg2, runtime_arg3, "Hi") From a5968f936462741a7edea5bbbe73cb067af3d34f Mon Sep 17 00:00:00 2001 From: Anjian Wen Date: Wed, 10 Dec 2025 02:34:52 +0000 Subject: [PATCH 238/706] 8371968: RISC-V: implement AES CBC intrinsics Reviewed-by: fyang, fjiang --- src/hotspot/cpu/riscv/stubGenerator_riscv.cpp | 182 +++++++++++++++++- 1 file changed, 181 insertions(+), 1 deletion(-) diff --git a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp index d0cbe8ea347..49c80dce88a 100644 --- a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp +++ b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp @@ -2606,6 +2606,184 @@ class StubGenerator: public StubCodeGenerator { return start; } + void cipherBlockChaining_encryptAESCrypt(int round, Register from, Register to, Register key, + Register rvec, Register input_len) { + const Register len = x29; + + VectorRegister working_vregs[] = { + v1, v2, v3, v4, v5, v6, v7, v8, + v9, v10, v11, v12, v13, v14, v15 + }; + + const unsigned int BLOCK_SIZE = 16; + + __ mv(len, input_len); + // load init rvec + __ vsetivli(x0, 4, Assembler::e32, Assembler::m1); + __ vle32_v(v16, rvec); + + generate_aes_loadkeys(key, working_vregs, round); + Label L_enc_loop; + __ bind(L_enc_loop); + // Encrypt from source by block size + __ vle32_v(v17, from); + __ addi(from, from, BLOCK_SIZE); + __ vxor_vv(v16, v16, v17); + generate_aes_encrypt(v16, working_vregs, round); + __ vse32_v(v16, to); + __ addi(to, to, BLOCK_SIZE); + __ subi(len, len, BLOCK_SIZE); + __ bnez(len, L_enc_loop); + + // save current rvec and return + __ vse32_v(v16, rvec); + __ mv(x10, input_len); + __ leave(); + __ ret(); + } + + // Arguments: + // + // Inputs: + // c_rarg0 - source byte array address + // c_rarg1 - destination byte array address + // c_rarg2 - K (key) in little endian int array + // c_rarg3 - r vector byte array address + // c_rarg4 - input length + // + // Output: + // x10 - input length + // + address generate_cipherBlockChaining_encryptAESCrypt() { + assert(UseAESIntrinsics, "Must be"); + assert(UseZvkn, "need AES instructions (Zvkned extension) support"); + __ align(CodeEntryAlignment); + StubId stub_id = StubId::stubgen_cipherBlockChaining_encryptAESCrypt_id; + StubCodeMark mark(this, stub_id); + + const Register from = c_rarg0; + const Register to = c_rarg1; + const Register key = c_rarg2; + const Register rvec = c_rarg3; + const Register input_len = c_rarg4; + + const Register keylen = x28; + + address start = __ pc(); + __ enter(); + + Label L_aes128, L_aes192; + // Compute #rounds for AES based on the length of the key array + __ lwu(keylen, Address(key, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT))); + __ mv(t0, 52); + __ bltu(keylen, t0, L_aes128); + __ beq(keylen, t0, L_aes192); + // Else we fallthrough to the biggest case (256-bit key size) + + // Note: the following function performs key += 15*16 + cipherBlockChaining_encryptAESCrypt(15, from, to, key, rvec, input_len); + + // Note: the following function performs key += 11*16 + __ bind(L_aes128); + cipherBlockChaining_encryptAESCrypt(11, from, to, key, rvec, input_len); + + // Note: the following function performs key += 13*16 + __ bind(L_aes192); + cipherBlockChaining_encryptAESCrypt(13, from, to, key, rvec, input_len); + + return start; + } + + void cipherBlockChaining_decryptAESCrypt(int round, Register from, Register to, Register key, + Register rvec, Register input_len) { + const Register len = x29; + + VectorRegister working_vregs[] = { + v1, v2, v3, v4, v5, v6, v7, v8, + v9, v10, v11, v12, v13, v14, v15 + }; + + const unsigned int BLOCK_SIZE = 16; + + __ mv(len, input_len); + // load init rvec + __ vsetivli(x0, 4, Assembler::e32, Assembler::m1); + __ vle32_v(v16, rvec); + + generate_aes_loadkeys(key, working_vregs, round); + Label L_dec_loop; + // Decrypt from source by block size + __ bind(L_dec_loop); + __ vle32_v(v17, from); + __ addi(from, from, BLOCK_SIZE); + __ vmv_v_v(v18, v17); + generate_aes_decrypt(v17, working_vregs, round); + __ vxor_vv(v17, v17, v16); + __ vse32_v(v17, to); + __ vmv_v_v(v16, v18); + __ addi(to, to, BLOCK_SIZE); + __ subi(len, len, BLOCK_SIZE); + __ bnez(len, L_dec_loop); + + // save current rvec and return + __ vse32_v(v16, rvec); + __ mv(x10, input_len); + __ leave(); + __ ret(); + } + + // Arguments: + // + // Inputs: + // c_rarg0 - source byte array address + // c_rarg1 - destination byte array address + // c_rarg2 - K (key) in little endian int array + // c_rarg3 - r vector byte array address + // c_rarg4 - input length + // + // Output: + // x10 - input length + // + address generate_cipherBlockChaining_decryptAESCrypt() { + assert(UseAESIntrinsics, "Must be"); + assert(UseZvkn, "need AES instructions (Zvkned extension) support"); + __ align(CodeEntryAlignment); + StubId stub_id = StubId::stubgen_cipherBlockChaining_decryptAESCrypt_id; + StubCodeMark mark(this, stub_id); + + const Register from = c_rarg0; + const Register to = c_rarg1; + const Register key = c_rarg2; + const Register rvec = c_rarg3; + const Register input_len = c_rarg4; + + const Register keylen = x28; + + address start = __ pc(); + __ enter(); + + Label L_aes128, L_aes192, L_aes128_loop, L_aes192_loop, L_aes256_loop; + // Compute #rounds for AES based on the length of the key array + __ lwu(keylen, Address(key, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT))); + __ mv(t0, 52); + __ bltu(keylen, t0, L_aes128); + __ beq(keylen, t0, L_aes192); + // Else we fallthrough to the biggest case (256-bit key size) + + // Note: the following function performs key += 15*16 + cipherBlockChaining_decryptAESCrypt(15, from, to, key, rvec, input_len); + + // Note: the following function performs key += 11*16 + __ bind(L_aes128); + cipherBlockChaining_decryptAESCrypt(11, from, to, key, rvec, input_len); + + // Note: the following function performs key += 13*16 + __ bind(L_aes192); + cipherBlockChaining_decryptAESCrypt(13, from, to, key, rvec, input_len); + + return start; + } + // Load big-endian 128-bit from memory. void be_load_counter_128(Register counter_hi, Register counter_lo, Register counter) { __ ld(counter_lo, Address(counter, 8)); // Load 128-bits from counter @@ -2772,8 +2950,8 @@ class StubGenerator: public StubCodeGenerator { // x10 - input length // address generate_counterMode_AESCrypt() { + assert(UseAESCTRIntrinsics, "Must be"); assert(UseZvkn, "need AES instructions (Zvkned extension) support"); - assert(UseAESCTRIntrinsics, "need AES instructions (Zvkned extension) support"); assert(UseZbb, "need basic bit manipulation (Zbb extension) support"); __ align(CodeEntryAlignment); @@ -7041,6 +7219,8 @@ static const int64_t right_3_bits = right_n_bits(3); if (UseAESIntrinsics) { StubRoutines::_aescrypt_encryptBlock = generate_aescrypt_encryptBlock(); StubRoutines::_aescrypt_decryptBlock = generate_aescrypt_decryptBlock(); + StubRoutines::_cipherBlockChaining_encryptAESCrypt = generate_cipherBlockChaining_encryptAESCrypt(); + StubRoutines::_cipherBlockChaining_decryptAESCrypt = generate_cipherBlockChaining_decryptAESCrypt(); } if (UseAESCTRIntrinsics) { From 1bbbce75c5e68429c2a32519eb3c36d964dcdf57 Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Wed, 10 Dec 2025 04:31:37 +0000 Subject: [PATCH 239/706] 6726690: SwingUtilities.replaceUI*Map() methods do not remove previously installed maps Reviewed-by: azvegint, tr --- .../classes/javax/swing/SwingUtilities.java | 6 ++ .../javax/swing/SwingUtilities/UIMapTest.java | 90 +++++++++++++++++++ 2 files changed, 96 insertions(+) create mode 100644 test/jdk/javax/swing/SwingUtilities/UIMapTest.java diff --git a/src/java.desktop/share/classes/javax/swing/SwingUtilities.java b/src/java.desktop/share/classes/javax/swing/SwingUtilities.java index 4633e9c4756..70fbeee8c7b 100644 --- a/src/java.desktop/share/classes/javax/swing/SwingUtilities.java +++ b/src/java.desktop/share/classes/javax/swing/SwingUtilities.java @@ -1813,6 +1813,9 @@ public class SwingUtilities implements SwingConstants while (map != null) { InputMap parent = map.getParent(); + if (uiInputMap == null) { + map.clear(); + } if (parent == null || (parent instanceof UIResource)) { map.setParent(uiInputMap); return; @@ -1837,6 +1840,9 @@ public class SwingUtilities implements SwingConstants while (map != null) { ActionMap parent = map.getParent(); + if (uiActionMap == null) { + map.clear(); + } if (parent == null || (parent instanceof UIResource)) { map.setParent(uiActionMap); return; diff --git a/test/jdk/javax/swing/SwingUtilities/UIMapTest.java b/test/jdk/javax/swing/SwingUtilities/UIMapTest.java new file mode 100644 index 00000000000..4a801580b35 --- /dev/null +++ b/test/jdk/javax/swing/SwingUtilities/UIMapTest.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2025, 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 6726690 + * @summary Verifies SwingUtilities.replaceUI*Map() methods remove + * previously installed maps + * @run main UIMapTest + */ + +import java.awt.event.ActionEvent; +import java.awt.event.KeyEvent; +import javax.swing.AbstractAction; +import javax.swing.Action; +import javax.swing.ActionMap; +import javax.swing.ComponentInputMap; +import javax.swing.InputMap; +import javax.swing.JButton; +import javax.swing.JComponent; +import javax.swing.JFrame; +import javax.swing.KeyStroke; +import javax.swing.SwingUtilities; + +public class UIMapTest { + + public static void main(String[] args) { + + StringBuilder str = new StringBuilder(); + + // Create the test button + JButton button = new JButton("Test"); + + // Create an input map that maps ENTER to the button + ComponentInputMap map = new ComponentInputMap(button); + map.put(KeyStroke.getKeyStroke("pressed ENTER"), "pressed"); + map.put(KeyStroke.getKeyStroke("released ENTER"), "released"); + + // Add the map + SwingUtilities.replaceUIInputMap(button, JComponent.WHEN_IN_FOCUSED_WINDOW, map); + + // Attempt to remove the map + SwingUtilities.replaceUIInputMap(button, JComponent.WHEN_IN_FOCUSED_WINDOW, null); + + if (button.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW). + get(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0)) != null) { + str.append("\nSwingUtilities.replaceUIInputMap " + + "didn't remove previously installed input map"); + } + + // Get the InputMap for the button when it has focus + InputMap inputMap = button.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW); + + // Map the VK_ENTER key stroke to a specific action name + inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "doEnterAction"); + Action enterAction = new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { } + }; + button.getActionMap().put("doEnterAction", enterAction); + SwingUtilities.replaceUIActionMap(button, null); + if (button.getActionMap().size() != 0) { + str.append("\nSwingUtilities.replaceUIActionMap " + + "didn't remove previously installed action map"); + } + if (str.length() != 0) { + throw new RuntimeException(str.toString()); + } + } +} From 00068a80304a809297d0df8698850861e9a1c5e9 Mon Sep 17 00:00:00 2001 From: Roland Westrelin Date: Wed, 10 Dec 2025 08:45:20 +0000 Subject: [PATCH 240/706] 8354282: C2: more crashes in compiled code because of dependency on removed range check CastIIs Reviewed-by: chagedorn, qamai, galder, epeter --- .../gc/shenandoah/c2/shenandoahSupport.cpp | 2 +- src/hotspot/share/opto/castnode.cpp | 141 ++++++++++------ src/hotspot/share/opto/castnode.hpp | 151 +++++++++++++++--- src/hotspot/share/opto/cfgnode.cpp | 10 +- src/hotspot/share/opto/compile.cpp | 2 +- src/hotspot/share/opto/escape.cpp | 6 +- src/hotspot/share/opto/library_call.cpp | 4 +- src/hotspot/share/opto/loopTransform.cpp | 4 +- src/hotspot/share/opto/loopnode.cpp | 6 +- src/hotspot/share/opto/loopopts.cpp | 4 +- src/hotspot/share/opto/macroArrayCopy.cpp | 2 +- .../c2/irTests/TestPushAddThruCast.java | 29 +++- ...yAccessAboveRCAfterRCCastIIEliminated.java | 82 +++++++++- 13 files changed, 341 insertions(+), 102 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp b/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp index 35ec9ed5c8c..40fe0c00490 100644 --- a/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp +++ b/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp @@ -1394,7 +1394,7 @@ void ShenandoahBarrierC2Support::pin_and_expand(PhaseIdealLoop* phase) { } if (addr->Opcode() == Op_AddP) { Node* orig_base = addr->in(AddPNode::Base); - Node* base = new CheckCastPPNode(ctrl, orig_base, orig_base->bottom_type(), ConstraintCastNode::StrongDependency); + Node* base = new CheckCastPPNode(ctrl, orig_base, orig_base->bottom_type(), ConstraintCastNode::DependencyType::NonFloatingNarrowing); phase->register_new_node(base, ctrl); if (addr->in(AddPNode::Base) == addr->in((AddPNode::Address))) { // Field access diff --git a/src/hotspot/share/opto/castnode.cpp b/src/hotspot/share/opto/castnode.cpp index 6d899c1f950..9c764f22e38 100644 --- a/src/hotspot/share/opto/castnode.cpp +++ b/src/hotspot/share/opto/castnode.cpp @@ -22,7 +22,6 @@ * */ -#include "castnode.hpp" #include "opto/addnode.hpp" #include "opto/callnode.hpp" #include "opto/castnode.hpp" @@ -35,12 +34,22 @@ #include "opto/type.hpp" #include "utilities/checkedCast.hpp" +const ConstraintCastNode::DependencyType ConstraintCastNode::DependencyType::FloatingNarrowing(true, true, "floating narrowing dependency"); // not pinned, narrows type +const ConstraintCastNode::DependencyType ConstraintCastNode::DependencyType::FloatingNonNarrowing(true, false, "floating non-narrowing dependency"); // not pinned, doesn't narrow type +const ConstraintCastNode::DependencyType ConstraintCastNode::DependencyType::NonFloatingNarrowing(false, true, "non-floating narrowing dependency"); // pinned, narrows type +const ConstraintCastNode::DependencyType ConstraintCastNode::DependencyType::NonFloatingNonNarrowing(false, false, "non-floating non-narrowing dependency"); // pinned, doesn't narrow type + //============================================================================= // If input is already higher or equal to cast type, then this is an identity. Node* ConstraintCastNode::Identity(PhaseGVN* phase) { - if (_dependency == UnconditionalDependency) { + if (!_dependency.narrows_type()) { + // If this cast doesn't carry a type dependency (i.e. not used for type narrowing), we cannot optimize it. return this; } + + // This cast node carries a type dependency. We can remove it if: + // - Its input has a narrower type + // - There's a dominating cast with same input but narrower type Node* dom = dominating_cast(phase, phase); if (dom != nullptr) { return dom; @@ -109,7 +118,7 @@ Node* ConstraintCastNode::Ideal(PhaseGVN* phase, bool can_reshape) { } uint ConstraintCastNode::hash() const { - return TypeNode::hash() + (int)_dependency + (_extra_types != nullptr ? _extra_types->hash() : 0); + return TypeNode::hash() + _dependency.hash() + (_extra_types != nullptr ? _extra_types->hash() : 0); } bool ConstraintCastNode::cmp(const Node &n) const { @@ -117,7 +126,7 @@ bool ConstraintCastNode::cmp(const Node &n) const { return false; } ConstraintCastNode& cast = (ConstraintCastNode&) n; - if (cast._dependency != _dependency) { + if (!cast._dependency.cmp(_dependency)) { return false; } if (_extra_types == nullptr || cast._extra_types == nullptr) { @@ -130,7 +139,7 @@ uint ConstraintCastNode::size_of() const { return sizeof(*this); } -Node* ConstraintCastNode::make_cast_for_basic_type(Node* c, Node* n, const Type* t, DependencyType dependency, BasicType bt) { +Node* ConstraintCastNode::make_cast_for_basic_type(Node* c, Node* n, const Type* t, const DependencyType& dependency, BasicType bt) { switch(bt) { case T_INT: return new CastIINode(c, n, t, dependency); @@ -143,9 +152,9 @@ Node* ConstraintCastNode::make_cast_for_basic_type(Node* c, Node* n, const Type* } TypeNode* ConstraintCastNode::dominating_cast(PhaseGVN* gvn, PhaseTransform* pt) const { - if (_dependency == UnconditionalDependency) { - return nullptr; - } + // See discussion at definition of ConstraintCastNode::DependencyType: replacing this cast with a dominating one is + // not safe if _dependency.narrows_type() is not true. + assert(_dependency.narrows_type(), "cast can't be replaced by dominating one"); Node* val = in(1); Node* ctl = in(0); int opc = Opcode(); @@ -205,30 +214,21 @@ void ConstraintCastNode::dump_spec(outputStream *st) const { st->print(" extra types: "); _extra_types->dump_on(st); } - if (_dependency != RegularDependency) { - st->print(" %s dependency", _dependency == StrongDependency ? "strong" : "unconditional"); - } + st->print(" "); + _dependency.dump_on(st); } #endif -const Type* CastIINode::Value(PhaseGVN* phase) const { - const Type *res = ConstraintCastNode::Value(phase); - if (res == Type::TOP) { - return Type::TOP; - } - assert(res->isa_int(), "res must be int"); - - // Similar to ConvI2LNode::Value() for the same reasons - // see if we can remove type assertion after loop opts - res = widen_type(phase, res, T_INT); - - return res; +CastIINode* CastIINode::make_with(Node* parent, const TypeInteger* type, const DependencyType& dependency) const { + return new CastIINode(in(0), parent, type, dependency, _range_check_dependency, _extra_types); } -Node* ConstraintCastNode::find_or_make_integer_cast(PhaseIterGVN* igvn, Node* parent, const TypeInteger* type) const { - Node* n = clone(); - n->set_req(1, parent); - n->as_ConstraintCast()->set_type(type); +CastLLNode* CastLLNode::make_with(Node* parent, const TypeInteger* type, const DependencyType& dependency) const { + return new CastLLNode(in(0), parent, type, dependency, _extra_types); +} + +Node* ConstraintCastNode::find_or_make_integer_cast(PhaseIterGVN* igvn, Node* parent, const TypeInteger* type, const DependencyType& dependency) const { + Node* n = make_with(parent, type, dependency); Node* existing = igvn->hash_find_insert(n); if (existing != nullptr) { n->destruct(igvn); @@ -242,14 +242,13 @@ Node *CastIINode::Ideal(PhaseGVN *phase, bool can_reshape) { if (progress != nullptr) { return progress; } - if (can_reshape && !phase->C->post_loop_opts_phase()) { - // makes sure we run ::Value to potentially remove type assertion after loop opts + if (!phase->C->post_loop_opts_phase()) { + // makes sure we run widen_type() to potentially common type assertions after loop opts phase->C->record_for_post_loop_opts_igvn(this); } if (!_range_check_dependency || phase->C->post_loop_opts_phase()) { return optimize_integer_cast(phase, T_INT); } - phase->C->record_for_post_loop_opts_igvn(this); return nullptr; } @@ -279,9 +278,9 @@ void CastIINode::dump_spec(outputStream* st) const { #endif CastIINode* CastIINode::pin_array_access_node() const { - assert(_dependency == RegularDependency, "already pinned"); + assert(_dependency.is_floating(), "already pinned"); if (has_range_check()) { - return new CastIINode(in(0), in(1), bottom_type(), StrongDependency, has_range_check()); + return new CastIINode(in(0), in(1), bottom_type(), _dependency.with_pinned_dependency(), has_range_check()); } return nullptr; } @@ -315,16 +314,6 @@ void CastIINode::remove_range_check_cast(Compile* C) { } -const Type* CastLLNode::Value(PhaseGVN* phase) const { - const Type* res = ConstraintCastNode::Value(phase); - if (res == Type::TOP) { - return Type::TOP; - } - assert(res->isa_long(), "res must be long"); - - return widen_type(phase, res, T_LONG); -} - bool CastLLNode::is_inner_loop_backedge(ProjNode* proj) { if (proj != nullptr) { Node* ctrl_use = proj->unique_ctrl_out_or_null(); @@ -392,7 +381,7 @@ Node* CastLLNode::Ideal(PhaseGVN* phase, bool can_reshape) { return progress; } if (!phase->C->post_loop_opts_phase()) { - // makes sure we run ::Value to potentially remove type assertion after loop opts + // makes sure we run widen_type() to potentially common type assertions after loop opts phase->C->record_for_post_loop_opts_igvn(this); } // transform (CastLL (ConvI2L ..)) into (ConvI2L (CastII ..)) if the type of the CastLL is narrower than the type of @@ -543,7 +532,7 @@ Node* CastP2XNode::Identity(PhaseGVN* phase) { return this; } -Node* ConstraintCastNode::make_cast_for_type(Node* c, Node* in, const Type* type, DependencyType dependency, +Node* ConstraintCastNode::make_cast_for_type(Node* c, Node* in, const Type* type, const DependencyType& dependency, const TypeTuple* types) { if (type->isa_int()) { return new CastIINode(c, in, type, dependency, false, types); @@ -564,7 +553,7 @@ Node* ConstraintCastNode::make_cast_for_type(Node* c, Node* in, const Type* type return nullptr; } -Node* ConstraintCastNode::optimize_integer_cast(PhaseGVN* phase, BasicType bt) { +Node* ConstraintCastNode::optimize_integer_cast_of_add(PhaseGVN* phase, BasicType bt) { PhaseIterGVN *igvn = phase->is_IterGVN(); const TypeInteger* this_type = this->type()->isa_integer(bt); if (this_type == nullptr) { @@ -586,8 +575,42 @@ Node* ConstraintCastNode::optimize_integer_cast(PhaseGVN* phase, BasicType bt) { Node* x = z->in(1); Node* y = z->in(2); - Node* cx = find_or_make_integer_cast(igvn, x, rx); - Node* cy = find_or_make_integer_cast(igvn, y, ry); + const TypeInteger* tx = phase->type(x)->is_integer(bt); + const TypeInteger* ty = phase->type(y)->is_integer(bt); + + // (Cast (Add x y) tz) is transformed into (Add (Cast x rx) (Cast y ry)) + // + // tz = [tzlo, tzhi] + // rx = [rxlo, rxhi] + // ry = [rylo, ryhi] + // with type of x, tx = [txlo, txhi] + // with type of y, ty = [tylo, tyhi] + // + // From Compile::push_thru_add(): + // rxlo = max(tzlo - tyhi, txlo) + // rxhi = min(tzhi - tylo, txhi) + // rylo = max(tzlo - txhi, tylo) + // ryhi = min(tzhi - txlo, tyhi) + // + // If x is a constant, then txlo = txhi + // rxlo = txlo, rxhi = txhi + // The bounds of the type of the Add after transformation then is: + // rxlo + rylo >= txlo + tzlo - txhi >= tzlo + // rxhi + ryhi <= txhi + tzhi - txlo <= tzhi + // The resulting type is not wider than the type of the Cast + // before transformation + // + // If neither x nor y are constant then the type of the resulting + // Add can be wider than the type of the type of the Cast before + // transformation. + // For instance, tx = [0, 10], ty = [0, 10], tz = [0, 10] + // then rx = [0, 10], ry = [0, 10] + // and rx + ry = [0, 20] which is wider than tz + // + // Same reasoning applies to (Cast (Sub x y) tz) + const DependencyType& dependency = (!tx->is_con() && !ty->is_con()) ? _dependency.with_non_narrowing() : _dependency; + Node* cx = find_or_make_integer_cast(igvn, x, rx, dependency); + Node* cy = find_or_make_integer_cast(igvn, y, ry, dependency); if (op == Op_Add(bt)) { return AddNode::make(cx, cy, bt); } else { @@ -599,11 +622,26 @@ Node* ConstraintCastNode::optimize_integer_cast(PhaseGVN* phase, BasicType bt) { return nullptr; } -const Type* ConstraintCastNode::widen_type(const PhaseGVN* phase, const Type* res, BasicType bt) const { - if (!phase->C->post_loop_opts_phase()) { +Node* ConstraintCastNode::optimize_integer_cast(PhaseGVN* phase, BasicType bt) { + Node* res = optimize_integer_cast_of_add(phase, bt); + if (res != nullptr) { return res; } + const Type* t = Value(phase); + if (t != Type::TOP && phase->C->post_loop_opts_phase()) { + const Type* bottom_t = bottom_type(); + const TypeInteger* wide_t = widen_type(phase, bottom_t, bt); + if (wide_t != bottom_t) { + // Widening the type of the Cast (to allow some commoning) causes the Cast to change how it can be optimized (if + // type of its input is narrower than the Cast's type, we can't remove it to not loose the control dependency). + return make_with(in(1), wide_t, _dependency.with_non_narrowing()); + } + } + return nullptr; +} +const TypeInteger* ConstraintCastNode::widen_type(const PhaseGVN* phase, const Type* res, BasicType bt) const { + const TypeInteger* this_type = res->is_integer(bt); // At VerifyConstraintCasts == 1, we verify the ConstraintCastNodes that are present during code // emission. This allows us detecting possible mis-scheduling due to these nodes being pinned at // the wrong control nodes. @@ -612,10 +650,9 @@ const Type* ConstraintCastNode::widen_type(const PhaseGVN* phase, const Type* re // mis-transformations that may happen due to these nodes being pinned at the wrong control // nodes. if (VerifyConstraintCasts > 1) { - return res; + return this_type; } - const TypeInteger* this_type = res->is_integer(bt); const TypeInteger* in_type = phase->type(in(1))->isa_integer(bt); if (in_type != nullptr && (in_type->lo_as_long() != this_type->lo_as_long() || @@ -636,5 +673,5 @@ const Type* ConstraintCastNode::widen_type(const PhaseGVN* phase, const Type* re MIN2(in_type->hi_as_long(), hi1), MAX2((int)in_type->_widen, w1), bt); } - return res; + return this_type; } diff --git a/src/hotspot/share/opto/castnode.hpp b/src/hotspot/share/opto/castnode.hpp index 3c6ade64aa8..2ff13e44780 100644 --- a/src/hotspot/share/opto/castnode.hpp +++ b/src/hotspot/share/opto/castnode.hpp @@ -33,21 +33,119 @@ // cast to a different range class ConstraintCastNode: public TypeNode { public: - enum DependencyType { - RegularDependency, // if cast doesn't improve input type, cast can be removed - StrongDependency, // leave cast in even if _type doesn't improve input type, can be replaced by stricter dominating cast if one exist - UnconditionalDependency // leave cast in unconditionally + // Cast nodes are subject to a few optimizations: + // + // 1- if the type carried by the Cast doesn't narrow the type of its input, the cast can be replaced by its input. + // Similarly, if a dominating Cast with the same input and a narrower type constraint is found, it can replace the + // current cast. + // + // 2- if the condition that the Cast is control dependent is hoisted, the Cast is hoisted as well + // + // 1- and 2- are not always applied depending on what constraint are applied to the Cast: there are cases where 1- + // and 2- apply, where neither 1- nor 2- apply and where one or the other apply. This class abstract away these + // details. + // + // If _narrows_type is true, the cast carries a type dependency: "after" the control the cast is dependent on, its data + // input is known to have a narrower type (stored in the cast node itself). Optimizations 1- above only apply to cast + // nodes for which _narrows_type is true. + // if _floating is true, the cast only depends on a single control: its control input. Otherwise, it is pinned at its + // current location. Optimizations 2- only apply to cast nodes for which _floating is true. + // _floating here is similar to Node::depends_only_on_test(). + // The 4 combinations of _narrows_types/_floating true/false have some use. See below, at the end of this class + // definition, for examples. + class DependencyType { + private: + const bool _floating; // Does this Cast depends on its control input or is it pinned? + const bool _narrows_type; // Does this Cast narrows the type i.e. if input type is narrower can it be removed? + const char* _desc; + DependencyType(bool depends_on_test, bool narrows_type, const char* desc) + : _floating(depends_on_test), + _narrows_type(narrows_type), + _desc(desc) { + } + NONCOPYABLE(DependencyType); + + public: + + bool is_floating() const { + return _floating; + } + + bool narrows_type() const { + return _narrows_type; + } + + void dump_on(outputStream *st) const { + st->print("%s", _desc); + } + + uint hash() const { + return (_floating ? 1 : 0) + (_narrows_type ? 2 : 0); + } + + bool cmp(const DependencyType& other) const { + return _floating == other._floating && _narrows_type == other._narrows_type; + } + + const DependencyType& with_non_narrowing() const { + if (_floating) { + return FloatingNonNarrowing; + } + return NonFloatingNonNarrowing; + } + + const DependencyType& with_pinned_dependency() const { + if (_narrows_type) { + return NonFloatingNarrowing; + } + return NonFloatingNonNarrowing; + } + + // All the possible combinations of floating/narrowing with example use cases: + + // Use case example: Range Check CastII + // Floating: The Cast is only dependent on the single range check. If the range check was ever to be hoisted it + // would be safe to let the Cast float to where the range check is hoisted up to. + // Narrowing: The Cast narrows the type to a positive index. If the input to the Cast is narrower, we can safely + // remove the cast because the array access will be safe. + static const DependencyType FloatingNarrowing; + // Use case example: Widening Cast nodes' types after loop opts: We want to common Casts with slightly different types. + // Floating: These Casts only depend on the single control. + // NonNarrowing: Even when the input type is narrower, we are not removing the Cast. Otherwise, the dependency + // to the single control is lost, and an array access could float above its range check because we + // just removed the dependency to the range check by removing the Cast. This could lead to an + // out-of-bounds access. + static const DependencyType FloatingNonNarrowing; + // Use case example: An array accesses that is no longer dependent on a single range check (e.g. range check smearing). + // NonFloating: The array access must be pinned below all the checks it depends on. If the check it directly depends + // on with a control input is hoisted, we do not hoist the Cast as well. If we allowed the Cast to float, + // we risk that the array access ends up above another check it depends on (we cannot model two control + // dependencies for a node in the IR). This could lead to an out-of-bounds access. + // Narrowing: If the Cast does not narrow the input type, then it's safe to remove the cast because the array access + // will be safe. + static const DependencyType NonFloatingNarrowing; + // Use case example: Sinking nodes out of a loop + // Non-Floating & Non-Narrowing: We don't want the Cast that forces the node to be out of loop to be removed in any + // case. Otherwise, the sunk node could float back into the loop, undoing the sinking. + // This Cast is only used for pinning without caring about narrowing types. + static const DependencyType NonFloatingNonNarrowing; + }; - protected: - const DependencyType _dependency; +protected: + const DependencyType& _dependency; virtual bool cmp( const Node &n ) const; virtual uint size_of() const; virtual uint hash() const; // Check the type - const Type* widen_type(const PhaseGVN* phase, const Type* res, BasicType bt) const; - Node* find_or_make_integer_cast(PhaseIterGVN* igvn, Node* parent, const TypeInteger* type) const; + const TypeInteger* widen_type(const PhaseGVN* phase, const Type* res, BasicType bt) const; + + virtual ConstraintCastNode* make_with(Node* parent, const TypeInteger* type, const DependencyType& dependency) const { + ShouldNotReachHere(); // Only implemented for CastII and CastLL + return nullptr; + } + + Node* find_or_make_integer_cast(PhaseIterGVN* igvn, Node* parent, const TypeInteger* type, const DependencyType& dependency) const; - private: // PhiNode::Ideal() transforms a Phi that merges a single uncasted value into a single cast pinned at the region. // The types of cast nodes eliminated as a consequence of this transformation are collected and stored here so the // type dependencies carried by the cast are known. The cast can then be eliminated if the type of its input is @@ -55,7 +153,7 @@ public: const TypeTuple* _extra_types; public: - ConstraintCastNode(Node* ctrl, Node* n, const Type* t, ConstraintCastNode::DependencyType dependency, + ConstraintCastNode(Node* ctrl, Node* n, const Type* t, const DependencyType& dependency, const TypeTuple* extra_types) : TypeNode(t,2), _dependency(dependency), _extra_types(extra_types) { init_class_id(Class_ConstraintCast); @@ -67,18 +165,21 @@ public: virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); virtual int Opcode() const; virtual uint ideal_reg() const = 0; - virtual bool depends_only_on_test() const { return _dependency == RegularDependency; } - bool carry_dependency() const { return _dependency != RegularDependency; } + bool carry_dependency() const { return !_dependency.cmp(DependencyType::FloatingNarrowing); } + // A cast node depends_only_on_test if and only if it is floating + virtual bool depends_only_on_test() const { return _dependency.is_floating(); } + const DependencyType& dependency() const { return _dependency; } TypeNode* dominating_cast(PhaseGVN* gvn, PhaseTransform* pt) const; - static Node* make_cast_for_basic_type(Node* c, Node* n, const Type* t, DependencyType dependency, BasicType bt); + static Node* make_cast_for_basic_type(Node* c, Node* n, const Type* t, const DependencyType& dependency, BasicType bt); #ifndef PRODUCT virtual void dump_spec(outputStream *st) const; #endif - static Node* make_cast_for_type(Node* c, Node* in, const Type* type, DependencyType dependency, + static Node* make_cast_for_type(Node* c, Node* in, const Type* type, const DependencyType& dependency, const TypeTuple* types); + Node* optimize_integer_cast_of_add(PhaseGVN* phase, BasicType bt); Node* optimize_integer_cast(PhaseGVN* phase, BasicType bt); bool higher_equal_types(PhaseGVN* phase, const Node* other) const; @@ -102,7 +203,7 @@ class CastIINode: public ConstraintCastNode { virtual uint size_of() const; public: - CastIINode(Node* ctrl, Node* n, const Type* t, DependencyType dependency = RegularDependency, bool range_check_dependency = false, const TypeTuple* types = nullptr) + CastIINode(Node* ctrl, Node* n, const Type* t, const DependencyType& dependency = DependencyType::FloatingNarrowing, bool range_check_dependency = false, const TypeTuple* types = nullptr) : ConstraintCastNode(ctrl, n, t, dependency, types), _range_check_dependency(range_check_dependency) { assert(ctrl != nullptr, "control must be set"); init_class_id(Class_CastII); @@ -110,7 +211,7 @@ class CastIINode: public ConstraintCastNode { virtual int Opcode() const; virtual uint ideal_reg() const { return Op_RegI; } virtual Node* Identity(PhaseGVN* phase); - virtual const Type* Value(PhaseGVN* phase) const; + virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); bool has_range_check() const { #ifdef _LP64 @@ -122,6 +223,7 @@ class CastIINode: public ConstraintCastNode { } CastIINode* pin_array_access_node() const; + CastIINode* make_with(Node* parent, const TypeInteger* type, const DependencyType& dependency) const; void remove_range_check_cast(Compile* C); #ifndef PRODUCT @@ -131,14 +233,12 @@ class CastIINode: public ConstraintCastNode { class CastLLNode: public ConstraintCastNode { public: - CastLLNode(Node* ctrl, Node* n, const Type* t, DependencyType dependency = RegularDependency, const TypeTuple* types = nullptr) + CastLLNode(Node* ctrl, Node* n, const Type* t, const DependencyType& dependency = DependencyType::FloatingNarrowing, const TypeTuple* types = nullptr) : ConstraintCastNode(ctrl, n, t, dependency, types) { assert(ctrl != nullptr, "control must be set"); init_class_id(Class_CastLL); } - virtual const Type* Value(PhaseGVN* phase) const; - static bool is_inner_loop_backedge(ProjNode* proj); static bool cmp_used_at_inner_loop_exit_test(CmpNode* cmp); @@ -147,11 +247,12 @@ public: virtual Node* Ideal(PhaseGVN* phase, bool can_reshape); virtual int Opcode() const; virtual uint ideal_reg() const { return Op_RegL; } + CastLLNode* make_with(Node* parent, const TypeInteger* type, const DependencyType& dependency) const; }; class CastHHNode: public ConstraintCastNode { public: - CastHHNode(Node* ctrl, Node* n, const Type* t, DependencyType dependency = RegularDependency, const TypeTuple* types = nullptr) + CastHHNode(Node* ctrl, Node* n, const Type* t, const DependencyType& dependency = DependencyType::FloatingNarrowing, const TypeTuple* types = nullptr) : ConstraintCastNode(ctrl, n, t, dependency, types) { assert(ctrl != nullptr, "control must be set"); init_class_id(Class_CastHH); @@ -162,7 +263,7 @@ public: class CastFFNode: public ConstraintCastNode { public: - CastFFNode(Node* ctrl, Node* n, const Type* t, DependencyType dependency = RegularDependency, const TypeTuple* types = nullptr) + CastFFNode(Node* ctrl, Node* n, const Type* t, const DependencyType& dependency = DependencyType::FloatingNarrowing, const TypeTuple* types = nullptr) : ConstraintCastNode(ctrl, n, t, dependency, types) { assert(ctrl != nullptr, "control must be set"); init_class_id(Class_CastFF); @@ -173,7 +274,7 @@ public: class CastDDNode: public ConstraintCastNode { public: - CastDDNode(Node* ctrl, Node* n, const Type* t, DependencyType dependency = RegularDependency, const TypeTuple* types = nullptr) + CastDDNode(Node* ctrl, Node* n, const Type* t, const DependencyType& dependency = DependencyType::FloatingNarrowing, const TypeTuple* types = nullptr) : ConstraintCastNode(ctrl, n, t, dependency, types) { assert(ctrl != nullptr, "control must be set"); init_class_id(Class_CastDD); @@ -184,7 +285,7 @@ public: class CastVVNode: public ConstraintCastNode { public: - CastVVNode(Node* ctrl, Node* n, const Type* t, DependencyType dependency = RegularDependency, const TypeTuple* types = nullptr) + CastVVNode(Node* ctrl, Node* n, const Type* t, const DependencyType& dependency = DependencyType::FloatingNarrowing, const TypeTuple* types = nullptr) : ConstraintCastNode(ctrl, n, t, dependency, types) { assert(ctrl != nullptr, "control must be set"); init_class_id(Class_CastVV); @@ -198,7 +299,7 @@ public: // cast pointer to pointer (different type) class CastPPNode: public ConstraintCastNode { public: - CastPPNode (Node* ctrl, Node* n, const Type* t, DependencyType dependency = RegularDependency, const TypeTuple* types = nullptr) + CastPPNode (Node* ctrl, Node* n, const Type* t, const DependencyType& dependency = DependencyType::FloatingNarrowing, const TypeTuple* types = nullptr) : ConstraintCastNode(ctrl, n, t, dependency, types) { init_class_id(Class_CastPP); } @@ -210,7 +311,7 @@ class CastPPNode: public ConstraintCastNode { // for _checkcast, cast pointer to pointer (different type), without JOIN, class CheckCastPPNode: public ConstraintCastNode { public: - CheckCastPPNode(Node* ctrl, Node* n, const Type* t, DependencyType dependency = RegularDependency, const TypeTuple* types = nullptr) + CheckCastPPNode(Node* ctrl, Node* n, const Type* t, const DependencyType& dependency = DependencyType::FloatingNarrowing, const TypeTuple* types = nullptr) : ConstraintCastNode(ctrl, n, t, dependency, types) { assert(ctrl != nullptr, "control must be set"); init_class_id(Class_CheckCastPP); diff --git a/src/hotspot/share/opto/cfgnode.cpp b/src/hotspot/share/opto/cfgnode.cpp index 0598f10b880..203aa69ce1b 100644 --- a/src/hotspot/share/opto/cfgnode.cpp +++ b/src/hotspot/share/opto/cfgnode.cpp @@ -2192,7 +2192,7 @@ Node *PhiNode::Ideal(PhaseGVN *phase, bool can_reshape) { if (phi_type->isa_ptr()) { const Type* uin_type = phase->type(uin); if (!phi_type->isa_oopptr() && !uin_type->isa_oopptr()) { - cast = new CastPPNode(r, uin, phi_type, ConstraintCastNode::StrongDependency, extra_types); + cast = new CastPPNode(r, uin, phi_type, ConstraintCastNode::DependencyType::NonFloatingNarrowing, extra_types); } else { // Use a CastPP for a cast to not null and a CheckCastPP for // a cast to a new klass (and both if both null-ness and @@ -2202,7 +2202,7 @@ Node *PhiNode::Ideal(PhaseGVN *phase, bool can_reshape) { // null, uin's type must be casted to not null if (phi_type->join(TypePtr::NOTNULL) == phi_type->remove_speculative() && uin_type->join(TypePtr::NOTNULL) != uin_type->remove_speculative()) { - cast = new CastPPNode(r, uin, TypePtr::NOTNULL, ConstraintCastNode::StrongDependency, extra_types); + cast = new CastPPNode(r, uin, TypePtr::NOTNULL, ConstraintCastNode::DependencyType::NonFloatingNarrowing, extra_types); } // If the type of phi and uin, both casted to not null, @@ -2214,14 +2214,14 @@ Node *PhiNode::Ideal(PhaseGVN *phase, bool can_reshape) { cast = phase->transform(cast); n = cast; } - cast = new CheckCastPPNode(r, n, phi_type, ConstraintCastNode::StrongDependency, extra_types); + cast = new CheckCastPPNode(r, n, phi_type, ConstraintCastNode::DependencyType::NonFloatingNarrowing, extra_types); } if (cast == nullptr) { - cast = new CastPPNode(r, uin, phi_type, ConstraintCastNode::StrongDependency, extra_types); + cast = new CastPPNode(r, uin, phi_type, ConstraintCastNode::DependencyType::NonFloatingNarrowing, extra_types); } } } else { - cast = ConstraintCastNode::make_cast_for_type(r, uin, phi_type, ConstraintCastNode::StrongDependency, extra_types); + cast = ConstraintCastNode::make_cast_for_type(r, uin, phi_type, ConstraintCastNode::DependencyType::NonFloatingNarrowing, extra_types); } assert(cast != nullptr, "cast should be set"); cast = phase->transform(cast); diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index bf7feeed0a2..621ba684da1 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -4582,7 +4582,7 @@ Node* Compile::constrained_convI2L(PhaseGVN* phase, Node* value, const TypeInt* // node from floating above the range check during loop optimizations. Otherwise, the // ConvI2L node may be eliminated independently of the range check, causing the data path // to become TOP while the control path is still there (although it's unreachable). - value = new CastIINode(ctrl, value, itype, carry_dependency ? ConstraintCastNode::StrongDependency : ConstraintCastNode::RegularDependency, true /* range check dependency */); + value = new CastIINode(ctrl, value, itype, carry_dependency ? ConstraintCastNode::DependencyType::NonFloatingNarrowing : ConstraintCastNode::DependencyType::FloatingNarrowing, true /* range check dependency */); value = phase->transform(value); } const TypeLong* ltype = TypeLong::make(itype->_lo, itype->_hi, itype->_widen); diff --git a/src/hotspot/share/opto/escape.cpp b/src/hotspot/share/opto/escape.cpp index fb3b5dba42c..b067d93176a 100644 --- a/src/hotspot/share/opto/escape.cpp +++ b/src/hotspot/share/opto/escape.cpp @@ -748,7 +748,7 @@ Node* ConnectionGraph::specialize_castpp(Node* castpp, Node* base, Node* current _igvn->_worklist.push(current_control); _igvn->_worklist.push(control_successor); - return _igvn->transform(ConstraintCastNode::make_cast_for_type(not_eq_control, base, _igvn->type(castpp), ConstraintCastNode::UnconditionalDependency, nullptr)); + return _igvn->transform(ConstraintCastNode::make_cast_for_type(not_eq_control, base, _igvn->type(castpp), ConstraintCastNode::DependencyType::NonFloatingNonNarrowing, nullptr)); } Node* ConnectionGraph::split_castpp_load_through_phi(Node* curr_addp, Node* curr_load, Node* region, GrowableArray* bases_for_loads, GrowableArray &alloc_worklist) { @@ -1235,7 +1235,7 @@ bool ConnectionGraph::reduce_phi_on_safepoints_helper(Node* ophi, Node* cast, No Node* nsr_merge_pointer = ophi; if (cast != nullptr) { const Type* new_t = merge_t->meet(TypePtr::NULL_PTR); - nsr_merge_pointer = _igvn->transform(ConstraintCastNode::make_cast_for_type(cast->in(0), cast->in(1), new_t, ConstraintCastNode::RegularDependency, nullptr)); + nsr_merge_pointer = _igvn->transform(ConstraintCastNode::make_cast_for_type(cast->in(0), cast->in(1), new_t, ConstraintCastNode::DependencyType::FloatingNarrowing, nullptr)); } for (uint spi = 0; spi < safepoints.size(); spi++) { @@ -1376,7 +1376,7 @@ void ConnectionGraph::reset_scalar_replaceable_entries(PhiNode* ophi) { } if (change) { - Node* new_cast = ConstraintCastNode::make_cast_for_type(out->in(0), out->in(1), out_new_t, ConstraintCastNode::StrongDependency, nullptr); + Node* new_cast = ConstraintCastNode::make_cast_for_type(out->in(0), out->in(1), out_new_t, ConstraintCastNode::DependencyType::NonFloatingNarrowing, nullptr); _igvn->replace_node(out, new_cast); _igvn->register_new_node_with_optimizer(new_cast); } diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index 113530c8835..2263fa720ce 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -1183,7 +1183,7 @@ bool LibraryCallKit::inline_preconditions_checkIndex(BasicType bt) { jlong upper_bound = _gvn.type(length)->is_integer(bt)->hi_as_long(); Node* casted_length = ConstraintCastNode::make_cast_for_basic_type( control(), length, TypeInteger::make(0, upper_bound, Type::WidenMax, bt), - ConstraintCastNode::RegularDependency, bt); + ConstraintCastNode::DependencyType::FloatingNarrowing, bt); casted_length = _gvn.transform(casted_length); replace_in_map(length, casted_length); length = casted_length; @@ -1213,7 +1213,7 @@ bool LibraryCallKit::inline_preconditions_checkIndex(BasicType bt) { // index is now known to be >= 0 and < length, cast it Node* result = ConstraintCastNode::make_cast_for_basic_type( control(), index, TypeInteger::make(0, upper_bound, Type::WidenMax, bt), - ConstraintCastNode::RegularDependency, bt); + ConstraintCastNode::DependencyType::FloatingNarrowing, bt); result = _gvn.transform(result); set_result(result); replace_in_map(index, result); diff --git a/src/hotspot/share/opto/loopTransform.cpp b/src/hotspot/share/opto/loopTransform.cpp index 5c65103677b..41bce0fe9b5 100644 --- a/src/hotspot/share/opto/loopTransform.cpp +++ b/src/hotspot/share/opto/loopTransform.cpp @@ -1366,7 +1366,7 @@ Node *PhaseIdealLoop::clone_up_backedge_goo(Node *back_ctrl, Node *preheader_ctr // the backedge of the main or post loop is removed, a Div node won't be able to float above the zero trip guard of the // loop and can't execute even if the loop is not reached. void PhaseIdealLoop::cast_incr_before_loop(Node* incr, Node* ctrl, CountedLoopNode* loop) { - Node* castii = new CastIINode(ctrl, incr, TypeInt::INT, ConstraintCastNode::UnconditionalDependency); + Node* castii = new CastIINode(ctrl, incr, TypeInt::INT, ConstraintCastNode::DependencyType::NonFloatingNonNarrowing); register_new_node(castii, ctrl); Node* phi = loop->phi(); assert(phi->in(LoopNode::EntryControl) == incr, "replacing wrong input?"); @@ -3262,7 +3262,7 @@ bool IdealLoopTree::do_remove_empty_loop(PhaseIdealLoop *phase) { Node* cast_ii = ConstraintCastNode::make_cast_for_basic_type( cl->in(LoopNode::EntryControl), exact_limit, phase->_igvn.type(exact_limit), - ConstraintCastNode::UnconditionalDependency, T_INT); + ConstraintCastNode::DependencyType::NonFloatingNonNarrowing, T_INT); phase->register_new_node(cast_ii, cl->in(LoopNode::EntryControl)); Node* final_iv = new SubINode(cast_ii, cl->stride()); diff --git a/src/hotspot/share/opto/loopnode.cpp b/src/hotspot/share/opto/loopnode.cpp index 03cc5cbcff6..42d3ee105f8 100644 --- a/src/hotspot/share/opto/loopnode.cpp +++ b/src/hotspot/share/opto/loopnode.cpp @@ -1001,7 +1001,7 @@ bool PhaseIdealLoop::create_loop_nest(IdealLoopTree* loop, Node_List &old_new) { // a negative stride). We add a CastII here to guarantee that, when the counted loop is created in a subsequent loop // opts pass, an accurate range of values for the limits is found. const TypeInt* inner_iters_actual_int_range = TypeInt::make(0, iters_limit, Type::WidenMin); - inner_iters_actual_int = new CastIINode(outer_head, inner_iters_actual_int, inner_iters_actual_int_range, ConstraintCastNode::UnconditionalDependency); + inner_iters_actual_int = new CastIINode(outer_head, inner_iters_actual_int, inner_iters_actual_int_range, ConstraintCastNode::DependencyType::NonFloatingNonNarrowing); _igvn.register_new_node_with_optimizer(inner_iters_actual_int); } else { inner_iters_actual_int = inner_iters_actual; @@ -1315,7 +1315,7 @@ bool PhaseIdealLoop::try_make_short_running_loop(IdealLoopTree* loop, jint strid register_new_node(bol, iff->in(0)); new_limit = ConstraintCastNode::make_cast_for_basic_type(new_predicate_proj, new_limit, TypeInteger::make(1, iters_limit_long, Type::WidenMin, bt), - ConstraintCastNode::UnconditionalDependency, bt); + ConstraintCastNode::DependencyType::NonFloatingNonNarrowing, bt); register_new_node(new_limit, new_predicate_proj); #ifndef PRODUCT @@ -1334,7 +1334,7 @@ bool PhaseIdealLoop::try_make_short_running_loop(IdealLoopTree* loop, jint strid const TypeLong* new_limit_t = new_limit->Value(&_igvn)->is_long(); new_limit = ConstraintCastNode::make_cast_for_basic_type(predicates.entry(), new_limit, TypeLong::make(0, new_limit_t->_hi, new_limit_t->_widen), - ConstraintCastNode::UnconditionalDependency, bt); + ConstraintCastNode::DependencyType::NonFloatingNonNarrowing, bt); register_new_node(new_limit, predicates.entry()); } else { assert(bt == T_INT && known_short_running_loop, "only CountedLoop statically known to be short running"); diff --git a/src/hotspot/share/opto/loopopts.cpp b/src/hotspot/share/opto/loopopts.cpp index ee3f138b8af..b1422d5db20 100644 --- a/src/hotspot/share/opto/loopopts.cpp +++ b/src/hotspot/share/opto/loopopts.cpp @@ -1174,7 +1174,7 @@ Node *PhaseIdealLoop::split_if_with_blocks_pre( Node *n ) { if ( nn ) return nn; } - if (n->is_ConstraintCast()) { + if (n->is_ConstraintCast() && n->as_ConstraintCast()->dependency().narrows_type()) { Node* dom_cast = n->as_ConstraintCast()->dominating_cast(&_igvn, this); // ConstraintCastNode::dominating_cast() uses node control input to determine domination. // Node control inputs don't necessarily agree with loop control info (due to @@ -1837,7 +1837,7 @@ void PhaseIdealLoop::try_sink_out_of_loop(Node* n) { if (in != nullptr && ctrl_is_member(n_loop, in)) { const Type* in_t = _igvn.type(in); cast = ConstraintCastNode::make_cast_for_type(x_ctrl, in, in_t, - ConstraintCastNode::UnconditionalDependency, nullptr); + ConstraintCastNode::DependencyType::NonFloatingNonNarrowing, nullptr); } if (cast != nullptr) { Node* prev = _igvn.hash_find_insert(cast); diff --git a/src/hotspot/share/opto/macroArrayCopy.cpp b/src/hotspot/share/opto/macroArrayCopy.cpp index 0ba8ed40c37..fb4a1842a36 100644 --- a/src/hotspot/share/opto/macroArrayCopy.cpp +++ b/src/hotspot/share/opto/macroArrayCopy.cpp @@ -233,7 +233,7 @@ void PhaseMacroExpand::generate_partial_inlining_block(Node** ctrl, MergeMemNode Node* inline_block = generate_guard(ctrl, bol_le, nullptr, PROB_FAIR); Node* stub_block = *ctrl; - Node* casted_length = new CastLLNode(inline_block, length, inline_range, ConstraintCastNode::RegularDependency); + Node* casted_length = new CastLLNode(inline_block, length, inline_range, ConstraintCastNode::DependencyType::FloatingNarrowing); transform_later(casted_length); Node* mask_gen = VectorMaskGenNode::make(casted_length, type); transform_later(mask_gen); diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestPushAddThruCast.java b/test/hotspot/jtreg/compiler/c2/irTests/TestPushAddThruCast.java index 7c5fa05f147..3aee78e9d6a 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/TestPushAddThruCast.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestPushAddThruCast.java @@ -44,13 +44,13 @@ public class TestPushAddThruCast { TestFramework.run(); } - final static int length = RANDOM.nextInt(Integer.MAX_VALUE); - final static long llength = RANDOM.nextInt(Integer.MAX_VALUE); + final static int length = RANDOM.nextInt(5, Integer.MAX_VALUE); + final static long llength = RANDOM.nextInt(2, Integer.MAX_VALUE); static int i; static long l; @Test - @IR(counts = { IRNode.CAST_II, "1" }) + @IR(counts = { IRNode.CAST_II, "2" }) public static int test1() { int j = Objects.checkIndex(i, length); int k = Objects.checkIndex(i + 1, length); @@ -67,7 +67,7 @@ public class TestPushAddThruCast { } @Test - @IR(counts = { IRNode.CAST_LL, "1" }) + @IR(counts = { IRNode.CAST_LL, "2" }) public static long test2() { long j = Objects.checkIndex(l, llength); long k = Objects.checkIndex(l + 1, llength); @@ -82,4 +82,25 @@ public class TestPushAddThruCast { throw new RuntimeException("incorrect result: " + res); } } + + // Test commoning of Casts after loop opts when they are at the same control + @Test + @IR(phase = CompilePhase.ITER_GVN1, counts = { IRNode.CAST_II, "4" }) + @IR(phase = CompilePhase.OPTIMIZE_FINISHED, counts = { IRNode.CAST_II, "2" }) + public static int test3() { + int j = Objects.checkIndex(i - 3, length); + j += Objects.checkIndex(i, length); + j += Objects.checkIndex(i - 2, length); + j += Objects.checkIndex(i - 1, length); + return j; + } + + @Run(test = "test3") + public static void test3_runner() { + i = RANDOM.nextInt(3, length - 1); + int res = test3(); + if (res != i * 4 - 6) { + throw new RuntimeException("incorrect result: " + res + " for i = " + i); + } + } } diff --git a/test/hotspot/jtreg/compiler/rangechecks/TestArrayAccessAboveRCAfterRCCastIIEliminated.java b/test/hotspot/jtreg/compiler/rangechecks/TestArrayAccessAboveRCAfterRCCastIIEliminated.java index 87e87842af3..b31c1425728 100644 --- a/test/hotspot/jtreg/compiler/rangechecks/TestArrayAccessAboveRCAfterRCCastIIEliminated.java +++ b/test/hotspot/jtreg/compiler/rangechecks/TestArrayAccessAboveRCAfterRCCastIIEliminated.java @@ -44,7 +44,6 @@ public class TestArrayAccessAboveRCAfterRCCastIIEliminated { private static volatile int volatileField; public static void main(String[] args) { - int[] array = new int[100]; for (int i = 0; i < 20_000; i++) { test1(9, 10, 1, true); test1(9, 10, 1, false); @@ -72,6 +71,13 @@ public class TestArrayAccessAboveRCAfterRCCastIIEliminated { test12(9, 10, 1, false); test13(9, 10, 1, true); test13(9, 10, 1, false); + test14(8, 0, 1, true); + test14(8, 0, 1, false); + inlined14(0, 0); + test15(8, 0, 1, true); + test15(8, 0, 1, false); + inlined15(0, 0); + } try { test1(-1, 10, 1, true); @@ -125,6 +131,14 @@ public class TestArrayAccessAboveRCAfterRCCastIIEliminated { test13(-1, 10, 1, true); } catch (ArrayIndexOutOfBoundsException arrayIndexOutOfBoundsException) { } + try { + test14(Integer.MAX_VALUE, 10, 1, true); + } catch (ArrayIndexOutOfBoundsException arrayIndexOutOfBoundsException) { + } + try { + test15(Integer.MAX_VALUE, 10, 1, true); + } catch (ArrayIndexOutOfBoundsException arrayIndexOutOfBoundsException) { + } } private static void test1(int i, int j, int flag, boolean flag2) { @@ -468,6 +482,72 @@ public class TestArrayAccessAboveRCAfterRCCastIIEliminated { } } + // Range check cast type widen after loop opts causes control dependency to be lost + private static void test14(int i, int j, int flag, boolean flag2) { + int l = 0; + for (; l < 10; l++); + j = inlined14(j, l); + int[] array = new int[10]; + notInlined(array); + if (flag == 0) { + } + if (flag2) { + float[] newArray = new float[10]; + newArray[i+j] = 42; // i+j in [0, 9] + float[] otherArray = new float[i+j]; // i+j in [0, max] + if (flag == 0) { + } + intField = array[otherArray.length]; + } else { + float[] newArray = new float[10]; + newArray[i+j] = 42; // i+j in [0, 9] + float[] otherArray = new float[i+j]; // i+j in [0, max] + if (flag == 0) { + } + intField = array[otherArray.length]; + } + } + + private static int inlined14(int j, int l) { + if (l == 10) { + j = 1; + } + return j; + } + + private static void test15(int i, int j, int flag, boolean flag2) { + i = Integer.max(i, Integer.MIN_VALUE + 1); + int l = 0; + for (; l < 10; l++); + j = inlined15(j, l); + int[] array = new int[10]; + notInlined(array); + if (flag == 0) { + } + if (flag2) { + float[] newArray = new float[10]; + newArray[i+j] = 42; // i+j in [0, 9] + float[] otherArray = new float[i+j]; // i+j in [0, max] + if (flag == 0) { + } + intField = array[otherArray.length]; + } else { + float[] newArray = new float[10]; + newArray[i+j] = 42; // i+j in [0, 9] + float[] otherArray = new float[i+j]; // i+j in [0, max] + if (flag == 0) { + } + intField = array[otherArray.length]; + } + } + + private static int inlined15(int j, int l) { + if (l == 10) { + j = Integer.max(j, Integer.MIN_VALUE + 10); + } + return j; + } + private static void notInlined(int[] array) { } From b60ac710bebf195972436da324983e61b51484ef Mon Sep 17 00:00:00 2001 From: Anton Seoane Ampudia Date: Wed, 10 Dec 2025 08:53:30 +0000 Subject: [PATCH 241/706] 8364490: Fatal error on large SpecTrapLimitExtraEntries value Reviewed-by: chagedorn, roland --- src/hotspot/share/runtime/globals.hpp | 1 + .../TestSpecTrapLimitExtraEntries.java | 40 +++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 test/hotspot/jtreg/compiler/arguments/TestSpecTrapLimitExtraEntries.java diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp index 68b5d8254fd..b3e9edc0a80 100644 --- a/src/hotspot/share/runtime/globals.hpp +++ b/src/hotspot/share/runtime/globals.hpp @@ -1369,6 +1369,7 @@ const int ObjectAlignmentInBytes = 8; \ product(int, SpecTrapLimitExtraEntries, 3, EXPERIMENTAL, \ "Extra method data trap entries for speculation") \ + range(0, 100) \ \ product(double, InlineFrequencyRatio, 0.25, DIAGNOSTIC, \ "Ratio of call site execution to caller method invocation") \ diff --git a/test/hotspot/jtreg/compiler/arguments/TestSpecTrapLimitExtraEntries.java b/test/hotspot/jtreg/compiler/arguments/TestSpecTrapLimitExtraEntries.java new file mode 100644 index 00000000000..83fd16ed0d9 --- /dev/null +++ b/test/hotspot/jtreg/compiler/arguments/TestSpecTrapLimitExtraEntries.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2025, 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 8364490 + * @summary "Hello world" sanity test for SpecTrapLimitExtraEntries + * + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:SpecTrapLimitExtraEntries=0 compiler.arguments.TestSpecTrapLimitExtraEntries + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:SpecTrapLimitExtraEntries=100 compiler.arguments.TestSpecTrapLimitExtraEntries + */ + +package compiler.arguments; + +public class TestSpecTrapLimitExtraEntries { + + public static void main(String[] args) { + System.out.println("Passed"); + } +} From 8eaeb6990b85ac8717f4fc4ce883f674017b91f3 Mon Sep 17 00:00:00 2001 From: David Briemann Date: Wed, 10 Dec 2025 10:21:42 +0000 Subject: [PATCH 242/706] 8372589: VM crashes on init when NonNMethodCodeHeapSize is set too small and UseTransparentHugePages is enabled Reviewed-by: mdoerr, chagedorn --- src/hotspot/share/code/codeCache.cpp | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/hotspot/share/code/codeCache.cpp b/src/hotspot/share/code/codeCache.cpp index beca3bcbcf5..95a2fb908de 100644 --- a/src/hotspot/share/code/codeCache.cpp +++ b/src/hotspot/share/code/codeCache.cpp @@ -227,11 +227,6 @@ void CodeCache::initialize_heaps() { if (!non_nmethod.set) { non_nmethod.size += compiler_buffer_size; - // Further down, just before FLAG_SET_ERGO(), all segment sizes are - // aligned down to the next lower multiple of min_size. For large page - // sizes, this may result in (non_nmethod.size == 0) which is not acceptable. - // Therefore, force non_nmethod.size to at least min_size. - non_nmethod.size = MAX2(non_nmethod.size, min_size); } if (!profiled.set && !non_profiled.set) { @@ -307,11 +302,10 @@ void CodeCache::initialize_heaps() { // Note: if large page support is enabled, min_size is at least the large // page size. This ensures that the code cache is covered by large pages. - non_profiled.size += non_nmethod.size & alignment_mask(min_size); - non_profiled.size += profiled.size & alignment_mask(min_size); - non_nmethod.size = align_down(non_nmethod.size, min_size); - profiled.size = align_down(profiled.size, min_size); - non_profiled.size = align_down(non_profiled.size, min_size); + non_nmethod.size = align_up(non_nmethod.size, min_size); + profiled.size = align_up(profiled.size, min_size); + non_profiled.size = align_up(non_profiled.size, min_size); + cache_size = non_nmethod.size + profiled.size + non_profiled.size; FLAG_SET_ERGO(NonNMethodCodeHeapSize, non_nmethod.size); FLAG_SET_ERGO(ProfiledCodeHeapSize, profiled.size); From b58e3b600bb14bf7133eda0c37a4be4c82919d79 Mon Sep 17 00:00:00 2001 From: Daniel Fuchs Date: Wed, 10 Dec 2025 12:08:53 +0000 Subject: [PATCH 243/706] 8373227: Test java/net/httpclient/http2/StreamFlowControlTest.java failed: should sleep time be raised? Reviewed-by: djelinski --- .../http2/StreamFlowControlTest.java | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/test/jdk/java/net/httpclient/http2/StreamFlowControlTest.java b/test/jdk/java/net/httpclient/http2/StreamFlowControlTest.java index 3e4ee4864f5..32f96c7ed4b 100644 --- a/test/jdk/java/net/httpclient/http2/StreamFlowControlTest.java +++ b/test/jdk/java/net/httpclient/http2/StreamFlowControlTest.java @@ -82,6 +82,9 @@ public class StreamFlowControlTest { String http2URI; String https2URI; final AtomicInteger reqid = new AtomicInteger(); + final static int WINDOW = + Integer.getInteger("jdk.httpclient.windowsize", 2 * 16 * 1024); + @DataProvider(name = "variants") @@ -147,7 +150,11 @@ public class StreamFlowControlTest { // the window is exceeded... long wait = uri.startsWith("https://") ? 800 : 500; try (InputStream is = response.body()) { - sleep(wait); + byte[] discard = new byte[WINDOW/4]; + for (int j=0; j<2; j++) { + sleep(wait); + if (is.read(discard) < 0) break; + } is.readAllBytes(); } // we could fail here if we haven't waited long enough @@ -205,7 +212,11 @@ public class StreamFlowControlTest { sent.join(); long wait = uri.startsWith("https://") ? 800 : 350; try (InputStream is = response.body()) { - sleep(wait); + byte[] discard = new byte[WINDOW/4]; + for (int j=0; j<2; j++) { + sleep(wait); + if (is.read(discard) < 0) break; + } is.readAllBytes(); } // we could fail here if we haven't waited long enough @@ -316,17 +327,16 @@ public class StreamFlowControlTest { bytes = "no request body!" .repeat(100).getBytes(StandardCharsets.UTF_8); } - int window = Integer.getInteger("jdk.httpclient.windowsize", 2 * 16 * 1024); final int maxChunkSize; if (t instanceof FCHttp2TestExchange fct) { - maxChunkSize = Math.min(window, fct.conn.getMaxFrameSize()); + maxChunkSize = Math.min(WINDOW, fct.conn.getMaxFrameSize()); } else { - maxChunkSize = Math.min(window, SettingsFrame.MAX_FRAME_SIZE); + maxChunkSize = Math.min(WINDOW, SettingsFrame.MAX_FRAME_SIZE); } byte[] resp = bytes.length <= maxChunkSize ? bytes : Arrays.copyOfRange(bytes, 0, maxChunkSize); - int max = (window / resp.length) + 2; + int max = (WINDOW / resp.length) + 2; // send in chunks t.sendResponseHeaders(200, 0); for (int i = 0; i <= max; i++) { From 655e9cda3f6b1fa3a6f0553e7745aa088dde53e8 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Wed, 10 Dec 2025 13:08:12 +0000 Subject: [PATCH 244/706] 8373335: Serial: Clean up SerialHeap members by access specifies Reviewed-by: jsikstro --- src/hotspot/share/gc/serial/serialHeap.cpp | 6 ++-- src/hotspot/share/gc/serial/serialHeap.hpp | 39 +++++++++++----------- 2 files changed, 23 insertions(+), 22 deletions(-) diff --git a/src/hotspot/share/gc/serial/serialHeap.cpp b/src/hotspot/share/gc/serial/serialHeap.cpp index 104924c1cad..08d730bf877 100644 --- a/src/hotspot/share/gc/serial/serialHeap.cpp +++ b/src/hotspot/share/gc/serial/serialHeap.cpp @@ -91,14 +91,16 @@ SerialHeap::SerialHeap() : CollectedHeap(), _young_gen(nullptr), _old_gen(nullptr), + _young_gen_saved_top(nullptr), + _old_gen_saved_top(nullptr), _rem_set(nullptr), _gc_policy_counters(new GCPolicyCounters("Copy:MSC", 2, 2)), _young_manager(nullptr), _old_manager(nullptr), - _is_heap_almost_full(false), _eden_pool(nullptr), _survivor_pool(nullptr), - _old_pool(nullptr) { + _old_pool(nullptr), + _is_heap_almost_full(false) { _young_manager = new GCMemoryManager("Copy"); _old_manager = new GCMemoryManager("MarkSweepCompact"); GCLocker::initialize(); diff --git a/src/hotspot/share/gc/serial/serialHeap.hpp b/src/hotspot/share/gc/serial/serialHeap.hpp index f5286179abf..36916c3f98e 100644 --- a/src/hotspot/share/gc/serial/serialHeap.hpp +++ b/src/hotspot/share/gc/serial/serialHeap.hpp @@ -76,6 +76,8 @@ class SerialHeap : public CollectedHeap { private: DefNewGeneration* _young_gen; TenuredGeneration* _old_gen; + + // Used during young-gc HeapWord* _young_gen_saved_top; HeapWord* _old_gen_saved_top; @@ -94,6 +96,10 @@ private: GCMemoryManager* _young_manager; GCMemoryManager* _old_manager; + MemoryPool* _eden_pool; + MemoryPool* _survivor_pool; + MemoryPool* _old_pool; + // Indicate whether heap is almost or approaching full. // Usually, there is some memory headroom for application/gc to run properly. // However, in extreme cases, e.g. young-gen is non-empty after a full gc, we @@ -113,6 +119,19 @@ private: static void verify_not_in_native_if_java_thread() NOT_DEBUG_RETURN; + // Try to allocate space by expanding the heap. + HeapWord* expand_heap_and_allocate(size_t size, bool is_tlab); + + HeapWord* mem_allocate_cas_noexpand(size_t size, bool is_tlab); + HeapWord* mem_allocate_work(size_t size, bool is_tlab); + + void initialize_serviceability() override; + + // Set the saved marks of generations, if that makes sense. + // In particular, if any generation might iterate over the oops + // in other generations, it should call this method. + void save_marks(); + public: // Returns JNI_OK on success jint initialize() override; @@ -211,26 +230,6 @@ public: // generations in a fully generational heap. CardTableRS* rem_set() { return _rem_set; } - public: - // Set the saved marks of generations, if that makes sense. - // In particular, if any generation might iterate over the oops - // in other generations, it should call this method. - void save_marks(); - -private: - // Try to allocate space by expanding the heap. - HeapWord* expand_heap_and_allocate(size_t size, bool is_tlab); - - HeapWord* mem_allocate_cas_noexpand(size_t size, bool is_tlab); - HeapWord* mem_allocate_work(size_t size, bool is_tlab); - - MemoryPool* _eden_pool; - MemoryPool* _survivor_pool; - MemoryPool* _old_pool; - - void initialize_serviceability() override; - -public: static SerialHeap* heap(); SerialHeap(); From 54430a87226096725b13f05326d08629420657ca Mon Sep 17 00:00:00 2001 From: Daniel Fuchs Date: Wed, 10 Dec 2025 15:14:46 +0000 Subject: [PATCH 245/706] 8373362: Http3TestServer should not log an exception stack trace when it is stopping normally Reviewed-by: jpai, djelinski --- .../test/lib/http3/Http3ServerExchange.java | 5 +++++ .../test/lib/http3/Http3TestServer.java | 19 ++++++++++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http3/Http3ServerExchange.java b/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http3/Http3ServerExchange.java index 9a39ba4358d..c127abf3c0f 100644 --- a/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http3/Http3ServerExchange.java +++ b/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http3/Http3ServerExchange.java @@ -108,6 +108,11 @@ public final class Http3ServerExchange implements Http2TestExchange { rspheadersBuilder = new HttpHeadersBuilder(); } + Http3ServerConnection http3Connection() { + return serverConn; + } + + String connectionTag() { return serverConn.quicConnection().logTag(); } diff --git a/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http3/Http3TestServer.java b/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http3/Http3TestServer.java index ff76c67ed7e..6e81813cac3 100644 --- a/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http3/Http3TestServer.java +++ b/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http3/Http3TestServer.java @@ -55,6 +55,7 @@ import jdk.internal.net.http.http3.ConnectionSettings; import jdk.internal.net.http.http3.Http3Error; import jdk.internal.net.http.http3.frames.SettingsFrame; import jdk.internal.net.quic.QuicTLSContext; +import jdk.internal.net.quic.QuicTransportErrors; import jdk.internal.net.quic.QuicVersion; import static java.nio.charset.StandardCharsets.US_ASCII; @@ -261,7 +262,23 @@ public class Http3TestServer implements QuicServer.ConnectionAcceptor, AutoClose handler.handle(exchange); } catch (Throwable failure) { System.err.println("Failed to handle exchange: " + failure); - failure.printStackTrace(); + boolean noError = false; + if (exchange instanceof Http3ServerExchange http3ServerExchange) { + var quicConnection = http3ServerExchange.http3Connection().quicConnection(); + var cause = quicConnection.terminationCause(); + if (cause != null) { + var code = cause.getCloseCode(); + noError = cause.isAppLayer() + ? Http3Error.isNoError(code) + : code == QuicTransportErrors.NO_ERROR.code(); + } + } + // don't print the full stack trace if the connection + // is terminated with no error, in order to avoid + // cluttering the log. + if (!noError) { + failure.printStackTrace(); + } final var ioException = (failure instanceof IOException) ? (IOException) failure : new IOException(failure); From 11aa6e10c017a7257c60eb7395d728d32b2006d4 Mon Sep 17 00:00:00 2001 From: Fairoz Matte Date: Wed, 10 Dec 2025 18:15:32 +0000 Subject: [PATCH 246/706] 8373270: GCC 14.2.0 reports warning: '%s' directive output may be truncated Reviewed-by: kbarrett, dholmes, alanb --- .../unix/native/libjli/java_md_common.c | 25 +------------------ 1 file changed, 1 insertion(+), 24 deletions(-) diff --git a/src/java.base/unix/native/libjli/java_md_common.c b/src/java.base/unix/native/libjli/java_md_common.c index f67a50304d0..45509c7d25d 100644 --- a/src/java.base/unix/native/libjli/java_md_common.c +++ b/src/java.base/unix/native/libjli/java_md_common.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, 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 @@ -259,29 +259,6 @@ JLI_ReportExceptionDescription(JNIEnv * env) { (*env)->ExceptionDescribe(env); } -/* - * Since using the file system as a registry is a bit risky, perform - * additional sanity checks on the identified directory to validate - * it as a valid JDK. - * - * Return 0 if the tests fail; otherwise return non-zero (true). - * - * Note that checking for anything more than the existence of an - * executable object at bin/java relative to the path being checked - * will break the regression tests. - */ -static int -CheckSanity(char *path, char *dir) -{ - char buffer[PATH_MAX]; - - if (JLI_StrLen(path) + JLI_StrLen(dir) + 11 > PATH_MAX) - return (0); /* Silently reject "impossibly" long paths */ - - JLI_Snprintf(buffer, sizeof(buffer), "%s/%s/bin/java", path, dir); - return ((access(buffer, X_OK) == 0) ? 1 : 0); -} - /* * "Borrowed" from Solaris 10 where the unsetenv() function is being added * to libc thanks to SUSv3 (Standard Unix Specification, version 3). As From 413f852bdb4767b2a1c29431144616668888138d Mon Sep 17 00:00:00 2001 From: Mat Carter Date: Wed, 10 Dec 2025 18:49:30 +0000 Subject: [PATCH 247/706] 8369736: Add management interface for AOT cache creation Reviewed-by: mr, iklam, kevinw --- src/hotspot/share/cds/aotMetaspace.cpp | 1 + src/hotspot/share/include/jvm.h | 3 + src/hotspot/share/prims/jvm.cpp | 13 ++ .../classes/sun/management/VMManagement.java | 5 +- .../sun/management/VMManagementImpl.java | 5 +- .../native/libmanagement/VMManagementImpl.c | 7 ++ .../internal/HotSpotAOTCacheImpl.java | 55 ++++++++ .../internal/PlatformMBeanProviderImpl.java | 38 +++++- .../jdk/management/HotSpotAOTCacheMXBean.java | 93 ++++++++++++++ .../aotCache/HotSpotAOTCacheMXBeanTest.java | 118 ++++++++++++++++++ 10 files changed, 335 insertions(+), 3 deletions(-) create mode 100644 src/jdk.management/share/classes/com/sun/management/internal/HotSpotAOTCacheImpl.java create mode 100644 src/jdk.management/share/classes/jdk/management/HotSpotAOTCacheMXBean.java create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/aotCache/HotSpotAOTCacheMXBeanTest.java diff --git a/src/hotspot/share/cds/aotMetaspace.cpp b/src/hotspot/share/cds/aotMetaspace.cpp index f56050d4d31..3c87e3ef797 100644 --- a/src/hotspot/share/cds/aotMetaspace.cpp +++ b/src/hotspot/share/cds/aotMetaspace.cpp @@ -96,6 +96,7 @@ #include "runtime/vmOperations.hpp" #include "runtime/vmThread.hpp" #include "sanitizers/leak.hpp" +#include "services/management.hpp" #include "utilities/align.hpp" #include "utilities/bitMap.inline.hpp" #include "utilities/defaultStream.hpp" diff --git a/src/hotspot/share/include/jvm.h b/src/hotspot/share/include/jvm.h index dccdcacef71..7236679d8f3 100644 --- a/src/hotspot/share/include/jvm.h +++ b/src/hotspot/share/include/jvm.h @@ -87,6 +87,9 @@ JVM_InternString(JNIEnv *env, jstring str); /* * java.lang.System */ +JNIEXPORT jboolean JNICALL +JVM_AOTEndRecording(JNIEnv *env); + JNIEXPORT jlong JNICALL JVM_CurrentTimeMillis(JNIEnv *env, jclass ignored); diff --git a/src/hotspot/share/prims/jvm.cpp b/src/hotspot/share/prims/jvm.cpp index 16d9efde410..48d89235c98 100644 --- a/src/hotspot/share/prims/jvm.cpp +++ b/src/hotspot/share/prims/jvm.cpp @@ -229,6 +229,19 @@ extern void trace_class_resolution(Klass* to_class) { // java.lang.System ////////////////////////////////////////////////////////////////////// +JVM_ENTRY(jboolean, JVM_AOTEndRecording(JNIEnv *env)) +#if INCLUDE_CDS + if (CDSConfig::is_dumping_preimage_static_archive()) { + if (!AOTMetaspace::preimage_static_archive_dumped()) { + AOTMetaspace::dump_static_archive(THREAD); + return JNI_TRUE; + } + } + return JNI_FALSE; +#else + return JNI_FALSE; +#endif // INCLUDE_CDS +JVM_END JVM_LEAF(jlong, JVM_CurrentTimeMillis(JNIEnv *env, jclass ignored)) return os::javaTimeMillis(); diff --git a/src/java.management/share/classes/sun/management/VMManagement.java b/src/java.management/share/classes/sun/management/VMManagement.java index 3e227225ccd..29391cf53ba 100644 --- a/src/java.management/share/classes/sun/management/VMManagement.java +++ b/src/java.management/share/classes/sun/management/VMManagement.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, 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,6 +48,9 @@ public interface VMManagement { public boolean isGcNotificationSupported(); public boolean isRemoteDiagnosticCommandsSupported(); + // AOT Subsystem + public boolean endAOTRecording(); + // Class Loading Subsystem public long getTotalClassCount(); public int getLoadedClassCount(); diff --git a/src/java.management/share/classes/sun/management/VMManagementImpl.java b/src/java.management/share/classes/sun/management/VMManagementImpl.java index b8c7a2921d4..0fd0d8ad562 100644 --- a/src/java.management/share/classes/sun/management/VMManagementImpl.java +++ b/src/java.management/share/classes/sun/management/VMManagementImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, 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 @@ -117,6 +117,9 @@ class VMManagementImpl implements VMManagement { public native boolean isThreadCpuTimeEnabled(); public native boolean isThreadAllocatedMemoryEnabled(); + // AOT Subsystem + public native boolean endAOTRecording(); + // Class Loading Subsystem public int getLoadedClassCount() { long count = getTotalClassCount() - getUnloadedClassCount(); diff --git a/src/java.management/share/native/libmanagement/VMManagementImpl.c b/src/java.management/share/native/libmanagement/VMManagementImpl.c index d5141c71ee7..e6570d06bdd 100644 --- a/src/java.management/share/native/libmanagement/VMManagementImpl.c +++ b/src/java.management/share/native/libmanagement/VMManagementImpl.c @@ -101,6 +101,13 @@ Java_sun_management_VMManagementImpl_getVmArguments0 return JVM_GetVmArguments(env); } +JNIEXPORT jboolean JNICALL +Java_sun_management_VMManagementImpl_endAOTRecording + (JNIEnv *env, jobject dummy) +{ + return JVM_AOTEndRecording(env); +} + JNIEXPORT jlong JNICALL Java_sun_management_VMManagementImpl_getTotalClassCount (JNIEnv *env, jobject dummy) diff --git a/src/jdk.management/share/classes/com/sun/management/internal/HotSpotAOTCacheImpl.java b/src/jdk.management/share/classes/com/sun/management/internal/HotSpotAOTCacheImpl.java new file mode 100644 index 00000000000..4bb556455ea --- /dev/null +++ b/src/jdk.management/share/classes/com/sun/management/internal/HotSpotAOTCacheImpl.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2025, Microsoft, Inc. 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 com.sun.management.internal; + +import javax.management.ObjectName; +import jdk.management.HotSpotAOTCacheMXBean; +import sun.management.Util; +import sun.management.VMManagement; + +/** + * Implementation class for the AOT Cache subsystem. + * + * ManagementFactory.getRuntimeMXBean() returns an instance + * of this class. + */ +public class HotSpotAOTCacheImpl implements HotSpotAOTCacheMXBean { + + private final VMManagement jvm; + /** + * Constructor of HotSpotAOTCacheImpl class. + */ + HotSpotAOTCacheImpl(VMManagement vm) { + this.jvm = vm; + } + + public boolean endRecording() { + return jvm.endAOTRecording(); + } + + public ObjectName getObjectName() { + return Util.newObjectName("jdk.management:type=HotSpotAOTCache"); + } +} \ No newline at end of file diff --git a/src/jdk.management/share/classes/com/sun/management/internal/PlatformMBeanProviderImpl.java b/src/jdk.management/share/classes/com/sun/management/internal/PlatformMBeanProviderImpl.java index 3a64fe6b858..b000516e626 100644 --- a/src/jdk.management/share/classes/com/sun/management/internal/PlatformMBeanProviderImpl.java +++ b/src/jdk.management/share/classes/com/sun/management/internal/PlatformMBeanProviderImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, 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,6 +39,7 @@ import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; import javax.management.DynamicMBean; +import jdk.management.HotSpotAOTCacheMXBean; import jdk.management.VirtualThreadSchedulerMXBean; import sun.management.ManagementFactoryHelper; import sun.management.spi.PlatformMBeanProvider; @@ -159,6 +160,41 @@ public final class PlatformMBeanProviderImpl extends PlatformMBeanProvider { } }); + /** + * HotSpotAOTCacheMXBean. + */ + initMBeanList.add(new PlatformComponent() { + private final Set> mbeanInterfaces = + Set.of(HotSpotAOTCacheMXBean.class); + private final Set mbeanInterfaceNames = + Set.of(HotSpotAOTCacheMXBean.class.getName()); + private HotSpotAOTCacheMXBean impl; + + @Override + public Set> mbeanInterfaces() { + return mbeanInterfaces; + } + + @Override + public Set mbeanInterfaceNames() { + return mbeanInterfaceNames; + } + + @Override + public String getObjectNamePattern() { + return "jdk.management:type=HotSpotAOTCache"; + } + + @Override + public Map nameToMBeanMap() { + HotSpotAOTCacheMXBean impl = this.impl; + if (impl == null) { + this.impl = impl = new HotSpotAOTCacheImpl(ManagementFactoryHelper.getVMManagement()); + } + return Map.of("jdk.management:type=HotSpotAOTCache", impl); + } + }); + /** * VirtualThreadSchedulerMXBean. */ diff --git a/src/jdk.management/share/classes/jdk/management/HotSpotAOTCacheMXBean.java b/src/jdk.management/share/classes/jdk/management/HotSpotAOTCacheMXBean.java new file mode 100644 index 00000000000..2dc02f2bd73 --- /dev/null +++ b/src/jdk.management/share/classes/jdk/management/HotSpotAOTCacheMXBean.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2025, Microsoft, Inc. 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.management; + +import java.lang.management.ManagementFactory; +import java.lang.management.PlatformManagedObject; +import javax.management.MBeanServer; +import javax.management.ObjectName; + +/** + * Management interface for the JDK's Ahead of Time (AOT) Cache. + * + *

      The management interface is registered with the platform {@link MBeanServer + * MBeanServer}. The {@link ObjectName ObjectName} that uniquely identifies the management + * interface within the {@code MBeanServer} is {@code jdk.management:type=HotSpotAOTCache}. + * + *

      Direct access to the MXBean interface can be obtained with + * {@link ManagementFactory#getPlatformMXBean(Class)}. + * + * @since 26 + */ +public interface HotSpotAOTCacheMXBean extends PlatformManagedObject { + /** + * If an AOT recording is in progress, ends the recording. This method returns + * after the AOT artifacts have been completely written. + * + *

      The JVM will start recording AOT artifacts upon start-up if appropriate JVM options are + * given in the command-line. The recording will stop when the JVM exits, or when + * the {@code endRecording} method is called. Examples: + * + *

      ${@code java -XX:AOTCacheOutput=app.aot ....} + * + *

      + * The JVM records optimization information for the current application in the AOT cache file + * {@code app.aot}. In a future run of the application, the option {@code -XX:AOTCache=app.aot} will + * cause the JVM to use the cache to improve the application's startup and warmup performance. + *
      + * + *

      ${@code java -XX:AOTMode=record -XX:AOTConfiguration=app.aotconfig ....} + * + *

      + * The JVM records optimization information for the current application in the AOT configuration + * file {@code app.aotconfig}. Subsequently, an AOT cache file can be created with the command: + * + *

      ${@code java -XX:AOTMode=create -XX:AOTConfiguration=app.aotconfig -XX:AOTCache=app.aot ...} + *

      + * + *

      For more information about creating and using the AOT artifacts, and detailed + * specification of the corresponding JVM command-line options, please refer + * to JEP 483 and JEP 514. + * + *

      Currently there are no APIs to start an AOT recording. AOT recordings must be + * started using JVM command-line options such as {@code -XX:AOTCacheOutput}. + * There are also no APIs to query whether an AOT recording is in progress, or what AOT + * artifacts are being recorded. + * + *

      This method enables an application to end its own AOT recording + * programatically, but that is not necessarily the best approach. Doing so + * requires changing the application’s code, which might not be + * feasible. Even when it is feasible, injecting training-specific logic + * into the application reduces the similarity between training runs and + * production runs, potentially making the AOT cache less effective. It may + * be better to arrange for an external agent to end the training run, + * thereby creating an AOT cache without interfering with the application’s + * code. + * + * @return {@code true} if a recording was in progress and has been ended + * successfully; {@code false} otherwise. + */ + public boolean endRecording(); +} \ No newline at end of file diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/HotSpotAOTCacheMXBeanTest.java b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/HotSpotAOTCacheMXBeanTest.java new file mode 100644 index 00000000000..fba3589f5ce --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/HotSpotAOTCacheMXBeanTest.java @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2025, Microsoft, Inc. 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 Sanity test for HotSpotAOTCache MXBean + * @requires vm.cds.write.archived.java.heap + * @library /test/jdk/lib/testlibrary /test/lib + * @build HotSpotAOTCacheMXBeanTest + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar app.jar HotSpotAOTCacheMXBeanApp + * @run driver HotSpotAOTCacheMXBeanTest + */ + +import java.io.IOException; +import java.lang.management.ManagementFactory; +import javax.management.MBeanServer; +import jdk.management.HotSpotAOTCacheMXBean; +import jdk.test.lib.cds.CDSAppTester; +import jdk.test.lib.helpers.ClassFileInstaller; +import jdk.test.lib.process.OutputAnalyzer; + +public class HotSpotAOTCacheMXBeanTest { + static final String appJar = ClassFileInstaller.getJarPath("app.jar"); + static final String mainClass = "HotSpotAOTCacheMXBeanApp"; + public static void main(String[] args) throws Exception { + Tester tester = new Tester(); + tester.runAOTWorkflow(); + } + + static class Tester extends CDSAppTester { + public Tester() { + super(mainClass); + } + + @Override + public String classpath(RunMode runMode) { + return appJar; + } + + @Override + public String[] vmArgs(RunMode runMode) { + return new String[] { + "-Xlog:cds+class=trace", + "--add-modules=jdk.management" + }; + } + + @Override + public String[] appCommandLine(RunMode runMode) { + return new String[] { + mainClass, runMode.name() + }; + } + + @Override + public void checkExecution(OutputAnalyzer out, RunMode runMode) { + var name = runMode.name(); + if (runMode.isApplicationExecuted()) { + if(runMode == RunMode.TRAINING) { + out.shouldContain("Hello Leyden " + name); + out.shouldContain("Successfully stopped recording"); + } else if (runMode == RunMode.ASSEMBLY) { + out.shouldNotContain("Hello Leyden "); + } else if (runMode == RunMode.PRODUCTION) { + out.shouldContain("Hello Leyden " + name); + out.shouldContain("Failed to stop recording"); + } + out.shouldNotContain("HotSpotAOTCacheMXBean is not available"); + out.shouldNotContain("IOException occurred!"); + } + } + } +} + +class HotSpotAOTCacheMXBeanApp { + public static void main(String[] args) { + System.out.println("Hello Leyden " + args[0]); + try { + MBeanServer server = ManagementFactory.getPlatformMBeanServer(); + HotSpotAOTCacheMXBean aotBean = ManagementFactory.newPlatformMXBeanProxy(server, + "jdk.management:type=HotSpotAOTCache", + HotSpotAOTCacheMXBean.class); + if (aotBean == null) { + System.out.println("HotSpotAOTCacheMXBean is not available"); + return; + } + if (aotBean.endRecording()) { + System.out.println("Successfully stopped recording"); + } else { + System.out.println("Failed to stop recording"); + } + } catch (IOException e) { + System.out.println("IOException occurred!"); + } + } +} \ No newline at end of file From 52aa7fe1c970709fe387b70a5020ea0e77c4047f Mon Sep 17 00:00:00 2001 From: Phil Race Date: Wed, 10 Dec 2025 21:40:18 +0000 Subject: [PATCH 248/706] 8334549: [Sound] Test timed out: javax/sound/sampled/Clip/OpenNonIntegralNumberOfSampleframes.java Reviewed-by: aivanov, kizune --- .../sound/sampled/Clip/OpenNonIntegralNumberOfSampleframes.java | 1 + 1 file changed, 1 insertion(+) diff --git a/test/jdk/javax/sound/sampled/Clip/OpenNonIntegralNumberOfSampleframes.java b/test/jdk/javax/sound/sampled/Clip/OpenNonIntegralNumberOfSampleframes.java index b3198b8ab77..30f38f55acb 100644 --- a/test/jdk/javax/sound/sampled/Clip/OpenNonIntegralNumberOfSampleframes.java +++ b/test/jdk/javax/sound/sampled/Clip/OpenNonIntegralNumberOfSampleframes.java @@ -32,6 +32,7 @@ import javax.sound.sampled.LineUnavailableException; /** * @test + * @key sound * @bug 8167435 */ public final class OpenNonIntegralNumberOfSampleframes { From 74dca863c2e61c13884c3454b8da7be125235970 Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Wed, 10 Dec 2025 22:46:35 +0000 Subject: [PATCH 249/706] 8371718: (sc) Channels.new{Input,Output}Stream can allocate unbounded memory for a socket channel Reviewed-by: alanb --- .../sun/nio/ch/ChannelInputStream.java | 3 +- .../sun/nio/ch/ChannelOutputStream.java | 11 +++- .../classes/sun/nio/ch/NioSocketImpl.java | 12 ++-- .../classes/sun/nio/ch/SocketChannelImpl.java | 3 +- .../share/classes/sun/nio/ch/Streams.java | 6 +- .../Channels/SocketChannelStreams.java | 64 ++++++++++++++++++- 6 files changed, 83 insertions(+), 16 deletions(-) diff --git a/src/java.base/share/classes/sun/nio/ch/ChannelInputStream.java b/src/java.base/share/classes/sun/nio/ch/ChannelInputStream.java index 14b2058d28d..09f6d7b1d75 100644 --- a/src/java.base/share/classes/sun/nio/ch/ChannelInputStream.java +++ b/src/java.base/share/classes/sun/nio/ch/ChannelInputStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, 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 @@ -109,6 +109,7 @@ class ChannelInputStream extends InputStream { if (len == 0) return 0; + len = Math.min(len, Streams.MAX_BUFFER_SIZE); ByteBuffer bb = ((this.bs == bs) ? this.bb : ByteBuffer.wrap(bs)); diff --git a/src/java.base/share/classes/sun/nio/ch/ChannelOutputStream.java b/src/java.base/share/classes/sun/nio/ch/ChannelOutputStream.java index dff8af9ebaf..b7207c9fd4b 100644 --- a/src/java.base/share/classes/sun/nio/ch/ChannelOutputStream.java +++ b/src/java.base/share/classes/sun/nio/ch/ChannelOutputStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, 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,10 +64,15 @@ class ChannelOutputStream extends OutputStream { * If the channel is selectable then it must be configured blocking. */ private void writeFully(ByteBuffer bb) throws IOException { - while (bb.remaining() > 0) { + int pos = bb.position(); + int rem = bb.limit() - pos; + while (rem > 0) { + bb.limit(pos + Math.min(Streams.MAX_BUFFER_SIZE, rem)); int n = ch.write(bb); if (n <= 0) - throw new RuntimeException("no bytes written"); + throw new IOException("Write failed"); + pos += n; + rem -= n; } } diff --git a/src/java.base/share/classes/sun/nio/ch/NioSocketImpl.java b/src/java.base/share/classes/sun/nio/ch/NioSocketImpl.java index 57935ff5b00..01f894be227 100644 --- a/src/java.base/share/classes/sun/nio/ch/NioSocketImpl.java +++ b/src/java.base/share/classes/sun/nio/ch/NioSocketImpl.java @@ -78,10 +78,6 @@ import static jdk.internal.util.Exceptions.formatMsg; public final class NioSocketImpl extends SocketImpl implements PlatformSocketImpl { private static final NativeDispatcher nd = new SocketDispatcher(); - // The maximum number of bytes to read/write per syscall to avoid needing - // a huge buffer from the temporary buffer cache - private static final int MAX_BUFFER_SIZE = 128 * 1024; - // true if this is a SocketImpl for a ServerSocket private final boolean server; @@ -355,8 +351,8 @@ public final class NioSocketImpl extends SocketImpl implements PlatformSocketImp // emulate legacy behavior to return -1, even if socket is closed if (readEOF) return -1; - // read up to MAX_BUFFER_SIZE bytes - int size = Math.min(len, MAX_BUFFER_SIZE); + // read up to Streams.MAX_BUFFER_SIZE bytes + int size = Math.min(len, Streams.MAX_BUFFER_SIZE); int n = implRead(b, off, size, remainingNanos); if (n == -1) readEOF = true; @@ -453,8 +449,8 @@ public final class NioSocketImpl extends SocketImpl implements PlatformSocketImp int pos = off; int end = off + len; while (pos < end) { - // write up to MAX_BUFFER_SIZE bytes - int size = Math.min((end - pos), MAX_BUFFER_SIZE); + // write up to Streams.MAX_BUFFER_SIZE bytes + int size = Math.min((end - pos), Streams.MAX_BUFFER_SIZE); int n = implWrite(b, pos, size); pos += n; } diff --git a/src/java.base/share/classes/sun/nio/ch/SocketChannelImpl.java b/src/java.base/share/classes/sun/nio/ch/SocketChannelImpl.java index 6f3e8b443dc..868ed3b64bc 100644 --- a/src/java.base/share/classes/sun/nio/ch/SocketChannelImpl.java +++ b/src/java.base/share/classes/sun/nio/ch/SocketChannelImpl.java @@ -1373,6 +1373,7 @@ class SocketChannelImpl // nothing to do return 0; } + len = Math.min(len, Streams.MAX_BUFFER_SIZE); readLock.lock(); try { @@ -1469,7 +1470,7 @@ class SocketChannelImpl beginWrite(true); configureSocketNonBlockingIfVirtualThread(); while (pos < end && isOpen()) { - int size = end - pos; + int size = Math.min(end - pos, Streams.MAX_BUFFER_SIZE); int n = tryWrite(b, pos, size); while (IOStatus.okayToRetry(n) && isOpen()) { park(Net.POLLOUT); diff --git a/src/java.base/share/classes/sun/nio/ch/Streams.java b/src/java.base/share/classes/sun/nio/ch/Streams.java index 4326c9e2e0b..847fa8333e8 100644 --- a/src/java.base/share/classes/sun/nio/ch/Streams.java +++ b/src/java.base/share/classes/sun/nio/ch/Streams.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, 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,6 +33,10 @@ import java.nio.channels.WritableByteChannel; * Factory methods for input/output streams based on channels. */ public class Streams { + // The maximum number of bytes to read/write per syscall to avoid needing + // a huge buffer from the temporary buffer cache + static final int MAX_BUFFER_SIZE = 128 * 1024; + private Streams() { } /** diff --git a/test/jdk/java/nio/channels/Channels/SocketChannelStreams.java b/test/jdk/java/nio/channels/Channels/SocketChannelStreams.java index 72c07392d7c..519de1e725f 100644 --- a/test/jdk/java/nio/channels/Channels/SocketChannelStreams.java +++ b/test/jdk/java/nio/channels/Channels/SocketChannelStreams.java @@ -22,10 +22,10 @@ */ /* @test - * @bug 8279339 - * @run testng SocketChannelStreams + * @bug 8279339 8371718 * @summary Exercise InputStream/OutputStream returned by Channels.newXXXStream * when channel is a SocketChannel + * @run testng SocketChannelStreams */ import java.io.Closeable; @@ -35,6 +35,8 @@ import java.io.OutputStream; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.Socket; +import java.nio.ByteBuffer; +import java.nio.channels.ByteChannel; import java.nio.channels.Channels; import java.nio.channels.IllegalBlockingModeException; import java.nio.channels.ServerSocketChannel; @@ -51,6 +53,9 @@ import static org.testng.Assert.*; @Test public class SocketChannelStreams { + // Maximum size of internal temporary buffer + private static final int MAX_BUFFER_SIZE = 128*1024; + private ScheduledExecutorService executor; @BeforeClass() @@ -379,6 +384,25 @@ public class SocketChannelStreams { }); } + /** + * Test that internal buffers have at most MAX_BUFFER_SIZE bytes remaining. + */ + public void testReadLimit() throws IOException { + InputStream in = Channels.newInputStream(new TestChannel()); + byte[] b = new byte[3*MAX_BUFFER_SIZE]; + int n = in.read(b, 0, b.length); + assertEquals(n, MAX_BUFFER_SIZE); + } + + /** + * Test that internal buffers have at most MAX_BUFFER_SIZE bytes remaining. + */ + public void testWriteLimit() throws IOException { + OutputStream out = Channels.newOutputStream(new TestChannel()); + byte[] b = new byte[3*MAX_BUFFER_SIZE]; + out.write(b, 0, b.length); + } + // -- test infrastructure -- private interface ThrowingTask { @@ -477,4 +501,40 @@ public class SocketChannelStreams { private Future schedule(Runnable task, long delay) { return executor.schedule(task, delay, TimeUnit.MILLISECONDS); } + + /** + * ByteChannel that throws if more than 128k bytes remain + * in the buffer supplied for reading or writing. + */ + private static class TestChannel implements ByteChannel { + @Override + public int read(ByteBuffer bb) throws IOException { + int rem = bb.remaining(); + if (rem > MAX_BUFFER_SIZE) { + throw new IOException("too big"); + } + bb.position(bb.limit()); + return rem; + } + + @Override + public int write(ByteBuffer bb) throws IOException { + int rem = bb.remaining(); + if (rem > MAX_BUFFER_SIZE) { + throw new IOException("too big"); + } + bb.position(bb.limit()); + return rem; + } + + @Override + public boolean isOpen() { + return true; + } + + @Override + public void close() { + throw new UnsupportedOperationException(); + } + } } From 920a99faeb6e0aee445df39cf8ddd43df18345d6 Mon Sep 17 00:00:00 2001 From: Kevin Walls Date: Thu, 11 Dec 2025 07:44:10 +0000 Subject: [PATCH 250/706] 8370731: Tests in vmTestbase/nsk/monitoring/GarbageCollectorMXBean/CollectionCounters/ failed: OutOfMemoryError Reviewed-by: sspitsyn --- .../CollectionCounters001.java | 53 +++++++++---------- .../TestDescription.java | 5 +- .../TestDescription.java | 5 +- .../TestDescription.java | 5 +- .../TestDescription.java | 5 +- 5 files changed, 38 insertions(+), 35 deletions(-) diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/GarbageCollectorMXBean/CollectionCounters/CollectionCounters001/CollectionCounters001.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/GarbageCollectorMXBean/CollectionCounters/CollectionCounters001/CollectionCounters001.java index f256a5649e5..aac6ab88246 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/GarbageCollectorMXBean/CollectionCounters/CollectionCounters001/CollectionCounters001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/GarbageCollectorMXBean/CollectionCounters/CollectionCounters001/CollectionCounters001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2025, 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,9 +29,10 @@ * @summary converted from VM Testbase nsk/monitoring/GarbageCollectorMXBean/CollectionCounters/CollectionCounters001. * VM Testbase keywords: [monitoring] * + * @requires vm.opt.DisableExplicitGC != "true" * @library /vmTestbase * /test/lib - * @run main/othervm + * @run main/othervm -XX:-UseGCOverheadLimit * nsk.monitoring.GarbageCollectorMXBean.CollectionCounters.CollectionCounters001.CollectionCounters001 * -testMode=directly */ @@ -60,6 +61,7 @@ import nsk.share.runner.RunParamsAware; * time. It may be false with -XX:+DisableExplicitGC. */ public class CollectionCounters001 extends MonitoringTestBase implements RunParamsAware, Initializable { + private List gcBeans; private MemoryMXBean memory; Stresser stresser; @@ -76,18 +78,21 @@ public class CollectionCounters001 extends MonitoringTestBase implements RunPara private void runOne(ExecutionController stresser) { updateCounters(); - validate(); - Algorithms.eatMemory(stresser); - if(stresser.continueExecution()) { + validate(false /* don't check gc count increases */); + int iteration = 0; + do { + System.out.println("=========== stresser iter: " + (stresser.getIteration()) + + " runOne iter: " + (++iteration) + " ==========="); + Algorithms.eatMemory(stresser); updateCounters(); - validateNonTrivial(); + validate(true); System.gc(); updateCounters(); - validateNonTrivial(); + validate(true); memory.gc(); updateCounters(); - validateNonTrivial(); - } + validate(true); + } while (stresser.continueExecution()); } public void run() { @@ -98,26 +103,20 @@ public class CollectionCounters001 extends MonitoringTestBase implements RunPara } } - private void validate() { + private void validate(boolean gcCountMustIncrease) { if (collectionCount < 0) - throw new TestFailure("collectionCount negative: " + collectionCount); + throw new TestFailure("collectionCount negative: " + collectionCount); if (collectionTime < 0) - throw new TestFailure("collectionTime negative: " + collectionTime); - if (collectionCount < collectionCountOld) + throw new TestFailure("collectionTime negative: " + collectionTime); + if (collectionTime < collectionTimeOld) + throw new TestFailure("collectionTime decreased: " + collectionTime + " -> " + collectionTimeOld); + if (!gcCountMustIncrease) { + if (collectionCount < collectionCountOld) throw new TestFailure("collectionCount decreased: " + collectionCount + " -> " + collectionCountOld); - if (collectionTime < collectionTimeOld) - throw new TestFailure("collectionTime decreased: " + collectionTime + " -> " + collectionTimeOld); - } - - private void validateNonTrivial() { - if (collectionCount < 0) - throw new TestFailure("collectionCount negative: " + collectionCount); - if (collectionTime < 0) - throw new TestFailure("collectionTime negative: " + collectionTime); - if (collectionCount <= collectionCountOld) + } else { + if (collectionCount <= collectionCountOld) throw new TestFailure("collectionCount not increased: " + collectionCount + " -> " + collectionCountOld); - if (collectionTime < collectionTimeOld) - throw new TestFailure("collection time became smaller: " + collectionTime + " -> " + collectionTimeOld); + } } private void updateCounters() { @@ -126,8 +125,8 @@ public class CollectionCounters001 extends MonitoringTestBase implements RunPara collectionCount = 0; collectionTime = 0; for (GarbageCollectorMXBean gcBean : gcBeans) { - collectionCount += gcBean.getCollectionCount(); - collectionTime += gcBean.getCollectionTime(); + collectionCount += gcBean.getCollectionCount(); + collectionTime += gcBean.getCollectionTime(); } } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/GarbageCollectorMXBean/CollectionCounters/CollectionCounters002/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/GarbageCollectorMXBean/CollectionCounters/CollectionCounters002/TestDescription.java index 9bfbf141d31..c331991cd68 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/GarbageCollectorMXBean/CollectionCounters/CollectionCounters002/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/GarbageCollectorMXBean/CollectionCounters/CollectionCounters002/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, 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,9 +29,10 @@ * @summary converted from VM Testbase nsk/monitoring/GarbageCollectorMXBean/CollectionCounters/CollectionCounters002. * VM Testbase keywords: [monitoring] * + * @requires vm.opt.DisableExplicitGC != "true" * @library /vmTestbase * /test/lib - * @run main/othervm + * @run main/othervm -XX:-UseGCOverheadLimit * nsk.monitoring.GarbageCollectorMXBean.CollectionCounters.CollectionCounters001.CollectionCounters001 * -testMode=server * -MBeanServer=default diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/GarbageCollectorMXBean/CollectionCounters/CollectionCounters003/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/GarbageCollectorMXBean/CollectionCounters/CollectionCounters003/TestDescription.java index 3524cfd66db..024c8d363a5 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/GarbageCollectorMXBean/CollectionCounters/CollectionCounters003/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/GarbageCollectorMXBean/CollectionCounters/CollectionCounters003/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, 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,9 +29,10 @@ * @summary converted from VM Testbase nsk/monitoring/GarbageCollectorMXBean/CollectionCounters/CollectionCounters003. * VM Testbase keywords: [monitoring] * + * @requires vm.opt.DisableExplicitGC != "true" * @library /vmTestbase * /test/lib - * @run main/othervm + * @run main/othervm -XX:-UseGCOverheadLimit * nsk.monitoring.GarbageCollectorMXBean.CollectionCounters.CollectionCounters001.CollectionCounters001 * -testMode=server * -MBeanServer=custom diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/GarbageCollectorMXBean/CollectionCounters/CollectionCounters004/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/GarbageCollectorMXBean/CollectionCounters/CollectionCounters004/TestDescription.java index b215e633464..09cde45ac4f 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/GarbageCollectorMXBean/CollectionCounters/CollectionCounters004/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/GarbageCollectorMXBean/CollectionCounters/CollectionCounters004/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, 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,9 +29,10 @@ * @summary converted from VM Testbase nsk/monitoring/GarbageCollectorMXBean/CollectionCounters/CollectionCounters004. * VM Testbase keywords: [monitoring] * + * @requires vm.opt.DisableExplicitGC != "true" * @library /vmTestbase * /test/lib - * @run main/othervm + * @run main/othervm -XX:-UseGCOverheadLimit * nsk.monitoring.GarbageCollectorMXBean.CollectionCounters.CollectionCounters001.CollectionCounters001 * -testMode=proxy * -MBeanServer=default diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/GarbageCollectorMXBean/CollectionCounters/CollectionCounters005/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/GarbageCollectorMXBean/CollectionCounters/CollectionCounters005/TestDescription.java index 63cccf1c268..f70f680498b 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/GarbageCollectorMXBean/CollectionCounters/CollectionCounters005/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/GarbageCollectorMXBean/CollectionCounters/CollectionCounters005/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, 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,9 +29,10 @@ * @summary converted from VM Testbase nsk/monitoring/GarbageCollectorMXBean/CollectionCounters/CollectionCounters005. * VM Testbase keywords: [monitoring] * + * @requires vm.opt.DisableExplicitGC != "true" * @library /vmTestbase * /test/lib - * @run main/othervm + * @run main/othervm -XX:-UseGCOverheadLimit * nsk.monitoring.GarbageCollectorMXBean.CollectionCounters.CollectionCounters001.CollectionCounters001 * -testMode=proxy * -MBeanServer=custom From b46aef88b333db8866c60c18cbf842b6cb89dacf Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Thu, 11 Dec 2025 08:17:25 +0000 Subject: [PATCH 251/706] 8371871: libSharedCloseAgent.cpp crashes VS2019 and older VS2022 compiler Reviewed-by: jvernee, mdoerr --- test/jdk/java/foreign/sharedclosejvmti/libSharedCloseAgent.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/jdk/java/foreign/sharedclosejvmti/libSharedCloseAgent.cpp b/test/jdk/java/foreign/sharedclosejvmti/libSharedCloseAgent.cpp index a82818e0280..3e7fc2e10da 100644 --- a/test/jdk/java/foreign/sharedclosejvmti/libSharedCloseAgent.cpp +++ b/test/jdk/java/foreign/sharedclosejvmti/libSharedCloseAgent.cpp @@ -102,7 +102,8 @@ Agent_OnLoad(JavaVM *vm, char *options, void *reserved) { return jni_err; } - jvmtiCapabilities capabilities{}; + jvmtiCapabilities capabilities; + memset(&capabilities, 0, sizeof(jvmtiCapabilities)); capabilities.can_generate_method_exit_events = 1; jvmtiError err = env->AddCapabilities(&capabilities); From 4b774cb46d9355015a6bfcf53b47233d6f235239 Mon Sep 17 00:00:00 2001 From: Saranya Natarajan Date: Thu, 11 Dec 2025 08:43:31 +0000 Subject: [PATCH 252/706] 8370489: Some compiler tests miss the @key randomness Reviewed-by: dfenacci, epeter, chagedorn --- .../jtreg/compiler/c2/TestMergeStores.java | 3 ++ .../c2/TestMergeStoresMemorySegment.java | 12 ++++++- .../jtreg/compiler/c2/TestMinMaxSubword.java | 1 + .../c2/aarch64/TestFloat16Replicate.java | 1 + .../compiler/c2/irTests/ModDNodeTests.java | 1 + .../compiler/c2/irTests/ModFNodeTests.java | 1 + .../c2/irTests/ModINodeIdealizationTests.java | 1 + .../c2/irTests/ModLNodeIdealizationTests.java | 1 + .../c2/irTests/TestMulNodeIdealization.java | 3 +- .../compiler/c2/irTests/TestShiftAndMask.java | 1 + .../irTests/UDivINodeIdealizationTests.java | 3 +- .../irTests/UDivLNodeIdealizationTests.java | 3 +- .../irTests/UModINodeIdealizationTests.java | 3 +- .../irTests/UModLNodeIdealizationTests.java | 3 +- .../TestDivDependentOnMainLoopGuard.java | 1 + .../jtreg/compiler/igvn/ExpressionFuzzer.java | 1 + .../TestFloat16MaxMinSpecialValues.java | 1 + .../InvariantCodeMotionReassociateAddSub.java | 1 + .../InvariantCodeMotionReassociateCmp.java | 1 + .../TestParallelIvInIntCountedLoop.java | 1 + .../loopopts/superword/MinMaxRed_Int.java | 1 + .../loopopts/superword/ReductionPerf.java | 3 +- .../loopopts/superword/TestAliasing.java | 1 + .../loopopts/superword/TestAlignVector.java | 1 + .../TestCompatibleUseDefTypeSize.java | 3 +- .../superword/TestDependencyOffsets.java | 33 +++++++++++++++++++ .../superword/TestEquivalentInvariants.java | 1 + .../loopopts/superword/TestMemorySegment.java | 1 + .../TestMemorySegmentUnalignedAddress.java | 1 + .../loopopts/superword/TestSplitPacks.java | 1 + .../jtreg/compiler/vectorapi/Test8278948.java | 3 +- .../vectorapi/TestVectorAddMulReduction.java | 1 + .../TestVectorCompressExpandBits.java | 1 + .../vectorapi/VectorMaskCastIdentityTest.java | 1 + .../compiler/vectorapi/VectorMultiplyOpt.java | 3 +- .../VectorSaturatedOperationsTest.java | 1 + .../vectorization/TestAutoVecIntMinMax.java | 1 + .../vectorization/TestEor3AArch64.java | 1 + .../vectorization/TestMacroLogicVector.java | 3 +- .../vectorization/TestVectorZeroCount.java | 12 +++---- 40 files changed, 99 insertions(+), 17 deletions(-) diff --git a/test/hotspot/jtreg/compiler/c2/TestMergeStores.java b/test/hotspot/jtreg/compiler/c2/TestMergeStores.java index 84329c4a9c8..5e6a757dd5f 100644 --- a/test/hotspot/jtreg/compiler/c2/TestMergeStores.java +++ b/test/hotspot/jtreg/compiler/c2/TestMergeStores.java @@ -34,6 +34,7 @@ import java.util.Random; /* * @test * @bug 8318446 8331054 8331311 8335392 8347405 + * @key randomness * @summary Test merging of consecutive stores * @modules java.base/jdk.internal.misc * @library /test/lib / @@ -43,6 +44,7 @@ import java.util.Random; /* * @test * @bug 8318446 8331054 8331311 8335392 8347405 + * @key randomness * @summary Test merging of consecutive stores * @modules java.base/jdk.internal.misc * @library /test/lib / @@ -52,6 +54,7 @@ import java.util.Random; /* * @test * @bug 8318446 8331054 8331311 8335392 8348959 8351414 + * @key randomness * @summary Test merging of consecutive stores * @modules java.base/jdk.internal.misc * @library /test/lib / diff --git a/test/hotspot/jtreg/compiler/c2/TestMergeStoresMemorySegment.java b/test/hotspot/jtreg/compiler/c2/TestMergeStoresMemorySegment.java index a5302d1b515..a275570747b 100644 --- a/test/hotspot/jtreg/compiler/c2/TestMergeStoresMemorySegment.java +++ b/test/hotspot/jtreg/compiler/c2/TestMergeStoresMemorySegment.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, 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.lang.foreign.*; /* * @test id=byte-array * @bug 8335392 + * @key randomness * @summary Test MergeStores optimization for MemorySegment * @library /test/lib / * @run driver compiler.c2.TestMergeStoresMemorySegment ByteArray @@ -42,6 +43,7 @@ import java.lang.foreign.*; /* * @test id=char-array * @bug 8335392 + * @key randomness * @summary Test MergeStores optimization for MemorySegment * @library /test/lib / * @run driver compiler.c2.TestMergeStoresMemorySegment CharArray @@ -50,6 +52,7 @@ import java.lang.foreign.*; /* * @test id=short-array * @bug 8335392 + * @key randomness * @summary Test MergeStores optimization for MemorySegment * @library /test/lib / * @run driver compiler.c2.TestMergeStoresMemorySegment ShortArray @@ -58,6 +61,7 @@ import java.lang.foreign.*; /* * @test id=int-array * @bug 8335392 + * @key randomness * @summary Test MergeStores optimization for MemorySegment * @library /test/lib / * @run driver compiler.c2.TestMergeStoresMemorySegment IntArray @@ -66,6 +70,7 @@ import java.lang.foreign.*; /* * @test id=long-array * @bug 8335392 + * @key randomness * @summary Test MergeStores optimization for MemorySegment * @library /test/lib / * @run driver compiler.c2.TestMergeStoresMemorySegment LongArray @@ -74,6 +79,7 @@ import java.lang.foreign.*; /* * @test id=float-array * @bug 8335392 + * @key randomness * @summary Test MergeStores optimization for MemorySegment * @library /test/lib / * @run driver compiler.c2.TestMergeStoresMemorySegment FloatArray @@ -82,6 +88,7 @@ import java.lang.foreign.*; /* * @test id=double-array * @bug 8335392 + * @key randomness * @summary Test MergeStores optimization for MemorySegment * @library /test/lib / * @run driver compiler.c2.TestMergeStoresMemorySegment DoubleArray @@ -90,6 +97,7 @@ import java.lang.foreign.*; /* * @test id=byte-buffer * @bug 8335392 + * @key randomness * @summary Test MergeStores optimization for MemorySegment * @library /test/lib / * @run driver compiler.c2.TestMergeStoresMemorySegment ByteBuffer @@ -98,6 +106,7 @@ import java.lang.foreign.*; /* * @test id=byte-buffer-direct * @bug 8335392 + * @key randomness * @summary Test MergeStores optimization for MemorySegment * @library /test/lib / * @run driver compiler.c2.TestMergeStoresMemorySegment ByteBufferDirect @@ -106,6 +115,7 @@ import java.lang.foreign.*; /* * @test id=native * @bug 8335392 + * @key randomness * @summary Test MergeStores optimization for MemorySegment * @library /test/lib / * @run driver compiler.c2.TestMergeStoresMemorySegment Native diff --git a/test/hotspot/jtreg/compiler/c2/TestMinMaxSubword.java b/test/hotspot/jtreg/compiler/c2/TestMinMaxSubword.java index 955aa4058f0..a7e90353f90 100644 --- a/test/hotspot/jtreg/compiler/c2/TestMinMaxSubword.java +++ b/test/hotspot/jtreg/compiler/c2/TestMinMaxSubword.java @@ -31,6 +31,7 @@ import java.util.Random; /* * @test * @bug 8294816 + * @key randomness * @summary Test Math.min/max vectorization miscompilation for integer subwords * @library /test/lib / * @requires vm.compiler2.enabled diff --git a/test/hotspot/jtreg/compiler/c2/aarch64/TestFloat16Replicate.java b/test/hotspot/jtreg/compiler/c2/aarch64/TestFloat16Replicate.java index ab7808a0401..6be4286d2a0 100644 --- a/test/hotspot/jtreg/compiler/c2/aarch64/TestFloat16Replicate.java +++ b/test/hotspot/jtreg/compiler/c2/aarch64/TestFloat16Replicate.java @@ -23,6 +23,7 @@ /** * @test * @bug 8361582 +* @key randomness * @summary Ensure the correct backend replicate node is being generated for * half precision float constants on >16B SVE machines * @modules jdk.incubator.vector diff --git a/test/hotspot/jtreg/compiler/c2/irTests/ModDNodeTests.java b/test/hotspot/jtreg/compiler/c2/irTests/ModDNodeTests.java index 3c28c936d31..7eed798871e 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/ModDNodeTests.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/ModDNodeTests.java @@ -30,6 +30,7 @@ import compiler.lib.ir_framework.*; /* * @test * @bug 8345766 + * @key randomness * @summary Test that Ideal transformations of ModDNode are being performed as expected. * @library /test/lib / * @run driver compiler.c2.irTests.ModDNodeTests diff --git a/test/hotspot/jtreg/compiler/c2/irTests/ModFNodeTests.java b/test/hotspot/jtreg/compiler/c2/irTests/ModFNodeTests.java index 1b5e14b4835..886efe57124 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/ModFNodeTests.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/ModFNodeTests.java @@ -30,6 +30,7 @@ import compiler.lib.ir_framework.*; /* * @test * @bug 8345766 + * @key randomness * @summary Test that Ideal transformations of ModFNode are being performed as expected. * @library /test/lib / * @run driver compiler.c2.irTests.ModFNodeTests diff --git a/test/hotspot/jtreg/compiler/c2/irTests/ModINodeIdealizationTests.java b/test/hotspot/jtreg/compiler/c2/irTests/ModINodeIdealizationTests.java index d19e2562779..1ba71584031 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/ModINodeIdealizationTests.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/ModINodeIdealizationTests.java @@ -32,6 +32,7 @@ import compiler.lib.ir_framework.*; /* * @test * @bug 8332268 + * @key randomness * @summary Test that Ideal transformations of ModINode* are being performed as expected. * @library /test/lib / * @run driver compiler.c2.irTests.ModINodeIdealizationTests diff --git a/test/hotspot/jtreg/compiler/c2/irTests/ModLNodeIdealizationTests.java b/test/hotspot/jtreg/compiler/c2/irTests/ModLNodeIdealizationTests.java index fc08ef60603..719cc596215 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/ModLNodeIdealizationTests.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/ModLNodeIdealizationTests.java @@ -32,6 +32,7 @@ import compiler.lib.ir_framework.*; /* * @test * @bug 8267265 + * @key randomness * @summary Test that Ideal transformations of ModLNode* are being performed as expected. * @library /test/lib / * @run driver compiler.c2.irTests.ModLNodeIdealizationTests diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestMulNodeIdealization.java b/test/hotspot/jtreg/compiler/c2/irTests/TestMulNodeIdealization.java index ca6d5fbe118..e0307f2eb98 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/TestMulNodeIdealization.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestMulNodeIdealization.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, 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 jdk.test.lib.Utils; /* * @test * @bug 8291336 + * @key randomness * @summary Test that transformation of multiply-by-2 is appropriately turned into additions. * @library /test/lib / * @requires vm.compiler2.enabled diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestShiftAndMask.java b/test/hotspot/jtreg/compiler/c2/irTests/TestShiftAndMask.java index 2cdc6414685..1413ee0cafa 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/TestShiftAndMask.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestShiftAndMask.java @@ -31,6 +31,7 @@ import java.util.Objects; /* * @test * @bug 8277850 8278949 8285793 8346664 + * @key randomness * @summary C2: optimize mask checks in counted loops * @library /test/lib / * @run driver compiler.c2.irTests.TestShiftAndMask diff --git a/test/hotspot/jtreg/compiler/c2/irTests/UDivINodeIdealizationTests.java b/test/hotspot/jtreg/compiler/c2/irTests/UDivINodeIdealizationTests.java index 7183e0b311a..dd135c93e0d 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/UDivINodeIdealizationTests.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/UDivINodeIdealizationTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, 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,6 +32,7 @@ import compiler.lib.ir_framework.*; /* * @test * @bug 8332268 + * @key randomness * @summary Test that Ideal transformations of UDivINode* are being performed as expected. * @library /test/lib / * @run driver compiler.c2.irTests.UDivINodeIdealizationTests diff --git a/test/hotspot/jtreg/compiler/c2/irTests/UDivLNodeIdealizationTests.java b/test/hotspot/jtreg/compiler/c2/irTests/UDivLNodeIdealizationTests.java index a5cfc2cddc5..bc80805cabd 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/UDivLNodeIdealizationTests.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/UDivLNodeIdealizationTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, 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,6 +32,7 @@ import compiler.lib.ir_framework.*; /* * @test * @bug 8332268 + * @key randomness * @summary Test that Ideal transformations of UDivLNode* are being performed as expected. * @library /test/lib / * @run driver compiler.c2.irTests.UDivLNodeIdealizationTests diff --git a/test/hotspot/jtreg/compiler/c2/irTests/UModINodeIdealizationTests.java b/test/hotspot/jtreg/compiler/c2/irTests/UModINodeIdealizationTests.java index fa24033ab46..99982c70b6e 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/UModINodeIdealizationTests.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/UModINodeIdealizationTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, 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,6 +32,7 @@ import compiler.lib.ir_framework.*; /* * @test * @bug 8332268 + * @key randomness * @summary Test that Ideal transformations of UModINode* are being performed as expected. * @library /test/lib / * @run driver compiler.c2.irTests.UModINodeIdealizationTests diff --git a/test/hotspot/jtreg/compiler/c2/irTests/UModLNodeIdealizationTests.java b/test/hotspot/jtreg/compiler/c2/irTests/UModLNodeIdealizationTests.java index 93ae861cfaa..9bbded327e0 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/UModLNodeIdealizationTests.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/UModLNodeIdealizationTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, 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,6 +32,7 @@ import compiler.lib.ir_framework.*; /* * @test * @bug 8332268 + * @key randomness * @summary Test that Ideal transformations of UModLNode* are being performed as expected. * @library /test/lib / * @run driver compiler.c2.irTests.UModLNodeIdealizationTests diff --git a/test/hotspot/jtreg/compiler/controldependency/TestDivDependentOnMainLoopGuard.java b/test/hotspot/jtreg/compiler/controldependency/TestDivDependentOnMainLoopGuard.java index a6b7a462743..27fdc6b9e34 100644 --- a/test/hotspot/jtreg/compiler/controldependency/TestDivDependentOnMainLoopGuard.java +++ b/test/hotspot/jtreg/compiler/controldependency/TestDivDependentOnMainLoopGuard.java @@ -24,6 +24,7 @@ /* * @test * @bug 8349139 + * @key randomness * @summary C2: Div looses dependency on condition that guarantees divisor not null in counted loop * @library /test/lib / * @run main/othervm -Xcomp -XX:-TieredCompilation -XX:CompileOnly=TestDivDependentOnMainLoopGuard::* diff --git a/test/hotspot/jtreg/compiler/igvn/ExpressionFuzzer.java b/test/hotspot/jtreg/compiler/igvn/ExpressionFuzzer.java index 40bfb2e4319..570c59f0da2 100644 --- a/test/hotspot/jtreg/compiler/igvn/ExpressionFuzzer.java +++ b/test/hotspot/jtreg/compiler/igvn/ExpressionFuzzer.java @@ -24,6 +24,7 @@ /* * @test * @bug 8359412 + * @key randomness * @summary Use the template framework library to generate random expressions. * @modules java.base/jdk.internal.misc * @library /test/lib / diff --git a/test/hotspot/jtreg/compiler/intrinsics/float16/TestFloat16MaxMinSpecialValues.java b/test/hotspot/jtreg/compiler/intrinsics/float16/TestFloat16MaxMinSpecialValues.java index f83ca307d84..f85297859f3 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/float16/TestFloat16MaxMinSpecialValues.java +++ b/test/hotspot/jtreg/compiler/intrinsics/float16/TestFloat16MaxMinSpecialValues.java @@ -30,6 +30,7 @@ import jdk.test.lib.*; /** * @test * @bug 8352585 + * @key randomness * @library /test/lib / * @summary Add special case handling for Float16.max/min x86 backend * @modules jdk.incubator.vector diff --git a/test/hotspot/jtreg/compiler/loopopts/InvariantCodeMotionReassociateAddSub.java b/test/hotspot/jtreg/compiler/loopopts/InvariantCodeMotionReassociateAddSub.java index 11f37c1f7e7..e05cef8335b 100644 --- a/test/hotspot/jtreg/compiler/loopopts/InvariantCodeMotionReassociateAddSub.java +++ b/test/hotspot/jtreg/compiler/loopopts/InvariantCodeMotionReassociateAddSub.java @@ -31,6 +31,7 @@ import java.util.Random; /* * @test * @bug 8323220 + * @key randomness * @summary Test loop invariant code motion of add/sub through reassociation * @library /test/lib / * @run driver compiler.c2.loopopts.InvariantCodeMotionReassociateAddSub diff --git a/test/hotspot/jtreg/compiler/loopopts/InvariantCodeMotionReassociateCmp.java b/test/hotspot/jtreg/compiler/loopopts/InvariantCodeMotionReassociateCmp.java index 566e294b4bf..bf139befc98 100644 --- a/test/hotspot/jtreg/compiler/loopopts/InvariantCodeMotionReassociateCmp.java +++ b/test/hotspot/jtreg/compiler/loopopts/InvariantCodeMotionReassociateCmp.java @@ -31,6 +31,7 @@ import java.util.Random; /* * @test * @bug 8323220 + * @key randomness * @summary Test loop invariant code motion for cmp nodes through reassociation * @library /test/lib / * @run driver compiler.c2.loopopts.InvariantCodeMotionReassociateCmp diff --git a/test/hotspot/jtreg/compiler/loopopts/parallel_iv/TestParallelIvInIntCountedLoop.java b/test/hotspot/jtreg/compiler/loopopts/parallel_iv/TestParallelIvInIntCountedLoop.java index 95ba9e6e795..f8abb716e42 100644 --- a/test/hotspot/jtreg/compiler/loopopts/parallel_iv/TestParallelIvInIntCountedLoop.java +++ b/test/hotspot/jtreg/compiler/loopopts/parallel_iv/TestParallelIvInIntCountedLoop.java @@ -32,6 +32,7 @@ import java.util.Random; /** * @test * @bug 8328528 + * @key randomness * @summary test the long typed parallel iv replacing transformation for int counted loop * @library /test/lib / * @requires vm.compiler2.enabled diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/MinMaxRed_Int.java b/test/hotspot/jtreg/compiler/loopopts/superword/MinMaxRed_Int.java index 4e15c0de6e9..08f5e200aa0 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/MinMaxRed_Int.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/MinMaxRed_Int.java @@ -24,6 +24,7 @@ /** * @test * @bug 8302673 + * @key randomness * @summary [SuperWord] MaxReduction and MinReduction should vectorize for int * @library /test/lib / * @run driver compiler.loopopts.superword.MinMaxRed_Int diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/ReductionPerf.java b/test/hotspot/jtreg/compiler/loopopts/superword/ReductionPerf.java index 56acdd349f8..10181ab3da2 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/ReductionPerf.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/ReductionPerf.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, 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,7 @@ /* * @test * @bug 8074981 8302652 + * @key randomness * @summary Test SuperWord Reduction Perf. * @library /test/lib / * @run main/othervm -Xbatch diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestAliasing.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestAliasing.java index 33cef6e5e6b..f5ad14871f9 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/TestAliasing.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestAliasing.java @@ -24,6 +24,7 @@ /* * @test * @bug 8324751 + * @key randomness * @summary Test Speculative Aliasing checks in SuperWord * @library /test/lib / * @run driver compiler.loopopts.superword.TestAliasing nCOH_nAV_ySAC diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestAlignVector.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestAlignVector.java index 322c36c39e1..5a2d11ef2e1 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/TestAlignVector.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestAlignVector.java @@ -36,6 +36,7 @@ import java.nio.ByteOrder; /* * @test id=NoAlignVector * @bug 8310190 + * @key randomness * @summary Test AlignVector with various loop init, stride, scale, invar, etc. * @modules java.base/jdk.internal.misc * @library /test/lib / diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestCompatibleUseDefTypeSize.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestCompatibleUseDefTypeSize.java index e6c373c4c87..0e17489e1c8 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/TestCompatibleUseDefTypeSize.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestCompatibleUseDefTypeSize.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, 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,6 +35,7 @@ import java.nio.ByteOrder; /* * @test * @bug 8325155 + * @key randomness * @summary Test some cases that vectorize after the removal of the alignment boundaries code. * Now, we instead check if use-def connections have compatible type size. * @library /test/lib / diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestDependencyOffsets.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestDependencyOffsets.java index e2aca036474..2678aab9c40 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/TestDependencyOffsets.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestDependencyOffsets.java @@ -24,6 +24,7 @@ /* * @test id=vanilla-A * @bug 8298935 8308606 8310308 8312570 8310190 + * @key randomness * @summary Test SuperWord: vector size, offsets, dependencies, alignment. * @library /test/lib / * @compile ../../lib/ir_framework/TestFramework.java @@ -33,6 +34,7 @@ /* * @test id=vanilla-U * @bug 8298935 8308606 8310308 8312570 8310190 + * @key randomness * @summary Test SuperWord: vector size, offsets, dependencies, alignment. * @library /test/lib / * @compile ../../lib/ir_framework/TestFramework.java @@ -42,6 +44,7 @@ /* * @test id=sse4-v016-A * @bug 8298935 8308606 8310308 8312570 8310190 + * @key randomness * @summary Test SuperWord: vector size, offsets, dependencies, alignment. * @requires vm.compiler2.enabled * @requires (os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64") @@ -54,6 +57,7 @@ /* * @test id=sse4-v016-U * @bug 8298935 8308606 8310308 8312570 8310190 + * @key randomness * @summary Test SuperWord: vector size, offsets, dependencies, alignment. * @requires vm.compiler2.enabled * @requires (os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64") @@ -66,6 +70,7 @@ /* * @test id=sse4-v008-A * @bug 8298935 8308606 8310308 8312570 8310190 + * @key randomness * @summary Test SuperWord: vector size, offsets, dependencies, alignment. * @requires vm.compiler2.enabled * @requires (os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64") @@ -78,6 +83,7 @@ /* * @test id=sse4-v008-U * @bug 8298935 8308606 8310308 8312570 8310190 + * @key randomness * @summary Test SuperWord: vector size, offsets, dependencies, alignment. * @requires vm.compiler2.enabled * @requires (os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64") @@ -102,6 +108,7 @@ /* * @test id=sse4-v004-U * @bug 8298935 8308606 8310308 8312570 8310190 + * @key randomness * @summary Test SuperWord: vector size, offsets, dependencies, alignment. * @requires vm.compiler2.enabled * @requires (os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64") @@ -114,6 +121,7 @@ /* * @test id=avx1-v032-A * @bug 8298935 8308606 8310308 8312570 8310190 + * @key randomness * @summary Test SuperWord: vector size, offsets, dependencies, alignment. * @requires vm.compiler2.enabled * @requires (os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64") @@ -126,6 +134,7 @@ /* * @test id=avx1-v032-U * @bug 8298935 8308606 8310308 8312570 8310190 + * @key randomness * @summary Test SuperWord: vector size, offsets, dependencies, alignment. * @requires vm.compiler2.enabled * @requires (os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64") @@ -138,6 +147,7 @@ /* * @test id=avx1-v016-A * @bug 8298935 8308606 8310308 8312570 8310190 + * @key randomness * @summary Test SuperWord: vector size, offsets, dependencies, alignment. * @requires vm.compiler2.enabled * @requires (os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64") @@ -150,6 +160,7 @@ /* * @test id=avx1-v016-U * @bug 8298935 8308606 8310308 8312570 8310190 + * @key randomness * @summary Test SuperWord: vector size, offsets, dependencies, alignment. * @requires vm.compiler2.enabled * @requires (os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64") @@ -162,6 +173,7 @@ /* * @test id=avx2-v032-A * @bug 8298935 8308606 8310308 8312570 8310190 + * @key randomness * @summary Test SuperWord: vector size, offsets, dependencies, alignment. * @requires vm.compiler2.enabled * @requires (os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64") @@ -174,6 +186,7 @@ /* * @test id=avx2-v032-U * @bug 8298935 8308606 8310308 8312570 8310190 + * @key randomness * @summary Test SuperWord: vector size, offsets, dependencies, alignment. * @requires vm.compiler2.enabled * @requires (os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64") @@ -186,6 +199,7 @@ /* * @test id=avx2-v016-A * @bug 8298935 8308606 8310308 8312570 8310190 + * @key randomness * @summary Test SuperWord: vector size, offsets, dependencies, alignment. * @requires vm.compiler2.enabled * @requires (os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64") @@ -198,6 +212,7 @@ /* * @test id=avx2-v016-U * @bug 8298935 8308606 8310308 8312570 8310190 + * @key randomness * @summary Test SuperWord: vector size, offsets, dependencies, alignment. * @requires vm.compiler2.enabled * @requires (os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64") @@ -210,6 +225,7 @@ /* * @test id=avx512-v064-A * @bug 8298935 8308606 8310308 8312570 8310190 + * @key randomness * @summary Test SuperWord: vector size, offsets, dependencies, alignment. * @requires vm.compiler2.enabled * @requires (os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64") @@ -222,6 +238,7 @@ /* * @test id=avx512-v064-U * @bug 8298935 8308606 8310308 8312570 8310190 + * @key randomness * @summary Test SuperWord: vector size, offsets, dependencies, alignment. * @requires vm.compiler2.enabled * @requires (os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64") @@ -234,6 +251,7 @@ /* * @test id=avx512-v032-A * @bug 8298935 8308606 8310308 8312570 8310190 + * @key randomness * @summary Test SuperWord: vector size, offsets, dependencies, alignment. * @requires vm.compiler2.enabled * @requires (os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64") @@ -246,6 +264,7 @@ /* * @test id=avx512-v032-U * @bug 8298935 8308606 8310308 8312570 8310190 + * @key randomness * @summary Test SuperWord: vector size, offsets, dependencies, alignment. * @requires vm.compiler2.enabled * @requires (os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64") @@ -258,6 +277,7 @@ /* * @test id=avx512bw-v064-A * @bug 8298935 8308606 8310308 8312570 8310190 + * @key randomness * @summary Test SuperWord: vector size, offsets, dependencies, alignment. * @requires vm.compiler2.enabled * @requires (os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64") @@ -270,6 +290,7 @@ /* * @test id=avx512bw-v064-U * @bug 8298935 8308606 8310308 8312570 8310190 + * @key randomness * @summary Test SuperWord: vector size, offsets, dependencies, alignment. * @requires vm.compiler2.enabled * @requires (os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64") @@ -282,6 +303,7 @@ /* * @test id=avx512bw-v032-A * @bug 8298935 8308606 8310308 8312570 8310190 + * @key randomness * @summary Test SuperWord: vector size, offsets, dependencies, alignment. * @requires vm.compiler2.enabled * @requires (os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64") @@ -294,6 +316,7 @@ /* * @test id=avx512bw-v032-U * @bug 8298935 8308606 8310308 8312570 8310190 + * @key randomness * @summary Test SuperWord: vector size, offsets, dependencies, alignment. * @requires vm.compiler2.enabled * @requires (os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64") @@ -306,6 +329,7 @@ /* * @test id=vec-v064-A * @bug 8298935 8308606 8310308 8312570 8310190 + * @key randomness * @summary Test SuperWord: vector size, offsets, dependencies, alignment. * @requires vm.compiler2.enabled * @requires (os.arch!="x86" & os.arch!="i386" & os.arch!="amd64" & os.arch!="x86_64") @@ -317,6 +341,7 @@ /* * @test id=vec-v064-U * @bug 8298935 8308606 8310308 8312570 8310190 + * @key randomness * @summary Test SuperWord: vector size, offsets, dependencies, alignment. * @requires vm.compiler2.enabled * @requires (os.arch!="x86" & os.arch!="i386" & os.arch!="amd64" & os.arch!="x86_64") @@ -328,6 +353,7 @@ /* * @test id=vec-v032-A * @bug 8298935 8308606 8310308 8312570 8310190 + * @key randomness * @summary Test SuperWord: vector size, offsets, dependencies, alignment. * @requires vm.compiler2.enabled * @requires (os.arch!="x86" & os.arch!="i386" & os.arch!="amd64" & os.arch!="x86_64") @@ -339,6 +365,7 @@ /* * @test id=vec-v032-U * @bug 8298935 8308606 8310308 8312570 8310190 + * @key randomness * @summary Test SuperWord: vector size, offsets, dependencies, alignment. * @requires vm.compiler2.enabled * @requires (os.arch!="x86" & os.arch!="i386" & os.arch!="amd64" & os.arch!="x86_64") @@ -350,6 +377,7 @@ /* * @test id=vec-v016-A * @bug 8298935 8308606 8310308 8312570 8310190 + * @key randomness * @summary Test SuperWord: vector size, offsets, dependencies, alignment. * @requires vm.compiler2.enabled * @requires (os.arch!="x86" & os.arch!="i386" & os.arch!="amd64" & os.arch!="x86_64") @@ -361,6 +389,7 @@ /* * @test id=vec-v016-U * @bug 8298935 8308606 8310308 8312570 8310190 + * @key randomness * @summary Test SuperWord: vector size, offsets, dependencies, alignment. * @requires vm.compiler2.enabled * @requires (os.arch!="x86" & os.arch!="i386" & os.arch!="amd64" & os.arch!="x86_64") @@ -372,6 +401,7 @@ /* * @test id=vec-v008-A * @bug 8298935 8308606 8310308 8312570 8310190 + * @key randomness * @summary Test SuperWord: vector size, offsets, dependencies, alignment. * @requires vm.compiler2.enabled * @requires (os.arch!="x86" & os.arch!="i386" & os.arch!="amd64" & os.arch!="x86_64") @@ -383,6 +413,7 @@ /* * @test id=vec-v008-U * @bug 8298935 8308606 8310308 8312570 8310190 + * @key randomness * @summary Test SuperWord: vector size, offsets, dependencies, alignment. * @requires vm.compiler2.enabled * @requires (os.arch!="x86" & os.arch!="i386" & os.arch!="amd64" & os.arch!="x86_64") @@ -394,6 +425,7 @@ /* * @test id=vec-v004-A * @bug 8298935 8308606 8310308 8312570 8310190 + * @key randomness * @summary Test SuperWord: vector size, offsets, dependencies, alignment. * @requires vm.compiler2.enabled * @requires (os.arch!="x86" & os.arch!="i386" & os.arch!="amd64" & os.arch!="x86_64") @@ -405,6 +437,7 @@ /* * @test id=vec-v004-U * @bug 8298935 8308606 8310308 8312570 8310190 + * @key randomness * @summary Test SuperWord: vector size, offsets, dependencies, alignment. * @requires vm.compiler2.enabled * @requires (os.arch!="x86" & os.arch!="i386" & os.arch!="amd64" & os.arch!="x86_64") diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestEquivalentInvariants.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestEquivalentInvariants.java index 91d1ee9666a..8677ae851cf 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/TestEquivalentInvariants.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestEquivalentInvariants.java @@ -35,6 +35,7 @@ import java.lang.foreign.*; /* * @test * @bug 8343685 8331659 + * @key randomness * @summary Test vectorization with various invariants that are equivalent, but not trivially so, * i.e. where the invariants have the same summands, but in a different order. * @modules java.base/jdk.internal.misc diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegment.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegment.java index a2b5434a5a2..20ba2638fc1 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegment.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegment.java @@ -34,6 +34,7 @@ import java.lang.foreign.*; /* * @test id=byte-array * @bug 8329273 + * @key randomness * @summary Test vectorization of loops over MemorySegment * @library /test/lib / * @run driver compiler.loopopts.superword.TestMemorySegment ByteArray diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegmentUnalignedAddress.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegmentUnalignedAddress.java index 969014e2293..7354ba896d0 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegmentUnalignedAddress.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegmentUnalignedAddress.java @@ -35,6 +35,7 @@ import java.lang.foreign.*; /* * @test id=byte-buffer-direct * @bug 8323582 + * @key randomness * @summary Test vectorization of loops over MemorySegment, with native memory where the address is not always aligned. * @library /test/lib / * @run driver compiler.loopopts.superword.TestMemorySegmentUnalignedAddress ByteBufferDirect diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestSplitPacks.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestSplitPacks.java index 631b55fc65f..9a2e23e4530 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/TestSplitPacks.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestSplitPacks.java @@ -35,6 +35,7 @@ import java.nio.ByteOrder; /* * @test * @bug 8326139 8348659 + * @key randomness * @summary Test splitting packs in SuperWord * @library /test/lib / * @run driver compiler.loopopts.superword.TestSplitPacks nCOH_nAV_ySAC diff --git a/test/hotspot/jtreg/compiler/vectorapi/Test8278948.java b/test/hotspot/jtreg/compiler/vectorapi/Test8278948.java index 5218e10c4af..5170c188133 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/Test8278948.java +++ b/test/hotspot/jtreg/compiler/vectorapi/Test8278948.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, 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,6 +33,7 @@ import jdk.test.lib.Utils; /* * @test * @bug 8278948 + * @key randomness * @summary Intermediate integer promotion vector length encoding is calculated incorrectly on x86 * @modules jdk.incubator.vector * @library /test/lib diff --git a/test/hotspot/jtreg/compiler/vectorapi/TestVectorAddMulReduction.java b/test/hotspot/jtreg/compiler/vectorapi/TestVectorAddMulReduction.java index 38a2753a7ed..ddf16ce185f 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/TestVectorAddMulReduction.java +++ b/test/hotspot/jtreg/compiler/vectorapi/TestVectorAddMulReduction.java @@ -38,6 +38,7 @@ import jdk.test.lib.Utils; /** * @test * @bug 8320725 + * @key randomness * @library /test/lib / * @summary Verify non-strictly ordered AddReductionVF/VD and MulReductionVF/VD * nodes are generated in VectorAPI diff --git a/test/hotspot/jtreg/compiler/vectorapi/TestVectorCompressExpandBits.java b/test/hotspot/jtreg/compiler/vectorapi/TestVectorCompressExpandBits.java index f5174b7e6dc..8889ccd0d26 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/TestVectorCompressExpandBits.java +++ b/test/hotspot/jtreg/compiler/vectorapi/TestVectorCompressExpandBits.java @@ -38,6 +38,7 @@ import jdk.test.lib.Utils; /** * @test * @bug 8301012 + * @key randomness * @library /test/lib / * @requires os.arch == "aarch64" & vm.cpu.features ~= ".*sve2.*" & vm.cpu.features ~= ".*svebitperm.*" * @summary [vectorapi]: Intrinsify CompressBitsV/ExpandBitsV and add the AArch64 SVE backend implementation diff --git a/test/hotspot/jtreg/compiler/vectorapi/VectorMaskCastIdentityTest.java b/test/hotspot/jtreg/compiler/vectorapi/VectorMaskCastIdentityTest.java index e66b16f053b..be9d8e6390c 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/VectorMaskCastIdentityTest.java +++ b/test/hotspot/jtreg/compiler/vectorapi/VectorMaskCastIdentityTest.java @@ -24,6 +24,7 @@ /* * @test * @bug 8356760 +* @key randomness * @library /test/lib / * @summary Optimize VectorMask.fromLong for all-true/all-false cases * @modules jdk.incubator.vector diff --git a/test/hotspot/jtreg/compiler/vectorapi/VectorMultiplyOpt.java b/test/hotspot/jtreg/compiler/vectorapi/VectorMultiplyOpt.java index a48cd25e47f..a8394f41f8a 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/VectorMultiplyOpt.java +++ b/test/hotspot/jtreg/compiler/vectorapi/VectorMultiplyOpt.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, 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,6 +32,7 @@ import java.lang.reflect.Array; /** * @test * @bug 8341137 + * @key randomness * @summary Optimize long vector multiplication using x86 VPMUL[U]DQ instruction. * @modules jdk.incubator.vector * @library /test/lib / diff --git a/test/hotspot/jtreg/compiler/vectorapi/VectorSaturatedOperationsTest.java b/test/hotspot/jtreg/compiler/vectorapi/VectorSaturatedOperationsTest.java index 887c41efd48..e51e6d31cb5 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/VectorSaturatedOperationsTest.java +++ b/test/hotspot/jtreg/compiler/vectorapi/VectorSaturatedOperationsTest.java @@ -24,6 +24,7 @@ /** * @test * @bug 8338021 8342677 8349522 +* @key randomness * @summary Add IR validation tests for newly added saturated vector add / sub operations * @modules jdk.incubator.vector * @library /test/lib / diff --git a/test/hotspot/jtreg/compiler/vectorization/TestAutoVecIntMinMax.java b/test/hotspot/jtreg/compiler/vectorization/TestAutoVecIntMinMax.java index 6d868b48dd7..917d69876ce 100644 --- a/test/hotspot/jtreg/compiler/vectorization/TestAutoVecIntMinMax.java +++ b/test/hotspot/jtreg/compiler/vectorization/TestAutoVecIntMinMax.java @@ -30,6 +30,7 @@ import jdk.test.lib.Utils; /* * @test * @bug 8288107 + * @key randomness * @summary Auto-vectorization enhancement for integer Math.max/Math.min operations * @library /test/lib / * @requires vm.compiler2.enabled diff --git a/test/hotspot/jtreg/compiler/vectorization/TestEor3AArch64.java b/test/hotspot/jtreg/compiler/vectorization/TestEor3AArch64.java index d5a3de09123..3fed3eda124 100644 --- a/test/hotspot/jtreg/compiler/vectorization/TestEor3AArch64.java +++ b/test/hotspot/jtreg/compiler/vectorization/TestEor3AArch64.java @@ -33,6 +33,7 @@ import jdk.test.lib.Utils; /* * @test * @bug 8293488 + * @key randomness * @summary Test EOR3 Neon/SVE2 instruction for aarch64 SHA3 extension * @library /test/lib / * @requires os.arch == "aarch64" diff --git a/test/hotspot/jtreg/compiler/vectorization/TestMacroLogicVector.java b/test/hotspot/jtreg/compiler/vectorization/TestMacroLogicVector.java index d2486f0ed77..9ab5994f566 100644 --- a/test/hotspot/jtreg/compiler/vectorization/TestMacroLogicVector.java +++ b/test/hotspot/jtreg/compiler/vectorization/TestMacroLogicVector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, 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,7 @@ /** * @test * @bug 8241040 + * @key randomness * @library /test/lib * * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions diff --git a/test/hotspot/jtreg/compiler/vectorization/TestVectorZeroCount.java b/test/hotspot/jtreg/compiler/vectorization/TestVectorZeroCount.java index c30a28c46f9..7d03bb52071 100644 --- a/test/hotspot/jtreg/compiler/vectorization/TestVectorZeroCount.java +++ b/test/hotspot/jtreg/compiler/vectorization/TestVectorZeroCount.java @@ -21,20 +21,20 @@ * questions. */ +package compiler.vectorization; + +import java.util.Random; +import jdk.test.lib.Utils; + /* @test * @bug 8349637 + * @key randomness * @requires vm.flavor == "server" & (vm.opt.TieredStopAtLevel == null | vm.opt.TieredStopAtLevel == 4) * @summary Ensure that vectorization of numberOfLeadingZeros and numberOfTrailingZeros outputs correct values * @library /test/lib / * @run main/othervm/timeout=480 compiler.vectorization.TestVectorZeroCount */ -package compiler.vectorization; - -import java.util.Random; - -import jdk.test.lib.Utils; - public class TestVectorZeroCount { private static final int SIZE = 1024; private static final Random RANDOM = Utils.getRandomInstance(); From 6a6ff876c515eba6cc89320e02dc5739d4540316 Mon Sep 17 00:00:00 2001 From: Roman Marchenko Date: Thu, 11 Dec 2025 08:48:26 +0000 Subject: [PATCH 253/706] 8372860: TestCodeCacheUnloadDuringConcCycle fails on ARM32 Reviewed-by: tschatzl, shade --- .../hotspot/jtreg/gc/g1/TestCodeCacheUnloadDuringConcCycle.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/hotspot/jtreg/gc/g1/TestCodeCacheUnloadDuringConcCycle.java b/test/hotspot/jtreg/gc/g1/TestCodeCacheUnloadDuringConcCycle.java index a4fadc185d2..af746ad206d 100644 --- a/test/hotspot/jtreg/gc/g1/TestCodeCacheUnloadDuringConcCycle.java +++ b/test/hotspot/jtreg/gc/g1/TestCodeCacheUnloadDuringConcCycle.java @@ -140,7 +140,7 @@ class TestCodeCacheUnloadDuringConcCycleRunner { System.out.println("Compiled " + i + " classes"); } i++; - } while (i < 200); + } while (i < 1000); System.out.println("Compilation done, compiled " + i + " classes"); } catch (Throwable t) { } From aa986be7529b7a2950202dbe6885e5224d331078 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Thu, 11 Dec 2025 10:56:20 +0000 Subject: [PATCH 254/706] 8373421: Parallel: Rename young generation eden and survivor space pool Reviewed-by: tschatzl, jsikstro --- .../gc/parallel/parallelScavengeHeap.cpp | 14 ++++++------ .../share/gc/parallel/psMemoryPool.cpp | 22 +++++++++---------- .../share/gc/parallel/psMemoryPool.hpp | 18 +++++++-------- 3 files changed, 27 insertions(+), 27 deletions(-) diff --git a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp index cff53e84059..0d8a3166f79 100644 --- a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp +++ b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp @@ -132,14 +132,14 @@ jint ParallelScavengeHeap::initialize() { void ParallelScavengeHeap::initialize_serviceability() { - _eden_pool = new EdenMutableSpacePool(_young_gen, - _young_gen->eden_space(), - "PS Eden Space", - false /* support_usage_threshold */); + _eden_pool = new PSEdenSpacePool(_young_gen, + _young_gen->eden_space(), + "PS Eden Space", + false /* support_usage_threshold */); - _survivor_pool = new SurvivorMutableSpacePool(_young_gen, - "PS Survivor Space", - false /* support_usage_threshold */); + _survivor_pool = new PSSurvivorSpacePool(_young_gen, + "PS Survivor Space", + false /* support_usage_threshold */); _old_pool = new PSOldGenerationPool(_old_gen, "PS Old Gen", diff --git a/src/hotspot/share/gc/parallel/psMemoryPool.cpp b/src/hotspot/share/gc/parallel/psMemoryPool.cpp index 81c7b17a1ef..40170f62f06 100644 --- a/src/hotspot/share/gc/parallel/psMemoryPool.cpp +++ b/src/hotspot/share/gc/parallel/psMemoryPool.cpp @@ -39,16 +39,16 @@ MemoryUsage PSOldGenerationPool::get_memory_usage() { return MemoryUsage(initial_size(), used, committed, maxSize); } -// The max size of EdenMutableSpacePool = +// The max size of PSEdenSpacePool = // max size of the PSYoungGen - capacity of two survivor spaces // // Max size of PS eden space is changing due to ergonomic. // PSYoungGen, PSOldGen, Eden, Survivor spaces are all resizable. // -EdenMutableSpacePool::EdenMutableSpacePool(PSYoungGen* young_gen, - MutableSpace* space, - const char* name, - bool support_usage_threshold) : +PSEdenSpacePool::PSEdenSpacePool(PSYoungGen* young_gen, + MutableSpace* space, + const char* name, + bool support_usage_threshold) : CollectedMemoryPool(name, space->capacity_in_bytes(), (young_gen->max_gen_size() - young_gen->from_space()->capacity_in_bytes() - @@ -58,7 +58,7 @@ EdenMutableSpacePool::EdenMutableSpacePool(PSYoungGen* young_gen, _space(space) { } -MemoryUsage EdenMutableSpacePool::get_memory_usage() { +MemoryUsage PSEdenSpacePool::get_memory_usage() { size_t maxSize = (available_for_allocation() ? max_size() : 0); size_t used = used_in_bytes(); size_t committed = _space->capacity_in_bytes(); @@ -66,20 +66,20 @@ MemoryUsage EdenMutableSpacePool::get_memory_usage() { return MemoryUsage(initial_size(), used, committed, maxSize); } -// The max size of SurvivorMutableSpacePool = +// The max size of PSSurvivorSpacePool = // current capacity of the from-space // // PS from and to survivor spaces could have different sizes. // -SurvivorMutableSpacePool::SurvivorMutableSpacePool(PSYoungGen* young_gen, - const char* name, - bool support_usage_threshold) : +PSSurvivorSpacePool::PSSurvivorSpacePool(PSYoungGen* young_gen, + const char* name, + bool support_usage_threshold) : CollectedMemoryPool(name, young_gen->from_space()->capacity_in_bytes(), young_gen->from_space()->capacity_in_bytes(), support_usage_threshold), _young_gen(young_gen) { } -MemoryUsage SurvivorMutableSpacePool::get_memory_usage() { +MemoryUsage PSSurvivorSpacePool::get_memory_usage() { size_t maxSize = (available_for_allocation() ? max_size() : 0); size_t used = used_in_bytes(); size_t committed = committed_in_bytes(); diff --git a/src/hotspot/share/gc/parallel/psMemoryPool.hpp b/src/hotspot/share/gc/parallel/psMemoryPool.hpp index 0da47e5a8ef..ed9793203d4 100644 --- a/src/hotspot/share/gc/parallel/psMemoryPool.hpp +++ b/src/hotspot/share/gc/parallel/psMemoryPool.hpp @@ -43,16 +43,16 @@ public: size_t max_size() const { return _old_gen->reserved().byte_size(); } }; -class EdenMutableSpacePool : public CollectedMemoryPool { +class PSEdenSpacePool : public CollectedMemoryPool { private: PSYoungGen* _young_gen; MutableSpace* _space; public: - EdenMutableSpacePool(PSYoungGen* young_gen, - MutableSpace* space, - const char* name, - bool support_usage_threshold); + PSEdenSpacePool(PSYoungGen* young_gen, + MutableSpace* space, + const char* name, + bool support_usage_threshold); MutableSpace* space() { return _space; } MemoryUsage get_memory_usage(); @@ -65,14 +65,14 @@ public: } }; -class SurvivorMutableSpacePool : public CollectedMemoryPool { +class PSSurvivorSpacePool : public CollectedMemoryPool { private: PSYoungGen* _young_gen; public: - SurvivorMutableSpacePool(PSYoungGen* young_gen, - const char* name, - bool support_usage_threshold); + PSSurvivorSpacePool(PSYoungGen* young_gen, + const char* name, + bool support_usage_threshold); MemoryUsage get_memory_usage(); From e1d1d53cd1211b64d1fef03583a23056908b3482 Mon Sep 17 00:00:00 2001 From: Daniel Gredler Date: Thu, 11 Dec 2025 13:53:01 +0000 Subject: [PATCH 255/706] 8167268: StandardGlyphVector.getGlyphMetrics creates metrics with erroneous bounds for characters with no outline (e.g., the space character ' ') Reviewed-by: serb, prr --- .../classes/sun/font/StandardGlyphVector.java | 14 ++-- .../font/GlyphVector/GlyphMetricsTest.java | 72 +++++++++++++++++++ 2 files changed, 80 insertions(+), 6 deletions(-) create mode 100644 test/jdk/java/awt/font/GlyphVector/GlyphMetricsTest.java diff --git a/src/java.desktop/share/classes/sun/font/StandardGlyphVector.java b/src/java.desktop/share/classes/sun/font/StandardGlyphVector.java index e333a9de291..d44bd9a00e5 100644 --- a/src/java.desktop/share/classes/sun/font/StandardGlyphVector.java +++ b/src/java.desktop/share/classes/sun/font/StandardGlyphVector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, 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 @@ -608,11 +608,13 @@ public class StandardGlyphVector extends GlyphVector { } Rectangle2D vb = getGlyphVisualBounds(ix).getBounds2D(); - Point2D pt = getGlyphPosition(ix); - vb.setRect(vb.getMinX() - pt.getX(), - vb.getMinY() - pt.getY(), - vb.getWidth(), - vb.getHeight()); + if (!vb.isEmpty()) { + Point2D pt = getGlyphPosition(ix); + vb.setRect(vb.getMinX() - pt.getX(), + vb.getMinY() - pt.getY(), + vb.getWidth(), + vb.getHeight()); + } Point2D.Float adv = getGlyphStrike(ix).strike.getGlyphMetrics(glyphs[ix]); GlyphMetrics gm = new GlyphMetrics(true, adv.x, adv.y, diff --git a/test/jdk/java/awt/font/GlyphVector/GlyphMetricsTest.java b/test/jdk/java/awt/font/GlyphVector/GlyphMetricsTest.java new file mode 100644 index 00000000000..415b840671c --- /dev/null +++ b/test/jdk/java/awt/font/GlyphVector/GlyphMetricsTest.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2025, 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 8167268 + * @summary Checks behavior of GlyphVector.getGlyphMetrics(int). + */ + +import java.awt.Font; +import java.awt.Rectangle; +import java.awt.font.FontRenderContext; +import java.awt.font.GlyphMetrics; +import java.awt.font.GlyphVector; +import java.awt.font.TextLayout; +import java.awt.geom.Rectangle2D; + +public class GlyphMetricsTest { + + public static void main(String[] args) { + + String text = "The quick brown \r\n fox JUMPS over \t the lazy dog."; + Font font = new Font(Font.DIALOG, Font.PLAIN, 60); + FontRenderContext frc = new FontRenderContext(null, true, true); + GlyphVector gv = font.createGlyphVector(frc, text); + + for (int i = 0; i < gv.getNumGlyphs(); i++) { + + GlyphMetrics gm = gv.getGlyphMetrics(i); + Rectangle2D bounds = gm.getBounds2D(); + assertEqual(gm.getAdvance(), gm.getAdvanceX(), 0, "advance x", i); + assertEqual(0, gm.getAdvanceY(), 0, "advance y", i); + + // assumes one glyph per char in the test text + String character = text.substring(i, i + 1); + TextLayout layout = new TextLayout(character, font, frc); + Rectangle pixelBounds = layout.getPixelBounds(frc, 0, 0); + assertEqual(pixelBounds.getWidth(), bounds.getWidth(), 2, "width", i); + assertEqual(pixelBounds.getHeight(), bounds.getHeight(), 2, "height", i); + assertEqual(pixelBounds.getX(), bounds.getX(), 2, "x", i); + assertEqual(pixelBounds.getY(), bounds.getY(), 2, "y", i); + } + } + + private static void assertEqual(double d1, double d2, double variance, + String scenario, int index) { + if (Math.abs(d1 - d2) > variance) { + String msg = String.format("%s for index %d: %f != %f", scenario, index, d1, d2); + throw new RuntimeException(msg); + } + } +} From b0bd0c398ee0e0fd625eba1e7d9802a4e420a2c5 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Thu, 11 Dec 2025 14:13:32 +0000 Subject: [PATCH 256/706] 8372759: Test build/AbsPathsInImage.java fails after JDK-8370438 Reviewed-by: erikj --- make/autoconf/flags-ldflags.m4 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/make/autoconf/flags-ldflags.m4 b/make/autoconf/flags-ldflags.m4 index b0dc565b39f..466ff1beaf4 100644 --- a/make/autoconf/flags-ldflags.m4 +++ b/make/autoconf/flags-ldflags.m4 @@ -63,7 +63,7 @@ AC_DEFUN([FLAGS_SETUP_LDFLAGS_HELPER], fi BASIC_LDFLAGS_JVM_ONLY="" - LDFLAGS_LTO="-flto=auto -fuse-linker-plugin -fno-strict-aliasing" + LDFLAGS_LTO="-flto=auto -fuse-linker-plugin -fno-strict-aliasing $DEBUG_PREFIX_CFLAGS" LDFLAGS_CXX_PARTIAL_LINKING="$MACHINE_FLAG -r" @@ -71,7 +71,7 @@ AC_DEFUN([FLAGS_SETUP_LDFLAGS_HELPER], BASIC_LDFLAGS_JVM_ONLY="-mno-omit-leaf-frame-pointer -mstack-alignment=16 \ -fPIC" - LDFLAGS_LTO="-flto=auto -fuse-linker-plugin -fno-strict-aliasing" + LDFLAGS_LTO="-flto=auto -fuse-linker-plugin -fno-strict-aliasing $DEBUG_PREFIX_CFLAGS" LDFLAGS_CXX_PARTIAL_LINKING="$MACHINE_FLAG -r" if test "x$OPENJDK_TARGET_OS" = xlinux; then From 2a1c676e0a1a357f75ea008e8e12c7ae9340b9b1 Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Thu, 11 Dec 2025 14:33:44 +0000 Subject: [PATCH 257/706] 8373464: Test JdkManagementCheckSince.java fails after JDK-8369736 Reviewed-by: dholmes, shade, kevinw --- .../share/classes/jdk/management/HotSpotAOTCacheMXBean.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/jdk.management/share/classes/jdk/management/HotSpotAOTCacheMXBean.java b/src/jdk.management/share/classes/jdk/management/HotSpotAOTCacheMXBean.java index 2dc02f2bd73..4a921c348d0 100644 --- a/src/jdk.management/share/classes/jdk/management/HotSpotAOTCacheMXBean.java +++ b/src/jdk.management/share/classes/jdk/management/HotSpotAOTCacheMXBean.java @@ -39,7 +39,7 @@ import javax.management.ObjectName; *

      Direct access to the MXBean interface can be obtained with * {@link ManagementFactory#getPlatformMXBean(Class)}. * - * @since 26 + * @since 27 */ public interface HotSpotAOTCacheMXBean extends PlatformManagedObject { /** @@ -90,4 +90,4 @@ public interface HotSpotAOTCacheMXBean extends PlatformManagedObject { * successfully; {@code false} otherwise. */ public boolean endRecording(); -} \ No newline at end of file +} From 692edc4879489d44a477a03028eb3e7ef9dff388 Mon Sep 17 00:00:00 2001 From: Nizar Benalla Date: Thu, 11 Dec 2025 15:30:21 +0000 Subject: [PATCH 258/706] 8373443: Update --release 26 symbol information for JDK 26 build 27 Reviewed-by: jlahoda, iris, darcy --- .../share/data/symbols/java.base-Q.sym.txt | 44 +++++++++++++ .../share/data/symbols/java.sql-Q.sym.txt | 64 +++++++++++++++++++ .../symbols/jdk.incubator.foreign-Q.sym.txt | 43 +++++++++++++ .../share/data/symbols/jdk.jpackage-Q.sym.txt | 31 +++++++++ src/jdk.compiler/share/data/symbols/symbols | 2 +- 5 files changed, 183 insertions(+), 1 deletion(-) create mode 100644 src/jdk.compiler/share/data/symbols/java.sql-Q.sym.txt create mode 100644 src/jdk.compiler/share/data/symbols/jdk.incubator.foreign-Q.sym.txt create mode 100644 src/jdk.compiler/share/data/symbols/jdk.jpackage-Q.sym.txt diff --git a/src/jdk.compiler/share/data/symbols/java.base-Q.sym.txt b/src/jdk.compiler/share/data/symbols/java.base-Q.sym.txt index fb1ec6ec7bb..29ecd9f0304 100644 --- a/src/jdk.compiler/share/data/symbols/java.base-Q.sym.txt +++ b/src/jdk.compiler/share/data/symbols/java.base-Q.sym.txt @@ -83,6 +83,11 @@ method name close descriptor ()V thrownTypes java/io/IOException flags 1 -class name java/lang/StableValue +class name java/lang/String +field name UNICODE_CASEFOLD_ORDER descriptor Ljava/util/Comparator; flags 19 signature Ljava/util/Comparator; +method name equalsFoldCase descriptor (Ljava/lang/String;)Z flags 1 +method name compareToFoldCase descriptor (Ljava/lang/String;)I flags 1 + class name java/lang/Thread -method name stop descriptor ()V @@ -464,6 +469,16 @@ innerclass innerClass java/lang/Thread$State outerClass java/lang/Thread innerCl innerclass innerClass java/util/concurrent/StructuredTaskScope$Subtask outerClass java/util/concurrent/StructuredTaskScope innerClassName Subtask flags 609 innerclass innerClass java/util/concurrent/StructuredTaskScope$Subtask$State outerClass java/util/concurrent/StructuredTaskScope$Subtask innerClassName State flags 4019 +class name java/util/concurrent/ThreadLocalRandom +method name nextGaussian descriptor ()D flags 1 + +class name java/util/jar/JarFile +header extends java/util/zip/ZipFile flags 21 +innerclass innerClass java/lang/Runtime$Version outerClass java/lang/Runtime innerClassName Version flags 19 +innerclass innerClass java/util/jar/Attributes$Name outerClass java/util/jar/Attributes innerClassName Name flags 9 +innerclass innerClass java/lang/ScopedValue$Carrier outerClass java/lang/ScopedValue innerClassName Carrier flags 19 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 + class name java/util/stream/Collectors header extends java/lang/Object flags 31 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; innerclass innerClass java/util/stream/Collector$Characteristics outerClass java/util/stream/Collector innerClassName Characteristics flags 4019 @@ -486,6 +501,35 @@ method name getKey descriptor (Ljava/security/Key;Ljava/security/Provider;)Ljava method name getKeyPair descriptor ([C)Ljava/security/KeyPair; thrownTypes java/security/NoSuchAlgorithmException,java/security/InvalidKeyException flags 1 classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;PEM_API;) method name getKeyPair descriptor (Ljava/security/Key;Ljava/security/Provider;)Ljava/security/KeyPair; thrownTypes java/security/NoSuchAlgorithmException,java/security/InvalidKeyException flags 1 classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;PEM_API;) +class name javax/crypto/spec/HPKEParameterSpec +header extends java/lang/Object implements java/security/spec/AlgorithmParameterSpec flags 31 +field name KEM_DHKEM_P_256_HKDF_SHA256 descriptor I constantValue 16 flags 19 +field name KEM_DHKEM_P_384_HKDF_SHA384 descriptor I constantValue 17 flags 19 +field name KEM_DHKEM_P_521_HKDF_SHA512 descriptor I constantValue 18 flags 19 +field name KEM_DHKEM_X25519_HKDF_SHA256 descriptor I constantValue 32 flags 19 +field name KEM_DHKEM_X448_HKDF_SHA512 descriptor I constantValue 33 flags 19 +field name KDF_HKDF_SHA256 descriptor I constantValue 1 flags 19 +field name KDF_HKDF_SHA384 descriptor I constantValue 2 flags 19 +field name KDF_HKDF_SHA512 descriptor I constantValue 3 flags 19 +field name AEAD_AES_128_GCM descriptor I constantValue 1 flags 19 +field name AEAD_AES_256_GCM descriptor I constantValue 2 flags 19 +field name AEAD_CHACHA20_POLY1305 descriptor I constantValue 3 flags 19 +field name EXPORT_ONLY descriptor I constantValue 65535 flags 19 +method name of descriptor (III)Ljavax/crypto/spec/HPKEParameterSpec; flags 9 +method name withInfo descriptor ([B)Ljavax/crypto/spec/HPKEParameterSpec; flags 1 +method name withPsk descriptor (Ljavax/crypto/SecretKey;[B)Ljavax/crypto/spec/HPKEParameterSpec; flags 1 +method name withEncapsulation descriptor ([B)Ljavax/crypto/spec/HPKEParameterSpec; flags 1 +method name withAuthKey descriptor (Ljava/security/AsymmetricKey;)Ljavax/crypto/spec/HPKEParameterSpec; flags 1 +method name kem_id descriptor ()I flags 1 +method name kdf_id descriptor ()I flags 1 +method name aead_id descriptor ()I flags 1 +method name info descriptor ()[B flags 1 +method name psk descriptor ()Ljavax/crypto/SecretKey; flags 1 +method name psk_id descriptor ()[B flags 1 +method name authKey descriptor ()Ljava/security/AsymmetricKey; flags 1 +method name encapsulation descriptor ()[B flags 1 +method name toString descriptor ()Ljava/lang/String; flags 1 + class name jdk/internal/classfile/impl/DirectCodeBuilder header extends jdk/internal/classfile/impl/AbstractDirectBuilder implements jdk/internal/classfile/impl/TerminalCodeBuilder flags 31 signature Ljdk/internal/classfile/impl/AbstractDirectBuilder;Ljdk/internal/classfile/impl/TerminalCodeBuilder; innerclass innerClass jdk/internal/classfile/impl/AbstractPseudoInstruction$ExceptionCatchImpl outerClass jdk/internal/classfile/impl/AbstractPseudoInstruction innerClassName ExceptionCatchImpl flags 19 diff --git a/src/jdk.compiler/share/data/symbols/java.sql-Q.sym.txt b/src/jdk.compiler/share/data/symbols/java.sql-Q.sym.txt new file mode 100644 index 00000000000..a8f41a27db0 --- /dev/null +++ b/src/jdk.compiler/share/data/symbols/java.sql-Q.sym.txt @@ -0,0 +1,64 @@ +# +# Copyright (c) 2025, 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. +# +# ########################################################## +# ### THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. ### +# ########################################################## +# +class name java/sql/Array +header extends java/lang/Object implements java/lang/AutoCloseable flags 601 +method name close descriptor ()V thrownTypes java/sql/SQLException flags 1 + +class name java/sql/Blob +header extends java/lang/Object implements java/lang/AutoCloseable flags 601 +method name close descriptor ()V thrownTypes java/sql/SQLException flags 1 + +class name java/sql/Clob +header extends java/lang/Object implements java/lang/AutoCloseable flags 601 +method name close descriptor ()V thrownTypes java/sql/SQLException flags 1 + +class name java/sql/Connection +method name enquoteLiteral descriptor (Ljava/lang/String;)Ljava/lang/String; thrownTypes java/sql/SQLException flags 1 +method name enquoteIdentifier descriptor (Ljava/lang/String;Z)Ljava/lang/String; thrownTypes java/sql/SQLException flags 1 +method name isSimpleIdentifier descriptor (Ljava/lang/String;)Z thrownTypes java/sql/SQLException flags 1 +method name enquoteNCharLiteral descriptor (Ljava/lang/String;)Ljava/lang/String; thrownTypes java/sql/SQLException flags 1 + +class name java/sql/JDBCType +field name DECFLOAT descriptor Ljava/sql/JDBCType; flags 4019 +field name JSON descriptor Ljava/sql/JDBCType; flags 4019 + +class name java/sql/SQLPermission +header extends java/security/BasicPermission flags 31 deprecated true runtimeAnnotations @Ljava/lang/Deprecated;(forRemoval=Ztrue,since="26") + +class name java/sql/SQLXML +header extends java/lang/Object implements java/lang/AutoCloseable flags 601 +method name close descriptor ()V thrownTypes java/sql/SQLException flags 1 + +class name java/sql/Statement +header extends java/lang/Object implements java/sql/Wrapper,java/lang/AutoCloseable flags 601 classAnnotations @Ljdk/Profile+Annotation;(value=I2) + +class name java/sql/Types +field name DECFLOAT descriptor I constantValue 2015 flags 19 +field name JSON descriptor I constantValue 2016 flags 19 + diff --git a/src/jdk.compiler/share/data/symbols/jdk.incubator.foreign-Q.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.incubator.foreign-Q.sym.txt new file mode 100644 index 00000000000..2d774f83cf1 --- /dev/null +++ b/src/jdk.compiler/share/data/symbols/jdk.incubator.foreign-Q.sym.txt @@ -0,0 +1,43 @@ +# +# Copyright (c) 2025, 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. +# +# ########################################################## +# ### THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. ### +# ########################################################## +# +class name jdk/internal/foreign/AbstractMemorySegmentImpl +header extends java/lang/Object implements java/lang/foreign/MemorySegment,java/lang/foreign/SegmentAllocator sealed true permittedSubclasses jdk/internal/foreign/HeapMemorySegmentImpl,jdk/internal/foreign/NativeMemorySegmentImpl flags 421 +innerclass innerClass java/lang/foreign/ValueLayout$OfByte outerClass java/lang/foreign/ValueLayout innerClassName OfByte flags 609 +innerclass innerClass java/lang/foreign/ValueLayout$OfBoolean outerClass java/lang/foreign/ValueLayout innerClassName OfBoolean flags 609 +innerclass innerClass java/lang/foreign/ValueLayout$OfChar outerClass java/lang/foreign/ValueLayout innerClassName OfChar flags 609 +innerclass innerClass java/lang/foreign/ValueLayout$OfShort outerClass java/lang/foreign/ValueLayout innerClassName OfShort flags 609 +innerclass innerClass java/lang/foreign/ValueLayout$OfInt outerClass java/lang/foreign/ValueLayout innerClassName OfInt flags 609 +innerclass innerClass java/lang/foreign/ValueLayout$OfFloat outerClass java/lang/foreign/ValueLayout innerClassName OfFloat flags 609 +innerclass innerClass java/lang/foreign/ValueLayout$OfLong outerClass java/lang/foreign/ValueLayout innerClassName OfLong flags 609 +innerclass innerClass java/lang/foreign/ValueLayout$OfDouble outerClass java/lang/foreign/ValueLayout innerClassName OfDouble flags 609 +innerclass innerClass java/lang/foreign/MemorySegment$Scope outerClass java/lang/foreign/MemorySegment innerClassName Scope flags 609 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 +-method name apply descriptor (Ljava/lang/String;Ljava/util/List;)Ljava/lang/RuntimeException; +-method name apply descriptor (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; + diff --git a/src/jdk.compiler/share/data/symbols/jdk.jpackage-Q.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jpackage-Q.sym.txt new file mode 100644 index 00000000000..27fd9e69203 --- /dev/null +++ b/src/jdk.compiler/share/data/symbols/jdk.jpackage-Q.sym.txt @@ -0,0 +1,31 @@ +# +# Copyright (c) 2025, 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. +# +# ########################################################## +# ### THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. ### +# ########################################################## +# +module name jdk.jpackage +header requires name\u0020;java.base\u0020;flags\u0020;8000,name\u0020;jdk.internal.opt\u0020;flags\u0020;0,name\u0020;jdk.jlink\u0020;flags\u0020;0,name\u0020;java.naming\u0020;flags\u0020;0,name\u0020;java.desktop\u0020;flags\u0020;0 uses jdk/jpackage/internal/cli/CliBundlingEnvironment provides interface\u0020;java/util/spi/ToolProvider\u0020;impls\u0020;jdk/jpackage/internal/cli/Main$Provider,interface\u0020;jdk/jpackage/internal/cli/CliBundlingEnvironment\u0020;impls\u0020;jdk/jpackage/internal/MacBundlingEnvironment target macos-aarch64 moduleMainClass jdk/jpackage/main/Main flags 8000 + diff --git a/src/jdk.compiler/share/data/symbols/symbols b/src/jdk.compiler/share/data/symbols/symbols index 4bc5127310f..8fdcac5c652 100644 --- a/src/jdk.compiler/share/data/symbols/symbols +++ b/src/jdk.compiler/share/data/symbols/symbols @@ -48,4 +48,4 @@ platform version M base L files java.base-M.sym.txt:java.compiler-M.sym.txt:java platform version N base M files java.base-N.sym.txt:java.compiler-N.sym.txt:java.desktop-N.sym.txt:java.management-N.sym.txt:java.management.rmi-N.sym.txt:jdk.compiler-N.sym.txt:jdk.httpserver-N.sym.txt:jdk.incubator.foreign-N.sym.txt:jdk.javadoc-N.sym.txt:jdk.jshell-N.sym.txt:jdk.localedata-N.sym.txt:jdk.unsupported-N.sym.txt platform version O base N files java.base-O.sym.txt:java.compiler-O.sym.txt:java.datatransfer-O.sym.txt:java.desktop-O.sym.txt:java.instrument-O.sym.txt:java.logging-O.sym.txt:java.management-O.sym.txt:java.management.rmi-O.sym.txt:java.naming-O.sym.txt:java.net.http-O.sym.txt:java.prefs-O.sym.txt:java.rmi-O.sym.txt:java.scripting-O.sym.txt:java.se-O.sym.txt:java.security.jgss-O.sym.txt:java.security.sasl-O.sym.txt:java.smartcardio-O.sym.txt:java.sql-O.sym.txt:java.sql.rowset-O.sym.txt:java.transaction.xa-O.sym.txt:java.xml-O.sym.txt:java.xml.crypto-O.sym.txt:jdk.accessibility-O.sym.txt:jdk.attach-O.sym.txt:jdk.charsets-O.sym.txt:jdk.compiler-O.sym.txt:jdk.crypto.cryptoki-O.sym.txt:jdk.dynalink-O.sym.txt:jdk.editpad-O.sym.txt:jdk.hotspot.agent-O.sym.txt:jdk.httpserver-O.sym.txt:jdk.incubator.foreign-O.sym.txt:jdk.incubator.vector-O.sym.txt:jdk.jartool-O.sym.txt:jdk.javadoc-O.sym.txt:jdk.jcmd-O.sym.txt:jdk.jconsole-O.sym.txt:jdk.jdeps-O.sym.txt:jdk.jdi-O.sym.txt:jdk.jdwp.agent-O.sym.txt:jdk.jfr-O.sym.txt:jdk.jlink-O.sym.txt:jdk.jpackage-O.sym.txt:jdk.jshell-O.sym.txt:jdk.jsobject-O.sym.txt:jdk.jstatd-O.sym.txt:jdk.localedata-O.sym.txt:jdk.management-O.sym.txt:jdk.management.agent-O.sym.txt:jdk.management.jfr-O.sym.txt:jdk.naming.dns-O.sym.txt:jdk.naming.rmi-O.sym.txt:jdk.net-O.sym.txt:jdk.nio.mapmode-O.sym.txt:jdk.sctp-O.sym.txt:jdk.security.auth-O.sym.txt:jdk.security.jgss-O.sym.txt:jdk.unsupported-O.sym.txt:jdk.xml.dom-O.sym.txt:jdk.zipfs-O.sym.txt platform version P base O files java.base-P.sym.txt:java.compiler-P.sym.txt:java.desktop-P.sym.txt:java.logging-P.sym.txt:java.management-P.sym.txt:java.net.http-P.sym.txt:java.security.jgss-P.sym.txt:java.xml.crypto-P.sym.txt:jdk.attach-P.sym.txt:jdk.compiler-P.sym.txt:jdk.incubator.foreign-P.sym.txt:jdk.incubator.vector-P.sym.txt:jdk.jdi-P.sym.txt:jdk.jfr-P.sym.txt:jdk.jpackage-P.sym.txt:jdk.jshell-P.sym.txt:jdk.net-P.sym.txt:jdk.security.jgss-P.sym.txt -platform version Q base P files java.base-Q.sym.txt:java.compiler-Q.sym.txt:java.desktop-Q.sym.txt:java.management-Q.sym.txt:java.net.http-Q.sym.txt:jdk.httpserver-Q.sym.txt:jdk.incubator.vector-Q.sym.txt:jdk.jartool-Q.sym.txt:jdk.jdeps-Q.sym.txt:jdk.jfr-Q.sym.txt:jdk.jlink-Q.sym.txt:jdk.jshell-Q.sym.txt:jdk.jsobject-Q.sym.txt:jdk.localedata-Q.sym.txt +platform version Q base P files java.base-Q.sym.txt:java.compiler-Q.sym.txt:java.desktop-Q.sym.txt:java.management-Q.sym.txt:java.net.http-Q.sym.txt:java.sql-Q.sym.txt:jdk.httpserver-Q.sym.txt:jdk.incubator.foreign-Q.sym.txt:jdk.incubator.vector-Q.sym.txt:jdk.jartool-Q.sym.txt:jdk.jdeps-Q.sym.txt:jdk.jfr-Q.sym.txt:jdk.jlink-Q.sym.txt:jdk.jpackage-Q.sym.txt:jdk.jshell-Q.sym.txt:jdk.jsobject-Q.sym.txt:jdk.localedata-Q.sym.txt From 431dcf84e9754c743105380ca69af647b57193bc Mon Sep 17 00:00:00 2001 From: Daniel Gredler Date: Thu, 11 Dec 2025 20:15:45 +0000 Subject: [PATCH 259/706] 8368702: [macosx] Printing text with composite fonts loses font transform Reviewed-by: psadhukhan, prr --- .../macosx/classes/sun/lwawt/macosx/CTextPipe.java | 12 +++++++++--- .../jdk/java/awt/print/PrinterJob/PrintTextTest.java | 2 +- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CTextPipe.java b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CTextPipe.java index 6fdda409ce5..cf4a6e72136 100644 --- a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CTextPipe.java +++ b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CTextPipe.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2025, 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 @@ -97,8 +97,14 @@ public class CTextPipe implements TextPipe { if (f2d instanceof CFont) { CompositeFont cf = ((CFont)f2d).getCompositeFont2D(); PhysicalFont pf = cf.getSlotFont(slot); - Font f = new Font(pf.getFontName(null), - font.getStyle(), font.getSize()); + String name = pf.getFontName(null); + Font f = new Font(name, font.getStyle(), font.getSize()); + if (font.isTransformed()) { + f = f.deriveFont(font.getTransform()); + } + if (font.hasLayoutAttributes()) { + f = f.deriveFont(font.getAttributes()); + } return f; } return null; diff --git a/test/jdk/java/awt/print/PrinterJob/PrintTextTest.java b/test/jdk/java/awt/print/PrinterJob/PrintTextTest.java index 06e71c4067f..defca807fc0 100644 --- a/test/jdk/java/awt/print/PrinterJob/PrintTextTest.java +++ b/test/jdk/java/awt/print/PrinterJob/PrintTextTest.java @@ -23,7 +23,7 @@ /* * @test - * @bug 6425068 7156751 7157659 8029204 8132890 8148334 8344637 + * @bug 6425068 7156751 7157659 8029204 8132890 8148334 8344637 8368702 * @key printer * @summary Confirm that text prints where we expect to the length we expect. * @library /java/awt/regtesthelpers From 66d7b0ce8f8414c3d5fd3476b65152b9f2a9a587 Mon Sep 17 00:00:00 2001 From: Sergey Bylokhov Date: Thu, 11 Dec 2025 20:32:58 +0000 Subject: [PATCH 260/706] 8371657: [macosx] Programmatically selecting/deselecting List item triggers an ItemEvent Reviewed-by: aivanov, azvegint, dnguyen, tr --- .../macosx/classes/sun/lwawt/LWListPeer.java | 51 +++-- test/jdk/ProblemList.txt | 1 + .../awt/List/NoEvents/ProgrammaticChange.java | 176 ++++++++++++++++++ 3 files changed, 215 insertions(+), 13 deletions(-) create mode 100644 test/jdk/java/awt/List/NoEvents/ProgrammaticChange.java diff --git a/src/java.desktop/macosx/classes/sun/lwawt/LWListPeer.java b/src/java.desktop/macosx/classes/sun/lwawt/LWListPeer.java index 905a66b3212..84258b454a2 100644 --- a/src/java.desktop/macosx/classes/sun/lwawt/LWListPeer.java +++ b/src/java.desktop/macosx/classes/sun/lwawt/LWListPeer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2025, 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,8 +86,11 @@ final class LWListPeer extends LWComponentPeer final int[] selectedIndices = getTarget().getSelectedIndexes(); synchronized (getDelegateLock()) { getDelegate().setSkipStateChangedEvent(true); - getDelegate().getView().setSelectedIndices(selectedIndices); - getDelegate().setSkipStateChangedEvent(false); + try { + getDelegate().getView().setSelectedIndices(selectedIndices); + } finally { + getDelegate().setSkipStateChangedEvent(false); + } } } @@ -111,24 +114,39 @@ final class LWListPeer extends LWComponentPeer @Override public void add(final String item, final int index) { synchronized (getDelegateLock()) { - getDelegate().getModel().add(index, item); - revalidate(); + getDelegate().setSkipStateChangedEvent(true); + try { + getDelegate().getModel().add(index, item); + revalidate(); + } finally { + getDelegate().setSkipStateChangedEvent(false); + } } } @Override public void delItems(final int start, final int end) { synchronized (getDelegateLock()) { - getDelegate().getModel().removeRange(start, end); - revalidate(); + getDelegate().setSkipStateChangedEvent(true); + try { + getDelegate().getModel().removeRange(start, end); + revalidate(); + } finally { + getDelegate().setSkipStateChangedEvent(false); + } } } @Override public void removeAll() { synchronized (getDelegateLock()) { - getDelegate().getModel().removeAllElements(); - revalidate(); + getDelegate().setSkipStateChangedEvent(true); + try { + getDelegate().getModel().removeAllElements(); + revalidate(); + } finally { + getDelegate().setSkipStateChangedEvent(false); + } } } @@ -136,16 +154,23 @@ final class LWListPeer extends LWComponentPeer public void select(final int index) { synchronized (getDelegateLock()) { getDelegate().setSkipStateChangedEvent(true); - getDelegate().getView().setSelectedIndex(index); - getDelegate().setSkipStateChangedEvent(false); + try { + getDelegate().getView().setSelectedIndex(index); + } finally { + getDelegate().setSkipStateChangedEvent(false); + } } } @Override public void deselect(final int index) { synchronized (getDelegateLock()) { - getDelegate().getView().getSelectionModel(). - removeSelectionInterval(index, index); + getDelegate().setSkipStateChangedEvent(true); + try { + getDelegate().getView().removeSelectionInterval(index, index); + } finally { + getDelegate().setSkipStateChangedEvent(false); + } } } diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 0076b1cf891..757d9c0ba63 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -150,6 +150,7 @@ java/awt/EventQueue/PushPopDeadlock/PushPopDeadlock.java 8024034 generic-all java/awt/grab/EmbeddedFrameTest1/EmbeddedFrameTest1.java 7080150 macosx-all java/awt/event/InputEvent/EventWhenTest/EventWhenTest.java 8168646 generic-all java/awt/List/KeyEventsTest/KeyEventsTest.java 8201307 linux-all +java/awt/List/NoEvents/ProgrammaticChange.java 8201307 linux-all java/awt/Paint/ListRepaint.java 8201307 linux-all java/awt/Mixing/AWT_Mixing/HierarchyBoundsListenerMixingTest.java 8049405 macosx-all java/awt/Mixing/AWT_Mixing/OpaqueOverlapping.java 8370584 windows-x64 diff --git a/test/jdk/java/awt/List/NoEvents/ProgrammaticChange.java b/test/jdk/java/awt/List/NoEvents/ProgrammaticChange.java new file mode 100644 index 00000000000..07b4bd2ac70 --- /dev/null +++ b/test/jdk/java/awt/List/NoEvents/ProgrammaticChange.java @@ -0,0 +1,176 @@ +/* + * Copyright Amazon.com Inc. 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.List; +import java.awt.Robot; +import java.util.Arrays; +import java.util.function.Supplier; + +/** + * @test + * @bug 8371657 + * @key headful + * @summary Checks that programmatic changes to a List do not fire events + */ +public final class ProgrammaticChange { + + private static Robot robot; + private static volatile boolean itemEvent; + private static volatile boolean actionEvent; + + public static void main(String[] args) throws Exception { + robot = new Robot(); + robot.mouseMove(0, 0); // Just in case, the mouse may affect selection + + var creators = Arrays.>asList( + List::new, () -> createList(false), () -> createList(true) + ); + for (Supplier creator : creators) { + test(creator, true); // Test displayable list + test(creator, false); // Test non-displayable list + } + } + + private static void test(Supplier creator, boolean displayable) { + List list = creator.get(); + list.addItemListener(event -> { + System.err.println("event = " + event); + itemEvent = true; + }); + list.addActionListener(event -> { + System.err.println("event = " + event); + actionEvent = true; + }); + + Frame frame = null; + try { + if (displayable) { + frame = new Frame(); + frame.setSize(300, 200); + frame.setLocationRelativeTo(null); + frame.add(list); + frame.setVisible(true); + } + tryTriggerEvents(list); + } finally { + if (frame != null) { + frame.dispose(); + } + } + } + + private static void tryTriggerEvents(List list) { + // Only "select" and "deselect" should not fire events per the spec, + // but we also check other methods to prevent accidental changes + selectAll(list); + verify(); + deselectAll(list); + verify(); + + // "add" may change the current selection + selectAll(list); + list.add("newItemStart", 0); + list.add("newItemMid", 1); + list.add("newItemEnd"); + verify(); + + // "remove" may change the current selection + selectAll(list); + list.remove(0); + verify(); + + // "makeVisible" may change the current selection + for (int i = 0; i < 100; i++){ + list.add("newItem_" + i, 0); + } + selectAll(list); + list.makeVisible(1); + list.makeVisible(99); + verify(); + + // "setMultipleMode" may change the current selection + selectAll(list); + list.setMultipleMode(!list.isMultipleMode()); + selectAll(list); + list.setMultipleSelections(!list.allowsMultipleSelections()); + verify(); + + // "removeAll" may change the current selection + selectAll(list); + list.removeAll(); + verify(); + + // No extra logic; just calling methods to touch all code paths + list.add("newItem1"); + list.getSelectedIndex(); + list.getSelectedIndexes(); + list.getSelectedItem(); + list.getSelectedItems(); + list.getSelectedObjects(); + list.getVisibleIndex(); + list.isIndexSelected(0); + list.isSelected(0); + + list.add("newItem2"); + list.delItems(0, 0); + list.addItem("newItem4"); + list.delItem(0); + list.addItem("newItem6", 0); + list.replaceItem("newItem7", 0); + list.remove("newItem7"); + list.add("newItem8"); + list.clear(); + verify(); + } + + private static void selectAll(List list) { + for (int index = 0; index < list.getItemCount(); index++) { + list.select(index); + } + } + + private static void deselectAll(List list) { + for (int index = 0; index < list.countItems(); index++) { + list.deselect(index); + } + } + + private static List createList(boolean multipleMode) { + List list = new List(4, multipleMode); + for (String item : new String[]{"item1", "item2", "item3"}) { + list.add(item); + } + return list; + } + + private static void verify() { + robot.waitForIdle(); + robot.delay(700); // Large delay, we are waiting for unexpected events + if (actionEvent || itemEvent) { + System.err.println("itemEvent: " + itemEvent); + System.err.println("actionEvent: " + actionEvent); + throw new RuntimeException("Unexpected event"); + } + } +} From ae85d899d074c531371dece30319ace701517528 Mon Sep 17 00:00:00 2001 From: Xueming Shen Date: Thu, 11 Dec 2025 20:47:32 +0000 Subject: [PATCH 261/706] 8373389: Two jdk/incubator/vector/ tests fails after JDK-8371446 Reviewed-by: psandoz --- test/jdk/jdk/incubator/vector/AbstractVectorTest.java | 5 +---- test/jdk/jdk/incubator/vector/Byte128VectorTests.java | 10 ++++++++-- test/jdk/jdk/incubator/vector/Byte256VectorTests.java | 10 ++++++++-- test/jdk/jdk/incubator/vector/Byte512VectorTests.java | 10 ++++++++-- test/jdk/jdk/incubator/vector/Byte64VectorTests.java | 10 ++++++++-- test/jdk/jdk/incubator/vector/ByteMaxVectorTests.java | 10 ++++++++-- .../jdk/jdk/incubator/vector/Double128VectorTests.java | 6 ++++++ .../jdk/jdk/incubator/vector/Double256VectorTests.java | 6 ++++++ .../jdk/jdk/incubator/vector/Double512VectorTests.java | 6 ++++++ test/jdk/jdk/incubator/vector/Double64VectorTests.java | 6 ++++++ .../jdk/jdk/incubator/vector/DoubleMaxVectorTests.java | 6 ++++++ test/jdk/jdk/incubator/vector/Float128VectorTests.java | 6 ++++++ test/jdk/jdk/incubator/vector/Float256VectorTests.java | 6 ++++++ test/jdk/jdk/incubator/vector/Float512VectorTests.java | 6 ++++++ test/jdk/jdk/incubator/vector/Float64VectorTests.java | 6 ++++++ test/jdk/jdk/incubator/vector/FloatMaxVectorTests.java | 6 ++++++ test/jdk/jdk/incubator/vector/Int128VectorTests.java | 10 ++++++++-- test/jdk/jdk/incubator/vector/Int256VectorTests.java | 10 ++++++++-- test/jdk/jdk/incubator/vector/Int512VectorTests.java | 10 ++++++++-- test/jdk/jdk/incubator/vector/Int64VectorTests.java | 10 ++++++++-- test/jdk/jdk/incubator/vector/IntMaxVectorTests.java | 10 ++++++++-- test/jdk/jdk/incubator/vector/Long128VectorTests.java | 10 ++++++++-- test/jdk/jdk/incubator/vector/Long256VectorTests.java | 10 ++++++++-- test/jdk/jdk/incubator/vector/Long512VectorTests.java | 10 ++++++++-- test/jdk/jdk/incubator/vector/Long64VectorTests.java | 10 ++++++++-- test/jdk/jdk/incubator/vector/LongMaxVectorTests.java | 10 ++++++++-- test/jdk/jdk/incubator/vector/Short128VectorTests.java | 10 ++++++++-- test/jdk/jdk/incubator/vector/Short256VectorTests.java | 10 ++++++++-- test/jdk/jdk/incubator/vector/Short512VectorTests.java | 10 ++++++++-- test/jdk/jdk/incubator/vector/Short64VectorTests.java | 10 ++++++++-- test/jdk/jdk/incubator/vector/ShortMaxVectorTests.java | 10 ++++++++-- 31 files changed, 221 insertions(+), 44 deletions(-) diff --git a/test/jdk/jdk/incubator/vector/AbstractVectorTest.java b/test/jdk/jdk/incubator/vector/AbstractVectorTest.java index b334e64ab80..99824d6e693 100644 --- a/test/jdk/jdk/incubator/vector/AbstractVectorTest.java +++ b/test/jdk/jdk/incubator/vector/AbstractVectorTest.java @@ -119,10 +119,7 @@ public class AbstractVectorTest { Arrays.fill(a, true); return a; }), - withToString("mask[false]", boolean[]::new), - withToString("mask[random]", (int s) -> { - return fill_boolean(s,_i -> RAND.nextBoolean()); - }) + withToString("mask[false]", boolean[]::new) ); static final List>> diff --git a/test/jdk/jdk/incubator/vector/Byte128VectorTests.java b/test/jdk/jdk/incubator/vector/Byte128VectorTests.java index 4980c66c02a..c33678bee1f 100644 --- a/test/jdk/jdk/incubator/vector/Byte128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Byte128VectorTests.java @@ -1125,6 +1125,12 @@ public class Byte128VectorTests extends AbstractVectorTest { .flatMap(pair -> BYTE_SATURATING_GENERATORS_ASSOC.stream().map(f -> List.of(pair.get(0), pair.get(1), f))) .collect(Collectors.toList()); + @DataProvider + public Object[][] boolUnaryOpProvider() { + return BOOL_ARRAY_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } static final List>> BYTE_GENERATOR_TRIPLES = BYTE_GENERATOR_PAIRS.stream(). @@ -4503,7 +4509,7 @@ public class Byte128VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolMaskUnaryOpProvider") + @Test(dataProvider = "boolUnaryOpProvider") static void anyTrueByte128VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -4527,7 +4533,7 @@ public class Byte128VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolMaskUnaryOpProvider") + @Test(dataProvider = "boolUnaryOpProvider") static void allTrueByte128VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); diff --git a/test/jdk/jdk/incubator/vector/Byte256VectorTests.java b/test/jdk/jdk/incubator/vector/Byte256VectorTests.java index b3cad54e101..837febfe0ed 100644 --- a/test/jdk/jdk/incubator/vector/Byte256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Byte256VectorTests.java @@ -1125,6 +1125,12 @@ public class Byte256VectorTests extends AbstractVectorTest { .flatMap(pair -> BYTE_SATURATING_GENERATORS_ASSOC.stream().map(f -> List.of(pair.get(0), pair.get(1), f))) .collect(Collectors.toList()); + @DataProvider + public Object[][] boolUnaryOpProvider() { + return BOOL_ARRAY_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } static final List>> BYTE_GENERATOR_TRIPLES = BYTE_GENERATOR_PAIRS.stream(). @@ -4503,7 +4509,7 @@ public class Byte256VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolMaskUnaryOpProvider") + @Test(dataProvider = "boolUnaryOpProvider") static void anyTrueByte256VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -4527,7 +4533,7 @@ public class Byte256VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolMaskUnaryOpProvider") + @Test(dataProvider = "boolUnaryOpProvider") static void allTrueByte256VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); diff --git a/test/jdk/jdk/incubator/vector/Byte512VectorTests.java b/test/jdk/jdk/incubator/vector/Byte512VectorTests.java index 83e48cd2fdc..1dd979f44bf 100644 --- a/test/jdk/jdk/incubator/vector/Byte512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Byte512VectorTests.java @@ -1125,6 +1125,12 @@ public class Byte512VectorTests extends AbstractVectorTest { .flatMap(pair -> BYTE_SATURATING_GENERATORS_ASSOC.stream().map(f -> List.of(pair.get(0), pair.get(1), f))) .collect(Collectors.toList()); + @DataProvider + public Object[][] boolUnaryOpProvider() { + return BOOL_ARRAY_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } static final List>> BYTE_GENERATOR_TRIPLES = BYTE_GENERATOR_PAIRS.stream(). @@ -4503,7 +4509,7 @@ public class Byte512VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolMaskUnaryOpProvider") + @Test(dataProvider = "boolUnaryOpProvider") static void anyTrueByte512VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -4527,7 +4533,7 @@ public class Byte512VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolMaskUnaryOpProvider") + @Test(dataProvider = "boolUnaryOpProvider") static void allTrueByte512VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); diff --git a/test/jdk/jdk/incubator/vector/Byte64VectorTests.java b/test/jdk/jdk/incubator/vector/Byte64VectorTests.java index 0088b3fbf8e..43d180db0a5 100644 --- a/test/jdk/jdk/incubator/vector/Byte64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Byte64VectorTests.java @@ -1125,6 +1125,12 @@ public class Byte64VectorTests extends AbstractVectorTest { .flatMap(pair -> BYTE_SATURATING_GENERATORS_ASSOC.stream().map(f -> List.of(pair.get(0), pair.get(1), f))) .collect(Collectors.toList()); + @DataProvider + public Object[][] boolUnaryOpProvider() { + return BOOL_ARRAY_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } static final List>> BYTE_GENERATOR_TRIPLES = BYTE_GENERATOR_PAIRS.stream(). @@ -4503,7 +4509,7 @@ public class Byte64VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolMaskUnaryOpProvider") + @Test(dataProvider = "boolUnaryOpProvider") static void anyTrueByte64VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -4527,7 +4533,7 @@ public class Byte64VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolMaskUnaryOpProvider") + @Test(dataProvider = "boolUnaryOpProvider") static void allTrueByte64VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); diff --git a/test/jdk/jdk/incubator/vector/ByteMaxVectorTests.java b/test/jdk/jdk/incubator/vector/ByteMaxVectorTests.java index 6df01fb48e3..cb7b00d8ebf 100644 --- a/test/jdk/jdk/incubator/vector/ByteMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/ByteMaxVectorTests.java @@ -1130,6 +1130,12 @@ public class ByteMaxVectorTests extends AbstractVectorTest { .flatMap(pair -> BYTE_SATURATING_GENERATORS_ASSOC.stream().map(f -> List.of(pair.get(0), pair.get(1), f))) .collect(Collectors.toList()); + @DataProvider + public Object[][] boolUnaryOpProvider() { + return BOOL_ARRAY_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } static final List>> BYTE_GENERATOR_TRIPLES = BYTE_GENERATOR_PAIRS.stream(). @@ -4508,7 +4514,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolMaskUnaryOpProvider") + @Test(dataProvider = "boolUnaryOpProvider") static void anyTrueByteMaxVectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -4532,7 +4538,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolMaskUnaryOpProvider") + @Test(dataProvider = "boolUnaryOpProvider") static void allTrueByteMaxVectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); diff --git a/test/jdk/jdk/incubator/vector/Double128VectorTests.java b/test/jdk/jdk/incubator/vector/Double128VectorTests.java index 879dac4c966..716d7b1f1f7 100644 --- a/test/jdk/jdk/incubator/vector/Double128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Double128VectorTests.java @@ -1217,6 +1217,12 @@ relativeError)); flatMap(fa -> DOUBLE_GENERATORS.stream().skip(1).map(fb -> List.of(fa, fb))). collect(Collectors.toList()); + @DataProvider + public Object[][] boolUnaryOpProvider() { + return BOOL_ARRAY_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } static final List>> DOUBLE_GENERATOR_TRIPLES = DOUBLE_GENERATOR_PAIRS.stream(). diff --git a/test/jdk/jdk/incubator/vector/Double256VectorTests.java b/test/jdk/jdk/incubator/vector/Double256VectorTests.java index 87230330642..298d5591b1c 100644 --- a/test/jdk/jdk/incubator/vector/Double256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Double256VectorTests.java @@ -1217,6 +1217,12 @@ relativeError)); flatMap(fa -> DOUBLE_GENERATORS.stream().skip(1).map(fb -> List.of(fa, fb))). collect(Collectors.toList()); + @DataProvider + public Object[][] boolUnaryOpProvider() { + return BOOL_ARRAY_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } static final List>> DOUBLE_GENERATOR_TRIPLES = DOUBLE_GENERATOR_PAIRS.stream(). diff --git a/test/jdk/jdk/incubator/vector/Double512VectorTests.java b/test/jdk/jdk/incubator/vector/Double512VectorTests.java index af8fbf5f51f..34723b27ec9 100644 --- a/test/jdk/jdk/incubator/vector/Double512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Double512VectorTests.java @@ -1217,6 +1217,12 @@ relativeError)); flatMap(fa -> DOUBLE_GENERATORS.stream().skip(1).map(fb -> List.of(fa, fb))). collect(Collectors.toList()); + @DataProvider + public Object[][] boolUnaryOpProvider() { + return BOOL_ARRAY_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } static final List>> DOUBLE_GENERATOR_TRIPLES = DOUBLE_GENERATOR_PAIRS.stream(). diff --git a/test/jdk/jdk/incubator/vector/Double64VectorTests.java b/test/jdk/jdk/incubator/vector/Double64VectorTests.java index 67822ae5353..f8ccd2ea8b4 100644 --- a/test/jdk/jdk/incubator/vector/Double64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Double64VectorTests.java @@ -1217,6 +1217,12 @@ relativeError)); flatMap(fa -> DOUBLE_GENERATORS.stream().skip(1).map(fb -> List.of(fa, fb))). collect(Collectors.toList()); + @DataProvider + public Object[][] boolUnaryOpProvider() { + return BOOL_ARRAY_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } static final List>> DOUBLE_GENERATOR_TRIPLES = DOUBLE_GENERATOR_PAIRS.stream(). diff --git a/test/jdk/jdk/incubator/vector/DoubleMaxVectorTests.java b/test/jdk/jdk/incubator/vector/DoubleMaxVectorTests.java index 5d7ae07c55a..1992f80eb2d 100644 --- a/test/jdk/jdk/incubator/vector/DoubleMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/DoubleMaxVectorTests.java @@ -1222,6 +1222,12 @@ relativeError)); flatMap(fa -> DOUBLE_GENERATORS.stream().skip(1).map(fb -> List.of(fa, fb))). collect(Collectors.toList()); + @DataProvider + public Object[][] boolUnaryOpProvider() { + return BOOL_ARRAY_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } static final List>> DOUBLE_GENERATOR_TRIPLES = DOUBLE_GENERATOR_PAIRS.stream(). diff --git a/test/jdk/jdk/incubator/vector/Float128VectorTests.java b/test/jdk/jdk/incubator/vector/Float128VectorTests.java index 0d3ce311a90..d605fa7c61f 100644 --- a/test/jdk/jdk/incubator/vector/Float128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Float128VectorTests.java @@ -1228,6 +1228,12 @@ relativeError)); flatMap(fa -> FLOAT_GENERATORS.stream().skip(1).map(fb -> List.of(fa, fb))). collect(Collectors.toList()); + @DataProvider + public Object[][] boolUnaryOpProvider() { + return BOOL_ARRAY_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } static final List>> FLOAT_GENERATOR_TRIPLES = FLOAT_GENERATOR_PAIRS.stream(). diff --git a/test/jdk/jdk/incubator/vector/Float256VectorTests.java b/test/jdk/jdk/incubator/vector/Float256VectorTests.java index 88ea856f17b..f72e81cd030 100644 --- a/test/jdk/jdk/incubator/vector/Float256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Float256VectorTests.java @@ -1228,6 +1228,12 @@ relativeError)); flatMap(fa -> FLOAT_GENERATORS.stream().skip(1).map(fb -> List.of(fa, fb))). collect(Collectors.toList()); + @DataProvider + public Object[][] boolUnaryOpProvider() { + return BOOL_ARRAY_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } static final List>> FLOAT_GENERATOR_TRIPLES = FLOAT_GENERATOR_PAIRS.stream(). diff --git a/test/jdk/jdk/incubator/vector/Float512VectorTests.java b/test/jdk/jdk/incubator/vector/Float512VectorTests.java index cdccbfdd319..68e182a602a 100644 --- a/test/jdk/jdk/incubator/vector/Float512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Float512VectorTests.java @@ -1228,6 +1228,12 @@ relativeError)); flatMap(fa -> FLOAT_GENERATORS.stream().skip(1).map(fb -> List.of(fa, fb))). collect(Collectors.toList()); + @DataProvider + public Object[][] boolUnaryOpProvider() { + return BOOL_ARRAY_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } static final List>> FLOAT_GENERATOR_TRIPLES = FLOAT_GENERATOR_PAIRS.stream(). diff --git a/test/jdk/jdk/incubator/vector/Float64VectorTests.java b/test/jdk/jdk/incubator/vector/Float64VectorTests.java index 056eae1974f..c5bc801bc03 100644 --- a/test/jdk/jdk/incubator/vector/Float64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Float64VectorTests.java @@ -1228,6 +1228,12 @@ relativeError)); flatMap(fa -> FLOAT_GENERATORS.stream().skip(1).map(fb -> List.of(fa, fb))). collect(Collectors.toList()); + @DataProvider + public Object[][] boolUnaryOpProvider() { + return BOOL_ARRAY_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } static final List>> FLOAT_GENERATOR_TRIPLES = FLOAT_GENERATOR_PAIRS.stream(). diff --git a/test/jdk/jdk/incubator/vector/FloatMaxVectorTests.java b/test/jdk/jdk/incubator/vector/FloatMaxVectorTests.java index 19bd385ca1f..5fccb85dc40 100644 --- a/test/jdk/jdk/incubator/vector/FloatMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/FloatMaxVectorTests.java @@ -1233,6 +1233,12 @@ relativeError)); flatMap(fa -> FLOAT_GENERATORS.stream().skip(1).map(fb -> List.of(fa, fb))). collect(Collectors.toList()); + @DataProvider + public Object[][] boolUnaryOpProvider() { + return BOOL_ARRAY_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } static final List>> FLOAT_GENERATOR_TRIPLES = FLOAT_GENERATOR_PAIRS.stream(). diff --git a/test/jdk/jdk/incubator/vector/Int128VectorTests.java b/test/jdk/jdk/incubator/vector/Int128VectorTests.java index 1bf3203790c..c0834d7710f 100644 --- a/test/jdk/jdk/incubator/vector/Int128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Int128VectorTests.java @@ -1115,6 +1115,12 @@ public class Int128VectorTests extends AbstractVectorTest { .flatMap(pair -> INT_SATURATING_GENERATORS_ASSOC.stream().map(f -> List.of(pair.get(0), pair.get(1), f))) .collect(Collectors.toList()); + @DataProvider + public Object[][] boolUnaryOpProvider() { + return BOOL_ARRAY_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } static final List>> INT_GENERATOR_TRIPLES = INT_GENERATOR_PAIRS.stream(). @@ -4547,7 +4553,7 @@ public class Int128VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolMaskUnaryOpProvider") + @Test(dataProvider = "boolUnaryOpProvider") static void anyTrueInt128VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -4571,7 +4577,7 @@ public class Int128VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolMaskUnaryOpProvider") + @Test(dataProvider = "boolUnaryOpProvider") static void allTrueInt128VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); diff --git a/test/jdk/jdk/incubator/vector/Int256VectorTests.java b/test/jdk/jdk/incubator/vector/Int256VectorTests.java index 5973fec7e57..cb8d306156a 100644 --- a/test/jdk/jdk/incubator/vector/Int256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Int256VectorTests.java @@ -1115,6 +1115,12 @@ public class Int256VectorTests extends AbstractVectorTest { .flatMap(pair -> INT_SATURATING_GENERATORS_ASSOC.stream().map(f -> List.of(pair.get(0), pair.get(1), f))) .collect(Collectors.toList()); + @DataProvider + public Object[][] boolUnaryOpProvider() { + return BOOL_ARRAY_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } static final List>> INT_GENERATOR_TRIPLES = INT_GENERATOR_PAIRS.stream(). @@ -4547,7 +4553,7 @@ public class Int256VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolMaskUnaryOpProvider") + @Test(dataProvider = "boolUnaryOpProvider") static void anyTrueInt256VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -4571,7 +4577,7 @@ public class Int256VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolMaskUnaryOpProvider") + @Test(dataProvider = "boolUnaryOpProvider") static void allTrueInt256VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); diff --git a/test/jdk/jdk/incubator/vector/Int512VectorTests.java b/test/jdk/jdk/incubator/vector/Int512VectorTests.java index a1e969fc852..d35d680c0c8 100644 --- a/test/jdk/jdk/incubator/vector/Int512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Int512VectorTests.java @@ -1115,6 +1115,12 @@ public class Int512VectorTests extends AbstractVectorTest { .flatMap(pair -> INT_SATURATING_GENERATORS_ASSOC.stream().map(f -> List.of(pair.get(0), pair.get(1), f))) .collect(Collectors.toList()); + @DataProvider + public Object[][] boolUnaryOpProvider() { + return BOOL_ARRAY_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } static final List>> INT_GENERATOR_TRIPLES = INT_GENERATOR_PAIRS.stream(). @@ -4547,7 +4553,7 @@ public class Int512VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolMaskUnaryOpProvider") + @Test(dataProvider = "boolUnaryOpProvider") static void anyTrueInt512VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -4571,7 +4577,7 @@ public class Int512VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolMaskUnaryOpProvider") + @Test(dataProvider = "boolUnaryOpProvider") static void allTrueInt512VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); diff --git a/test/jdk/jdk/incubator/vector/Int64VectorTests.java b/test/jdk/jdk/incubator/vector/Int64VectorTests.java index 15b3b68820e..9c35785e298 100644 --- a/test/jdk/jdk/incubator/vector/Int64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Int64VectorTests.java @@ -1115,6 +1115,12 @@ public class Int64VectorTests extends AbstractVectorTest { .flatMap(pair -> INT_SATURATING_GENERATORS_ASSOC.stream().map(f -> List.of(pair.get(0), pair.get(1), f))) .collect(Collectors.toList()); + @DataProvider + public Object[][] boolUnaryOpProvider() { + return BOOL_ARRAY_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } static final List>> INT_GENERATOR_TRIPLES = INT_GENERATOR_PAIRS.stream(). @@ -4547,7 +4553,7 @@ public class Int64VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolMaskUnaryOpProvider") + @Test(dataProvider = "boolUnaryOpProvider") static void anyTrueInt64VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -4571,7 +4577,7 @@ public class Int64VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolMaskUnaryOpProvider") + @Test(dataProvider = "boolUnaryOpProvider") static void allTrueInt64VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); diff --git a/test/jdk/jdk/incubator/vector/IntMaxVectorTests.java b/test/jdk/jdk/incubator/vector/IntMaxVectorTests.java index 67368e0f70e..0f5e0d1cdc0 100644 --- a/test/jdk/jdk/incubator/vector/IntMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/IntMaxVectorTests.java @@ -1120,6 +1120,12 @@ public class IntMaxVectorTests extends AbstractVectorTest { .flatMap(pair -> INT_SATURATING_GENERATORS_ASSOC.stream().map(f -> List.of(pair.get(0), pair.get(1), f))) .collect(Collectors.toList()); + @DataProvider + public Object[][] boolUnaryOpProvider() { + return BOOL_ARRAY_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } static final List>> INT_GENERATOR_TRIPLES = INT_GENERATOR_PAIRS.stream(). @@ -4552,7 +4558,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolMaskUnaryOpProvider") + @Test(dataProvider = "boolUnaryOpProvider") static void anyTrueIntMaxVectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -4576,7 +4582,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolMaskUnaryOpProvider") + @Test(dataProvider = "boolUnaryOpProvider") static void allTrueIntMaxVectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); diff --git a/test/jdk/jdk/incubator/vector/Long128VectorTests.java b/test/jdk/jdk/incubator/vector/Long128VectorTests.java index 6f91fb9ffbf..832329a0a8b 100644 --- a/test/jdk/jdk/incubator/vector/Long128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Long128VectorTests.java @@ -1105,6 +1105,12 @@ public class Long128VectorTests extends AbstractVectorTest { .flatMap(pair -> LONG_SATURATING_GENERATORS_ASSOC.stream().map(f -> List.of(pair.get(0), pair.get(1), f))) .collect(Collectors.toList()); + @DataProvider + public Object[][] boolUnaryOpProvider() { + return BOOL_ARRAY_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } static final List>> LONG_GENERATOR_TRIPLES = LONG_GENERATOR_PAIRS.stream(). @@ -4569,7 +4575,7 @@ public class Long128VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolMaskUnaryOpProvider") + @Test(dataProvider = "boolUnaryOpProvider") static void anyTrueLong128VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -4593,7 +4599,7 @@ public class Long128VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolMaskUnaryOpProvider") + @Test(dataProvider = "boolUnaryOpProvider") static void allTrueLong128VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); diff --git a/test/jdk/jdk/incubator/vector/Long256VectorTests.java b/test/jdk/jdk/incubator/vector/Long256VectorTests.java index 118c955ad24..ff9d063ad0a 100644 --- a/test/jdk/jdk/incubator/vector/Long256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Long256VectorTests.java @@ -1105,6 +1105,12 @@ public class Long256VectorTests extends AbstractVectorTest { .flatMap(pair -> LONG_SATURATING_GENERATORS_ASSOC.stream().map(f -> List.of(pair.get(0), pair.get(1), f))) .collect(Collectors.toList()); + @DataProvider + public Object[][] boolUnaryOpProvider() { + return BOOL_ARRAY_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } static final List>> LONG_GENERATOR_TRIPLES = LONG_GENERATOR_PAIRS.stream(). @@ -4569,7 +4575,7 @@ public class Long256VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolMaskUnaryOpProvider") + @Test(dataProvider = "boolUnaryOpProvider") static void anyTrueLong256VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -4593,7 +4599,7 @@ public class Long256VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolMaskUnaryOpProvider") + @Test(dataProvider = "boolUnaryOpProvider") static void allTrueLong256VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); diff --git a/test/jdk/jdk/incubator/vector/Long512VectorTests.java b/test/jdk/jdk/incubator/vector/Long512VectorTests.java index 1bca0ef0ebd..fac87be8e22 100644 --- a/test/jdk/jdk/incubator/vector/Long512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Long512VectorTests.java @@ -1105,6 +1105,12 @@ public class Long512VectorTests extends AbstractVectorTest { .flatMap(pair -> LONG_SATURATING_GENERATORS_ASSOC.stream().map(f -> List.of(pair.get(0), pair.get(1), f))) .collect(Collectors.toList()); + @DataProvider + public Object[][] boolUnaryOpProvider() { + return BOOL_ARRAY_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } static final List>> LONG_GENERATOR_TRIPLES = LONG_GENERATOR_PAIRS.stream(). @@ -4569,7 +4575,7 @@ public class Long512VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolMaskUnaryOpProvider") + @Test(dataProvider = "boolUnaryOpProvider") static void anyTrueLong512VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -4593,7 +4599,7 @@ public class Long512VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolMaskUnaryOpProvider") + @Test(dataProvider = "boolUnaryOpProvider") static void allTrueLong512VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); diff --git a/test/jdk/jdk/incubator/vector/Long64VectorTests.java b/test/jdk/jdk/incubator/vector/Long64VectorTests.java index 212bbb5047c..7c283b972dc 100644 --- a/test/jdk/jdk/incubator/vector/Long64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Long64VectorTests.java @@ -1105,6 +1105,12 @@ public class Long64VectorTests extends AbstractVectorTest { .flatMap(pair -> LONG_SATURATING_GENERATORS_ASSOC.stream().map(f -> List.of(pair.get(0), pair.get(1), f))) .collect(Collectors.toList()); + @DataProvider + public Object[][] boolUnaryOpProvider() { + return BOOL_ARRAY_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } static final List>> LONG_GENERATOR_TRIPLES = LONG_GENERATOR_PAIRS.stream(). @@ -4569,7 +4575,7 @@ public class Long64VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolMaskUnaryOpProvider") + @Test(dataProvider = "boolUnaryOpProvider") static void anyTrueLong64VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -4593,7 +4599,7 @@ public class Long64VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolMaskUnaryOpProvider") + @Test(dataProvider = "boolUnaryOpProvider") static void allTrueLong64VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); diff --git a/test/jdk/jdk/incubator/vector/LongMaxVectorTests.java b/test/jdk/jdk/incubator/vector/LongMaxVectorTests.java index 3eba905e4f8..c76a2a2affd 100644 --- a/test/jdk/jdk/incubator/vector/LongMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/LongMaxVectorTests.java @@ -1110,6 +1110,12 @@ public class LongMaxVectorTests extends AbstractVectorTest { .flatMap(pair -> LONG_SATURATING_GENERATORS_ASSOC.stream().map(f -> List.of(pair.get(0), pair.get(1), f))) .collect(Collectors.toList()); + @DataProvider + public Object[][] boolUnaryOpProvider() { + return BOOL_ARRAY_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } static final List>> LONG_GENERATOR_TRIPLES = LONG_GENERATOR_PAIRS.stream(). @@ -4574,7 +4580,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolMaskUnaryOpProvider") + @Test(dataProvider = "boolUnaryOpProvider") static void anyTrueLongMaxVectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -4598,7 +4604,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolMaskUnaryOpProvider") + @Test(dataProvider = "boolUnaryOpProvider") static void allTrueLongMaxVectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); diff --git a/test/jdk/jdk/incubator/vector/Short128VectorTests.java b/test/jdk/jdk/incubator/vector/Short128VectorTests.java index 50be26b163a..8300c64e574 100644 --- a/test/jdk/jdk/incubator/vector/Short128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Short128VectorTests.java @@ -1115,6 +1115,12 @@ public class Short128VectorTests extends AbstractVectorTest { .flatMap(pair -> SHORT_SATURATING_GENERATORS_ASSOC.stream().map(f -> List.of(pair.get(0), pair.get(1), f))) .collect(Collectors.toList()); + @DataProvider + public Object[][] boolUnaryOpProvider() { + return BOOL_ARRAY_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } static final List>> SHORT_GENERATOR_TRIPLES = SHORT_GENERATOR_PAIRS.stream(). @@ -4494,7 +4500,7 @@ public class Short128VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolMaskUnaryOpProvider") + @Test(dataProvider = "boolUnaryOpProvider") static void anyTrueShort128VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -4518,7 +4524,7 @@ public class Short128VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolMaskUnaryOpProvider") + @Test(dataProvider = "boolUnaryOpProvider") static void allTrueShort128VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); diff --git a/test/jdk/jdk/incubator/vector/Short256VectorTests.java b/test/jdk/jdk/incubator/vector/Short256VectorTests.java index 5f63164755b..f208905b203 100644 --- a/test/jdk/jdk/incubator/vector/Short256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Short256VectorTests.java @@ -1115,6 +1115,12 @@ public class Short256VectorTests extends AbstractVectorTest { .flatMap(pair -> SHORT_SATURATING_GENERATORS_ASSOC.stream().map(f -> List.of(pair.get(0), pair.get(1), f))) .collect(Collectors.toList()); + @DataProvider + public Object[][] boolUnaryOpProvider() { + return BOOL_ARRAY_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } static final List>> SHORT_GENERATOR_TRIPLES = SHORT_GENERATOR_PAIRS.stream(). @@ -4494,7 +4500,7 @@ public class Short256VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolMaskUnaryOpProvider") + @Test(dataProvider = "boolUnaryOpProvider") static void anyTrueShort256VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -4518,7 +4524,7 @@ public class Short256VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolMaskUnaryOpProvider") + @Test(dataProvider = "boolUnaryOpProvider") static void allTrueShort256VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); diff --git a/test/jdk/jdk/incubator/vector/Short512VectorTests.java b/test/jdk/jdk/incubator/vector/Short512VectorTests.java index 5044f8db482..776ba2115b8 100644 --- a/test/jdk/jdk/incubator/vector/Short512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Short512VectorTests.java @@ -1115,6 +1115,12 @@ public class Short512VectorTests extends AbstractVectorTest { .flatMap(pair -> SHORT_SATURATING_GENERATORS_ASSOC.stream().map(f -> List.of(pair.get(0), pair.get(1), f))) .collect(Collectors.toList()); + @DataProvider + public Object[][] boolUnaryOpProvider() { + return BOOL_ARRAY_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } static final List>> SHORT_GENERATOR_TRIPLES = SHORT_GENERATOR_PAIRS.stream(). @@ -4494,7 +4500,7 @@ public class Short512VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolMaskUnaryOpProvider") + @Test(dataProvider = "boolUnaryOpProvider") static void anyTrueShort512VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -4518,7 +4524,7 @@ public class Short512VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolMaskUnaryOpProvider") + @Test(dataProvider = "boolUnaryOpProvider") static void allTrueShort512VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); diff --git a/test/jdk/jdk/incubator/vector/Short64VectorTests.java b/test/jdk/jdk/incubator/vector/Short64VectorTests.java index bc12c3f0938..9903759f8f3 100644 --- a/test/jdk/jdk/incubator/vector/Short64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Short64VectorTests.java @@ -1115,6 +1115,12 @@ public class Short64VectorTests extends AbstractVectorTest { .flatMap(pair -> SHORT_SATURATING_GENERATORS_ASSOC.stream().map(f -> List.of(pair.get(0), pair.get(1), f))) .collect(Collectors.toList()); + @DataProvider + public Object[][] boolUnaryOpProvider() { + return BOOL_ARRAY_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } static final List>> SHORT_GENERATOR_TRIPLES = SHORT_GENERATOR_PAIRS.stream(). @@ -4494,7 +4500,7 @@ public class Short64VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolMaskUnaryOpProvider") + @Test(dataProvider = "boolUnaryOpProvider") static void anyTrueShort64VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -4518,7 +4524,7 @@ public class Short64VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolMaskUnaryOpProvider") + @Test(dataProvider = "boolUnaryOpProvider") static void allTrueShort64VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); diff --git a/test/jdk/jdk/incubator/vector/ShortMaxVectorTests.java b/test/jdk/jdk/incubator/vector/ShortMaxVectorTests.java index ec2df02b171..2e5c37d8cc6 100644 --- a/test/jdk/jdk/incubator/vector/ShortMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/ShortMaxVectorTests.java @@ -1120,6 +1120,12 @@ public class ShortMaxVectorTests extends AbstractVectorTest { .flatMap(pair -> SHORT_SATURATING_GENERATORS_ASSOC.stream().map(f -> List.of(pair.get(0), pair.get(1), f))) .collect(Collectors.toList()); + @DataProvider + public Object[][] boolUnaryOpProvider() { + return BOOL_ARRAY_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } static final List>> SHORT_GENERATOR_TRIPLES = SHORT_GENERATOR_PAIRS.stream(). @@ -4499,7 +4505,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolMaskUnaryOpProvider") + @Test(dataProvider = "boolUnaryOpProvider") static void anyTrueShortMaxVectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -4523,7 +4529,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolMaskUnaryOpProvider") + @Test(dataProvider = "boolUnaryOpProvider") static void allTrueShortMaxVectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); From c46bed7292aad21b8cf9defcccac43c010a1f116 Mon Sep 17 00:00:00 2001 From: Serguei Spitsyn Date: Fri, 12 Dec 2025 04:03:33 +0000 Subject: [PATCH 262/706] 8371502: serviceability/jvmti/vthread/ThreadListStackTracesTest/ThreadListStackTracesTest.java failing Reviewed-by: lmesnik, amenkov --- .../ThreadListStackTracesTest.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/test/hotspot/jtreg/serviceability/jvmti/vthread/ThreadListStackTracesTest/ThreadListStackTracesTest.java b/test/hotspot/jtreg/serviceability/jvmti/vthread/ThreadListStackTracesTest/ThreadListStackTracesTest.java index 98695390ef7..079f65620d8 100644 --- a/test/hotspot/jtreg/serviceability/jvmti/vthread/ThreadListStackTracesTest/ThreadListStackTracesTest.java +++ b/test/hotspot/jtreg/serviceability/jvmti/vthread/ThreadListStackTracesTest/ThreadListStackTracesTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, 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 @@ -44,6 +44,13 @@ abstract class TestTask implements Runnable { } } + public void ensureReadyAndWaiting(Thread vt, Thread.State expState, ReentrantLock rlock) { + // wait while the thread is not ready or thread state is unexpected + while (!threadReady || (vt.getState() != expState) || !rlock.hasQueuedThreads()) { + sleep(1); + } + } + public void ensureReady(Thread vt, Thread.State expState) { // wait while the thread is not ready or thread state is unexpected while (!threadReady || (vt.getState() != expState)) { @@ -97,7 +104,7 @@ public class ThreadListStackTracesTest { String name = "ReentrantLockTestTask"; TestTask task = new ReentrantLockTestTask(); Thread vt = Thread.ofVirtual().name(name).start(task); - task.ensureReady(vt, expState); + task.ensureReadyAndWaiting(vt, expState, reentrantLock); checkStates(vt, expState); } From 325cdb7fc5cd2ce1d2c2bf08ca064fb0f7e5a0b8 Mon Sep 17 00:00:00 2001 From: Jaikiran Pai Date: Fri, 12 Dec 2025 05:46:33 +0000 Subject: [PATCH 263/706] 8373517: Revert the macos Tahoe specific change done in JDK-8359830 Reviewed-by: rriggs, bpb --- .../macosx/native/libjava/java_props_macosx.c | 50 ++++++------------- 1 file changed, 16 insertions(+), 34 deletions(-) diff --git a/src/java.base/macosx/native/libjava/java_props_macosx.c b/src/java.base/macosx/native/libjava/java_props_macosx.c index 6656bf04efc..94749ee3efe 100644 --- a/src/java.base/macosx/native/libjava/java_props_macosx.c +++ b/src/java.base/macosx/native/libjava/java_props_macosx.c @@ -23,7 +23,6 @@ * questions. */ -#include #include #include #include @@ -230,50 +229,33 @@ void setOSNameAndVersion(java_props_t *sprops) { NSString *nsVerStr = NULL; char* osVersionCStr = NULL; NSOperatingSystemVersion osVer = [[NSProcessInfo processInfo] operatingSystemVersion]; - // Some macOS versions require special handling. For example, - // when the NSOperatingSystemVersion reports 10.16 as the version - // then it should be treated as 11. Similarly, when it reports 16.0 - // as the version then it should be treated as 26. - // If the SYSTEM_VERSION_COMPAT environment variable (a macOS construct) - // is set to 1, then we don't do any special handling for any versions - // and just literally use the value that NSOperatingSystemVersion reports. - const char* envVal = getenv("SYSTEM_VERSION_COMPAT"); - const bool versionCompatEnabled = envVal != NULL - && strncmp(envVal, "1", 1) == 0; - const bool requiresSpecialHandling = - ((long) osVer.majorVersion == 10 && (long) osVer.minorVersion >= 16) - || ((long) osVer.majorVersion == 16 && (long) osVer.minorVersion >= 0); - if (!requiresSpecialHandling || versionCompatEnabled) { - // no special handling - just use the version reported - // by NSOperatingSystemVersion - if (osVer.patchVersion == 0) { - // Omit trailing ".0" + // Copy out the char* if running on version other than 10.16 Mac OS (10.16 == 11.x) + // or explicitly requesting version compatibility + if (!((long)osVer.majorVersion == 10 && (long)osVer.minorVersion >= 16) || + (getenv("SYSTEM_VERSION_COMPAT") != NULL)) { + if (osVer.patchVersion == 0) { // Omit trailing ".0" nsVerStr = [NSString stringWithFormat:@"%ld.%ld", (long)osVer.majorVersion, (long)osVer.minorVersion]; } else { nsVerStr = [NSString stringWithFormat:@"%ld.%ld.%ld", - (long)osVer.majorVersion, (long)osVer.minorVersion, - (long)osVer.patchVersion]; + (long)osVer.majorVersion, (long)osVer.minorVersion, (long)osVer.patchVersion]; } } else { - // Requires special handling. We ignore the version reported - // by the NSOperatingSystemVersion API and instead read the - // *real* ProductVersion from - // /System/Library/CoreServices/.SystemVersionPlatform.plist. - // If not found there, then as a last resort we fallback to - // /System/Library/CoreServices/SystemVersion.plist - NSDictionary *version = [NSDictionary dictionaryWithContentsOfFile: - @"/System/Library/CoreServices/.SystemVersionPlatform.plist"]; + // Version 10.16, without explicit env setting of SYSTEM_VERSION_COMPAT + // AKA 11+ Read the *real* ProductVersion from the hidden link to avoid SYSTEM_VERSION_COMPAT + // If not found, fallback below to the SystemVersion.plist + NSDictionary *version = [NSDictionary dictionaryWithContentsOfFile : + @"/System/Library/CoreServices/.SystemVersionPlatform.plist"]; if (version != NULL) { - nsVerStr = [version objectForKey: @"ProductVersion"]; + nsVerStr = [version objectForKey : @"ProductVersion"]; } } - // Last resort - fallback to reading the SystemVersion.plist + // Fallback to reading the SystemVersion.plist if (nsVerStr == NULL) { - NSDictionary *version = [NSDictionary dictionaryWithContentsOfFile: - @"/System/Library/CoreServices/SystemVersion.plist"]; + NSDictionary *version = [NSDictionary dictionaryWithContentsOfFile : + @"/System/Library/CoreServices/SystemVersion.plist"]; if (version != NULL) { - nsVerStr = [version objectForKey: @"ProductVersion"]; + nsVerStr = [version objectForKey : @"ProductVersion"]; } } From 650de99fc662a3e8473391627df9e523b6b80727 Mon Sep 17 00:00:00 2001 From: Emanuel Peter Date: Fri, 12 Dec 2025 07:17:17 +0000 Subject: [PATCH 264/706] 8367158: C2: create better fill and copy benchmarks, taking alignment into account Reviewed-by: qamai, kvn --- .../compiler/VectorBulkOperationsArray.java | 774 ++++++++++++++++++ .../VectorBulkOperationsMemorySegment.java | 374 +++++++++ 2 files changed, 1148 insertions(+) create mode 100644 test/micro/org/openjdk/bench/vm/compiler/VectorBulkOperationsArray.java create mode 100644 test/micro/org/openjdk/bench/vm/compiler/VectorBulkOperationsMemorySegment.java diff --git a/test/micro/org/openjdk/bench/vm/compiler/VectorBulkOperationsArray.java b/test/micro/org/openjdk/bench/vm/compiler/VectorBulkOperationsArray.java new file mode 100644 index 00000000000..2b055779ff6 --- /dev/null +++ b/test/micro/org/openjdk/bench/vm/compiler/VectorBulkOperationsArray.java @@ -0,0 +1,774 @@ +/* + * Copyright (c) 2025, 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.vm.compiler; + +import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.infra.*; + +import java.util.concurrent.TimeUnit; +import java.util.Random; +import java.util.Arrays; + +/** + * This benchmark is here to measure vectorized peformance for some simple bulk operations: + * - fill + * - copy + * + * We may add more in the future, for example: + * - comparison + * - find index + * - filter + * - ... + * + * One important feature of this benchmark, is that we control for alignment and 4k-aliasing, + * something almost no benchmarks have considered up to now. But it is important to get more + * precise, clean and reliable results. + * + * Note, you may want to play with "-XX:-OptimizeFill" for the fill benchmarks, so that we do + * not use the fill-intrinsic, but auto-vectorize. Though I'm currently not seeing a difference, + * maybe the loop is not recognized properly? Maybe the alignment "randomization" prevents it. + * + * Please also look at the companion benchmark: + * VectorBulkOperationsMemorySegment.java + */ +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@State(Scope.Thread) +@Warmup(iterations = 3, time = 1000, timeUnit = TimeUnit.MILLISECONDS) +@Measurement(iterations = 5, time = 1000, timeUnit = TimeUnit.MILLISECONDS) +@Fork(value = 1) +public class VectorBulkOperationsArray { + @Param({ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", + "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", + "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", + "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", + "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", + "50", "51", "52", "53", "54", "55", "56", "57", "58", "59", + "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", + "70", "71", "72", "73", "74", "75", "76", "77", "78", "79", + "80", "81", "82", "83", "84", "85", "86", "87", "88", "89", + "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", + "100","101","102","103","104","105","106","107","108","109", + "110","111","112","113","114","115","116","117","118","119", + "120","121","122","123","124","125","126","127","128","129", + "130","131","132","133","134","135","136","137","138","139", + "140","141","142","143","144","145","146","147","148","149", + "150","151","152","153","154","155","156","157","158","159", + "160","161","162","163","164","165","166","167","168","169", + "170","171","172","173","174","175","176","177","178","179", + "180","181","182","183","184","185","186","187","188","189", + "190","191","192","193","194","195","196","197","198","199", + "200","201","202","203","204","205","206","207","208","209", + "210","211","212","213","214","215","216","217","218","219", + "220","221","222","223","224","225","226","227","228","229", + "230","231","232","233","234","235","236","237","238","239", + "240","241","242","243","244","245","246","247","248","249", + "250","251","252","253","254","255","256","257","258","259", + "260","261","262","263","264","265","266","267","268","269", + "270","271","272","273","274","275","276","277","278","279", + "280","281","282","283","284","285","286","287","288","289", + "290","291","292","293","294","295","296","297","298","299", + "300"}) + public static int NUM_ACCESS_ELEMENTS; + // This is just a default to investigate small iteration loops. + + // Every array has two regions: + // - read region + // - write region + // We should make sure that the region is a multiple of 4k, so that the + // 4k-aliasing prevention trick can work. If we used two arrays, then + // we would not know what the relative offset is between them, so we could + // not do anything about the 4k-aliasing effects. + // Background on 4k-aliasing: many modern CPUs have a store-to-load-forwarding + // mechanism that speeds up loads if the memory locations that were recently + // stored to. For this, the CPU needs to check if there is a store in the store + // buffer with the same address and size. There are various implementations + // with different performance characteristics on various CPUs. For x86, there + // is a special mechanism that quickly checks the lowest 12bits of the address, + // to see if there is a match. If there is a match on the 12bits, we then + // have to eventually check the rest of the bits. There seems to be something + // speculative going on, and so if we eventually find that there is a match + // things are really fast. But if we eventually find that the rest of the + // bits do not match, we have to abort and redo the load from memory/cache, + // and that can be slower than if we had gone to memory/cache directly. Hence, + // if we regularly have matches on the 12bits, but mismatches on the other + // bits, we can be slower than expected. 12bits of address gives us a cyclic + // patterns every 4k bytes. So if you load/store with a distance of 4k or + // a multiple, you can see slower performance than expected, you get a dip/ + // spike in the curve that is a strange artifact. We would like to avoid this + // in our benchmark. That is why we make sure to have k * 4k + 2k offset + // between load and store. + // + // It would be ince to set REGION_SIZE statically, but we want to keep it rather small if possible, + // to avoid running out of cache. But it might be quite large if NUM_ACCESS_ELEMENTS is large. + public static int REGION_SIZE = -1024; + public static final int REGION_2_BYTE_OFFSET = 1024 * 2; // prevent 4k-aliasing + public static final int REGION_2_SHORT_OFFSET = REGION_2_BYTE_OFFSET / 2; + public static final int REGION_2_CHAR_OFFSET = REGION_2_BYTE_OFFSET / 2; + public static final int REGION_2_INT_OFFSET = REGION_2_BYTE_OFFSET / 4; + public static final int REGION_2_LONG_OFFSET = REGION_2_BYTE_OFFSET / 8; + public static final int REGION_2_FLOAT_OFFSET = REGION_2_BYTE_OFFSET / 4; + public static final int REGION_2_DOUBLE_OFFSET = REGION_2_BYTE_OFFSET / 8; + // For Objects, it could be 4 or 8 bytes. Dividing by 8 gives us something + // reasonable for both cases. + public static final int REGION_2_OBJECT_OFFSET = REGION_2_BYTE_OFFSET / 8; + + // The arrays with the two regions each + private byte[] aB; + private short[] aS; + private char[] aC; + private int[] aI; + private long[] aL; + private float[] aF; + private double[] aD; + + // Used when we need variable values in fill. + private byte varB = 42; + private short varS = 42; + private char varC = 42; + private int varI = 42; + private long varL = 42; + private float varF = 42; + private double varD = 42; + + // Classes for Object arrays. + static class A { + int x; + A(int x) { + this.x = x; + } + } + static class B extends A { + int y; + B(int x, int y) { + super(x); + this.y = y; + } + } + private A[] aOA; + private B[] aOB; + private A varOA = new A(-1); + private B varOB = new B(-1, -1); + + // Number of repetitions, to randomize the offsets. + public static final int REPETITIONS = 64 * 64; + + @CompilerControl(CompilerControl.Mode.INLINE) + public static int offsetLoad(int i) { return i & 63; } // bits 0-7, value from 0-63 + + @CompilerControl(CompilerControl.Mode.INLINE) + public static int offsetStore(int i) { return (i >> 8) & 63; } // bits 8-15, value from 0-63 + + @Param("42") + private int seed; + private Random r = new Random(seed); + + public static int roundUp4k(int i) { + return (i + 4*1024-1) & (-4*1024); + } + + @Setup + public void init() { + // Make sure we can fit the longs, and then some whiggle room for alignment. + REGION_SIZE = roundUp4k(NUM_ACCESS_ELEMENTS * 8 + 1024 + REGION_2_BYTE_OFFSET); + aB = new byte[2 * REGION_SIZE]; + aC = new char[2 * REGION_SIZE]; + aS = new short[2 * REGION_SIZE]; + aI = new int[2 * REGION_SIZE]; + aL = new long[2 * REGION_SIZE]; + aF = new float[2 * REGION_SIZE]; + aD = new double[2 * REGION_SIZE]; + aOA = new A[2 * REGION_SIZE]; + aOB = new B[2 * REGION_SIZE]; + + for (int i = 0; i < 2 * REGION_SIZE; i++) { + aB[i] = (byte) r.nextInt(); + aS[i] = (short) r.nextInt(); + aC[i] = (char) r.nextInt(); + aI[i] = r.nextInt(); + aL[i] = r.nextLong(); + aF[i] = r.nextFloat(); + aD[i] = r.nextDouble(); + aOA[i] = switch (i % 4) { + case 0, 1 -> new A(i); + case 2 -> new B(i, i); + default -> null; + }; + aOB[i] = (i % 3 != 0) ? new B(i, i) : null; + } + } + + // -------------------------------- BYTE ------------------------------ + + @Benchmark + @OperationsPerInvocation(REPETITIONS) + public void fill_zero_byte_loop() { + for (int r = 0; r < REPETITIONS; r++) { + int offset_store = offsetStore(r) + REGION_SIZE + REGION_2_BYTE_OFFSET; + for (int i = 0; i < NUM_ACCESS_ELEMENTS; i++) { + aB[i + offset_store] = 0; + } + } + } + + @Benchmark + @OperationsPerInvocation(REPETITIONS) + public void fill_var_byte_loop() { + for (int r = 0; r < REPETITIONS; r++) { + int offset_store = offsetStore(r) + REGION_SIZE + REGION_2_BYTE_OFFSET; + for (int i = 0; i < NUM_ACCESS_ELEMENTS; i++) { + aB[i + offset_store] = varB; + } + } + } + + @Benchmark + @OperationsPerInvocation(REPETITIONS) + public void fill_zero_byte_arrays_fill() { + for (int r = 0; r < REPETITIONS; r++) { + int offset_store = offsetStore(r) + REGION_SIZE + REGION_2_BYTE_OFFSET; + Arrays.fill(aB, offset_store, offset_store + NUM_ACCESS_ELEMENTS, (byte)0); + } + } + + @Benchmark + @OperationsPerInvocation(REPETITIONS) + public void fill_var_byte_arrays_fill() { + for (int r = 0; r < REPETITIONS; r++) { + int offset_store = offsetStore(r) + REGION_SIZE + REGION_2_BYTE_OFFSET; + Arrays.fill(aB, offset_store, offset_store + NUM_ACCESS_ELEMENTS, varB); + } + } + + @Benchmark + @OperationsPerInvocation(REPETITIONS) + public void copy_byte_loop() { + for (int r = 0; r < REPETITIONS; r++) { + int offset_load = offsetLoad(r); + int offset_store = offsetStore(r) + REGION_SIZE + REGION_2_BYTE_OFFSET; + for (int i = 0; i < NUM_ACCESS_ELEMENTS; i++) { + aB[i + offset_store] = aB[i + offset_load]; + } + } + } + + @Benchmark + @OperationsPerInvocation(REPETITIONS) + public void copy_byte_system_arraycopy() { + for (int r = 0; r < REPETITIONS; r++) { + int offset_load = offsetLoad(r); + int offset_store = offsetStore(r) + REGION_SIZE + REGION_2_BYTE_OFFSET; + System.arraycopy(aB, offset_load, aB, offset_store, NUM_ACCESS_ELEMENTS); + } + } + + // -------------------------------- CHAR ------------------------------ + + @Benchmark + @OperationsPerInvocation(REPETITIONS) + public void fill_zero_char_loop() { + for (int r = 0; r < REPETITIONS; r++) { + int offset_store = offsetStore(r) + REGION_SIZE + REGION_2_CHAR_OFFSET; + for (int i = 0; i < NUM_ACCESS_ELEMENTS; i++) { + aC[i + offset_store] = 0; + } + } + } + + @Benchmark + @OperationsPerInvocation(REPETITIONS) + public void fill_var_char_loop() { + for (int r = 0; r < REPETITIONS; r++) { + int offset_store = offsetStore(r) + REGION_SIZE + REGION_2_CHAR_OFFSET; + for (int i = 0; i < NUM_ACCESS_ELEMENTS; i++) { + aC[i + offset_store] = varC; + } + } + } + + @Benchmark + @OperationsPerInvocation(REPETITIONS) + public void fill_zero_char_arrays_fill() { + for (int r = 0; r < REPETITIONS; r++) { + int offset_store = offsetStore(r) + REGION_SIZE + REGION_2_CHAR_OFFSET; + Arrays.fill(aC, offset_store, offset_store + NUM_ACCESS_ELEMENTS, (char)0); + } + } + + @Benchmark + @OperationsPerInvocation(REPETITIONS) + public void fill_var_char_arrays_fill() { + for (int r = 0; r < REPETITIONS; r++) { + int offset_store = offsetStore(r) + REGION_SIZE + REGION_2_CHAR_OFFSET; + Arrays.fill(aC, offset_store, offset_store + NUM_ACCESS_ELEMENTS, varC); + } + } + + @Benchmark + @OperationsPerInvocation(REPETITIONS) + public void copy_char_loop() { + for (int r = 0; r < REPETITIONS; r++) { + int offset_load = offsetLoad(r); + int offset_store = offsetStore(r) + REGION_SIZE + REGION_2_CHAR_OFFSET; + for (int i = 0; i < NUM_ACCESS_ELEMENTS; i++) { + aC[i + offset_store] = aC[i + offset_load]; + } + } + } + + @Benchmark + @OperationsPerInvocation(REPETITIONS) + public void copy_char_system_arraycopy() { + for (int r = 0; r < REPETITIONS; r++) { + int offset_load = offsetLoad(r); + int offset_store = offsetStore(r) + REGION_SIZE + REGION_2_CHAR_OFFSET; + System.arraycopy(aC, offset_load, aC, offset_store, NUM_ACCESS_ELEMENTS); + } + } + + // -------------------------------- SHORT ------------------------------ + + @Benchmark + @OperationsPerInvocation(REPETITIONS) + public void fill_zero_short_loop() { + for (int r = 0; r < REPETITIONS; r++) { + int offset_store = offsetStore(r) + REGION_SIZE + REGION_2_SHORT_OFFSET; + for (int i = 0; i < NUM_ACCESS_ELEMENTS; i++) { + aS[i + offset_store] = 0; + } + } + } + + @Benchmark + @OperationsPerInvocation(REPETITIONS) + public void fill_var_short_loop() { + for (int r = 0; r < REPETITIONS; r++) { + int offset_store = offsetStore(r) + REGION_SIZE + REGION_2_SHORT_OFFSET; + for (int i = 0; i < NUM_ACCESS_ELEMENTS; i++) { + aS[i + offset_store] = varS; + } + } + } + + @Benchmark + @OperationsPerInvocation(REPETITIONS) + public void fill_zero_short_arrays_fill() { + for (int r = 0; r < REPETITIONS; r++) { + int offset_store = offsetStore(r) + REGION_SIZE + REGION_2_SHORT_OFFSET; + Arrays.fill(aS, offset_store, offset_store + NUM_ACCESS_ELEMENTS, (short)0); + } + } + + @Benchmark + @OperationsPerInvocation(REPETITIONS) + public void fill_var_short_arrays_fill() { + for (int r = 0; r < REPETITIONS; r++) { + int offset_store = offsetStore(r) + REGION_SIZE + REGION_2_SHORT_OFFSET; + Arrays.fill(aS, offset_store, offset_store + NUM_ACCESS_ELEMENTS, varS); + } + } + + @Benchmark + @OperationsPerInvocation(REPETITIONS) + public void copy_short_loop() { + for (int r = 0; r < REPETITIONS; r++) { + int offset_load = offsetLoad(r); + int offset_store = offsetStore(r) + REGION_SIZE + REGION_2_SHORT_OFFSET; + for (int i = 0; i < NUM_ACCESS_ELEMENTS; i++) { + aS[i + offset_store] = aS[i + offset_load]; + } + } + } + + @Benchmark + @OperationsPerInvocation(REPETITIONS) + public void copy_short_system_arraycopy() { + for (int r = 0; r < REPETITIONS; r++) { + int offset_load = offsetLoad(r); + int offset_store = offsetStore(r) + REGION_SIZE + REGION_2_SHORT_OFFSET; + System.arraycopy(aS, offset_load, aS, offset_store, NUM_ACCESS_ELEMENTS); + } + } + + // -------------------------------- INT ------------------------------ + + @Benchmark + @OperationsPerInvocation(REPETITIONS) + public void fill_zero_int_loop() { + for (int r = 0; r < REPETITIONS; r++) { + int offset_store = offsetStore(r) + REGION_SIZE + REGION_2_INT_OFFSET; + for (int i = 0; i < NUM_ACCESS_ELEMENTS; i++) { + aI[i + offset_store] = 0; + } + } + } + + @Benchmark + @OperationsPerInvocation(REPETITIONS) + public void fill_var_int_loop() { + for (int r = 0; r < REPETITIONS; r++) { + int offset_store = offsetStore(r) + REGION_SIZE + REGION_2_INT_OFFSET; + for (int i = 0; i < NUM_ACCESS_ELEMENTS; i++) { + aI[i + offset_store] = varI; + } + } + } + + @Benchmark + @OperationsPerInvocation(REPETITIONS) + public void fill_zero_int_arrays_fill() { + for (int r = 0; r < REPETITIONS; r++) { + int offset_store = offsetStore(r) + REGION_SIZE + REGION_2_INT_OFFSET; + Arrays.fill(aI, offset_store, offset_store + NUM_ACCESS_ELEMENTS, (int)0); + } + } + + @Benchmark + @OperationsPerInvocation(REPETITIONS) + public void fill_var_int_arrays_fill() { + for (int r = 0; r < REPETITIONS; r++) { + int offset_store = offsetStore(r) + REGION_SIZE + REGION_2_INT_OFFSET; + Arrays.fill(aI, offset_store, offset_store + NUM_ACCESS_ELEMENTS, varI); + } + } + + @Benchmark + @OperationsPerInvocation(REPETITIONS) + public void copy_int_loop() { + for (int r = 0; r < REPETITIONS; r++) { + int offset_load = offsetLoad(r); + int offset_store = offsetStore(r) + REGION_SIZE + REGION_2_INT_OFFSET; + for (int i = 0; i < NUM_ACCESS_ELEMENTS; i++) { + aI[i + offset_store] = aI[i + offset_load]; + } + } + } + + @Benchmark + @OperationsPerInvocation(REPETITIONS) + public void copy_int_system_arraycopy() { + for (int r = 0; r < REPETITIONS; r++) { + int offset_load = offsetLoad(r); + int offset_store = offsetStore(r) + REGION_SIZE + REGION_2_INT_OFFSET; + System.arraycopy(aI, offset_load, aI, offset_store, NUM_ACCESS_ELEMENTS); + } + } + + // -------------------------------- LONG ------------------------------ + + @Benchmark + @OperationsPerInvocation(REPETITIONS) + public void fill_zero_long_loop() { + for (int r = 0; r < REPETITIONS; r++) { + int offset_store = offsetStore(r) + REGION_SIZE + REGION_2_LONG_OFFSET; + for (int i = 0; i < NUM_ACCESS_ELEMENTS; i++) { + aL[i + offset_store] = 0; + } + } + } + + @Benchmark + @OperationsPerInvocation(REPETITIONS) + public void fill_var_long_loop() { + for (int r = 0; r < REPETITIONS; r++) { + int offset_store = offsetStore(r) + REGION_SIZE + REGION_2_LONG_OFFSET; + for (int i = 0; i < NUM_ACCESS_ELEMENTS; i++) { + aL[i + offset_store] = varL; + } + } + } + + @Benchmark + @OperationsPerInvocation(REPETITIONS) + public void fill_zero_long_arrays_fill() { + for (int r = 0; r < REPETITIONS; r++) { + int offset_store = offsetStore(r) + REGION_SIZE + REGION_2_LONG_OFFSET; + Arrays.fill(aL, offset_store, offset_store + NUM_ACCESS_ELEMENTS, (long)0); + } + } + + @Benchmark + @OperationsPerInvocation(REPETITIONS) + public void fill_var_long_arrays_fill() { + for (int r = 0; r < REPETITIONS; r++) { + int offset_store = offsetStore(r) + REGION_SIZE + REGION_2_LONG_OFFSET; + Arrays.fill(aL, offset_store, offset_store + NUM_ACCESS_ELEMENTS, varL); + } + } + + @Benchmark + @OperationsPerInvocation(REPETITIONS) + public void copy_long_loop() { + for (int r = 0; r < REPETITIONS; r++) { + int offset_load = offsetLoad(r); + int offset_store = offsetStore(r) + REGION_SIZE + REGION_2_LONG_OFFSET; + for (int i = 0; i < NUM_ACCESS_ELEMENTS; i++) { + aL[i + offset_store] = aL[i + offset_load]; + } + } + } + + @Benchmark + @OperationsPerInvocation(REPETITIONS) + public void copy_long_system_arraycopy() { + for (int r = 0; r < REPETITIONS; r++) { + int offset_load = offsetLoad(r); + int offset_store = offsetStore(r) + REGION_SIZE + REGION_2_LONG_OFFSET; + System.arraycopy(aL, offset_load, aL, offset_store, NUM_ACCESS_ELEMENTS); + } + } + + // -------------------------------- FLOAT ------------------------------ + + @Benchmark + @OperationsPerInvocation(REPETITIONS) + public void fill_zero_float_loop() { + for (int r = 0; r < REPETITIONS; r++) { + int offset_store = offsetStore(r) + REGION_SIZE + REGION_2_FLOAT_OFFSET; + for (int i = 0; i < NUM_ACCESS_ELEMENTS; i++) { + aF[i + offset_store] = 0; + } + } + } + + @Benchmark + @OperationsPerInvocation(REPETITIONS) + public void fill_var_float_loop() { + for (int r = 0; r < REPETITIONS; r++) { + int offset_store = offsetStore(r) + REGION_SIZE + REGION_2_FLOAT_OFFSET; + for (int i = 0; i < NUM_ACCESS_ELEMENTS; i++) { + aF[i + offset_store] = varF; + } + } + } + + @Benchmark + @OperationsPerInvocation(REPETITIONS) + public void fill_zero_float_arrays_fill() { + for (int r = 0; r < REPETITIONS; r++) { + int offset_store = offsetStore(r) + REGION_SIZE + REGION_2_FLOAT_OFFSET; + Arrays.fill(aF, offset_store, offset_store + NUM_ACCESS_ELEMENTS, (float)0); + } + } + + @Benchmark + @OperationsPerInvocation(REPETITIONS) + public void fill_var_float_arrays_fill() { + for (int r = 0; r < REPETITIONS; r++) { + int offset_store = offsetStore(r) + REGION_SIZE + REGION_2_FLOAT_OFFSET; + Arrays.fill(aF, offset_store, offset_store + NUM_ACCESS_ELEMENTS, varF); + } + } + + @Benchmark + @OperationsPerInvocation(REPETITIONS) + public void copy_float_loop() { + for (int r = 0; r < REPETITIONS; r++) { + int offset_load = offsetLoad(r); + int offset_store = offsetStore(r) + REGION_SIZE + REGION_2_FLOAT_OFFSET; + for (int i = 0; i < NUM_ACCESS_ELEMENTS; i++) { + aF[i + offset_store] = aF[i + offset_load]; + } + } + } + + @Benchmark + @OperationsPerInvocation(REPETITIONS) + public void copy_float_system_arraycopy() { + for (int r = 0; r < REPETITIONS; r++) { + int offset_load = offsetLoad(r); + int offset_store = offsetStore(r) + REGION_SIZE + REGION_2_FLOAT_OFFSET; + System.arraycopy(aF, offset_load, aF, offset_store, NUM_ACCESS_ELEMENTS); + } + } + + // -------------------------------- DOUBLE ------------------------------ + + @Benchmark + @OperationsPerInvocation(REPETITIONS) + public void fill_zero_double_loop() { + for (int r = 0; r < REPETITIONS; r++) { + int offset_store = offsetStore(r) + REGION_SIZE + REGION_2_DOUBLE_OFFSET; + for (int i = 0; i < NUM_ACCESS_ELEMENTS; i++) { + aD[i + offset_store] = 0; + } + } + } + + @Benchmark + @OperationsPerInvocation(REPETITIONS) + public void fill_var_double_loop() { + for (int r = 0; r < REPETITIONS; r++) { + int offset_store = offsetStore(r) + REGION_SIZE + REGION_2_DOUBLE_OFFSET; + for (int i = 0; i < NUM_ACCESS_ELEMENTS; i++) { + aD[i + offset_store] = varD; + } + } + } + + @Benchmark + @OperationsPerInvocation(REPETITIONS) + public void fill_zero_double_arrays_fill() { + for (int r = 0; r < REPETITIONS; r++) { + int offset_store = offsetStore(r) + REGION_SIZE + REGION_2_DOUBLE_OFFSET; + Arrays.fill(aD, offset_store, offset_store + NUM_ACCESS_ELEMENTS, (double)0); + } + } + + @Benchmark + @OperationsPerInvocation(REPETITIONS) + public void fill_var_double_arrays_fill() { + for (int r = 0; r < REPETITIONS; r++) { + int offset_store = offsetStore(r) + REGION_SIZE + REGION_2_DOUBLE_OFFSET; + Arrays.fill(aD, offset_store, offset_store + NUM_ACCESS_ELEMENTS, varD); + } + } + + @Benchmark + @OperationsPerInvocation(REPETITIONS) + public void copy_double_loop() { + for (int r = 0; r < REPETITIONS; r++) { + int offset_load = offsetLoad(r); + int offset_store = offsetStore(r) + REGION_SIZE + REGION_2_DOUBLE_OFFSET; + for (int i = 0; i < NUM_ACCESS_ELEMENTS; i++) { + aD[i + offset_store] = aD[i + offset_load]; + } + } + } + + @Benchmark + @OperationsPerInvocation(REPETITIONS) + public void copy_double_system_arraycopy() { + for (int r = 0; r < REPETITIONS; r++) { + int offset_load = offsetLoad(r); + int offset_store = offsetStore(r) + REGION_SIZE + REGION_2_DOUBLE_OFFSET; + System.arraycopy(aD, offset_load, aD, offset_store, NUM_ACCESS_ELEMENTS); + } + } + + // -------------------------------- OBJECT ------------------------------ + + @Benchmark + @OperationsPerInvocation(REPETITIONS) + public void fill_null_loop() { + for (int r = 0; r < REPETITIONS; r++) { + int offset_store = offsetStore(r) + REGION_SIZE + REGION_2_OBJECT_OFFSET; + for (int i = 0; i < NUM_ACCESS_ELEMENTS; i++) { + aOA[i + offset_store] = null; + } + } + } + + @Benchmark + @OperationsPerInvocation(REPETITIONS) + public void fill_A2A_loop() { + for (int r = 0; r < REPETITIONS; r++) { + int offset_store = offsetStore(r) + REGION_SIZE + REGION_2_OBJECT_OFFSET; + for (int i = 0; i < NUM_ACCESS_ELEMENTS; i++) { + aOA[i + offset_store] = varOA; + } + } + } + + @Benchmark + @OperationsPerInvocation(REPETITIONS) + public void fill_B2A_loop() { + for (int r = 0; r < REPETITIONS; r++) { + int offset_store = offsetStore(r) + REGION_SIZE + REGION_2_OBJECT_OFFSET; + for (int i = 0; i < NUM_ACCESS_ELEMENTS; i++) { + aOA[i + offset_store] = varOB; + } + } + } + + @Benchmark + @OperationsPerInvocation(REPETITIONS) + public void fill_null_arrays_fill() { + for (int r = 0; r < REPETITIONS; r++) { + int offset_store = offsetStore(r) + REGION_SIZE + REGION_2_OBJECT_OFFSET; + Arrays.fill(aOA, offset_store, offset_store + NUM_ACCESS_ELEMENTS, null); + } + } + + @Benchmark + @OperationsPerInvocation(REPETITIONS) + public void fill_A2A_arrays_fill() { + for (int r = 0; r < REPETITIONS; r++) { + int offset_store = offsetStore(r) + REGION_SIZE + REGION_2_OBJECT_OFFSET; + Arrays.fill(aOA, offset_store, offset_store + NUM_ACCESS_ELEMENTS, varOA); + } + } + + @Benchmark + @OperationsPerInvocation(REPETITIONS) + public void fill_B2A_arrays_fill() { + for (int r = 0; r < REPETITIONS; r++) { + int offset_store = offsetStore(r) + REGION_SIZE + REGION_2_OBJECT_OFFSET; + Arrays.fill(aOA, offset_store, offset_store + NUM_ACCESS_ELEMENTS, varOB); + } + } + + @Benchmark + @OperationsPerInvocation(REPETITIONS) + public void copy_A2A_loop() { + for (int r = 0; r < REPETITIONS; r++) { + int offset_load = offsetLoad(r); + int offset_store = offsetStore(r) + REGION_SIZE + REGION_2_OBJECT_OFFSET; + for (int i = 0; i < NUM_ACCESS_ELEMENTS; i++) { + aOA[i + offset_store] = aOA[i + offset_load]; + } + } + } + + @Benchmark + @OperationsPerInvocation(REPETITIONS) + public void copy_B2A_loop() { + for (int r = 0; r < REPETITIONS; r++) { + int offset_load = offsetLoad(r); + int offset_store = offsetStore(r) + REGION_SIZE + REGION_2_OBJECT_OFFSET; + for (int i = 0; i < NUM_ACCESS_ELEMENTS; i++) { + aOA[i + offset_store] = aOB[i + offset_load]; + } + } + } + + @Benchmark + @OperationsPerInvocation(REPETITIONS) + public void copy_A2A_system_arraycopy() { + for (int r = 0; r < REPETITIONS; r++) { + int offset_load = offsetLoad(r); + int offset_store = offsetStore(r) + REGION_SIZE + REGION_2_OBJECT_OFFSET; + System.arraycopy(aOA, offset_load, aOA, offset_store, NUM_ACCESS_ELEMENTS); + } + } + + @Benchmark + @OperationsPerInvocation(REPETITIONS) + public void copy_B2A_system_arraycopy() { + for (int r = 0; r < REPETITIONS; r++) { + int offset_load = offsetLoad(r); + int offset_store = offsetStore(r) + REGION_SIZE + REGION_2_OBJECT_OFFSET; + System.arraycopy(aOB, offset_load, aOA, offset_store, NUM_ACCESS_ELEMENTS); + } + } +} diff --git a/test/micro/org/openjdk/bench/vm/compiler/VectorBulkOperationsMemorySegment.java b/test/micro/org/openjdk/bench/vm/compiler/VectorBulkOperationsMemorySegment.java new file mode 100644 index 00000000000..fae12a4ac9d --- /dev/null +++ b/test/micro/org/openjdk/bench/vm/compiler/VectorBulkOperationsMemorySegment.java @@ -0,0 +1,374 @@ +/* + * Copyright (c) 2025, 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.vm.compiler; + +import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.infra.*; + +import java.lang.foreign.*; +import java.util.concurrent.TimeUnit; +import java.util.Random; +import java.util.Arrays; + +/** + * This benchmark is here to measure vectorized peformance for some simple bulk operations: + * - fill + * - copy + * + * We may add more in the future, for example: + * - comparison + * - find index + * - filter + * - ... + * + * One important feature of this benchmark, is that we control for alignment and 4k-aliasing, + * something almost no benchmarks have considered up to now. But it is important to get more + * precise, clean and reliable results. + * + * Please also look at the companion benchmark: + * VectorBulkOperationsArray.java + */ +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@State(Scope.Thread) +@Warmup(iterations = 3, time = 1000, timeUnit = TimeUnit.MILLISECONDS) +@Measurement(iterations = 5, time = 1000, timeUnit = TimeUnit.MILLISECONDS) +@Fork(value = 1) +public class VectorBulkOperationsMemorySegment { + @Param({ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", + "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", + "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", + "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", + "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", + "50", "51", "52", "53", "54", "55", "56", "57", "58", "59", + "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", + "70", "71", "72", "73", "74", "75", "76", "77", "78", "79", + "80", "81", "82", "83", "84", "85", "86", "87", "88", "89", + "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", + "100","101","102","103","104","105","106","107","108","109", + "110","111","112","113","114","115","116","117","118","119", + "120","121","122","123","124","125","126","127","128","129", + "130","131","132","133","134","135","136","137","138","139", + "140","141","142","143","144","145","146","147","148","149", + "150","151","152","153","154","155","156","157","158","159", + "160","161","162","163","164","165","166","167","168","169", + "170","171","172","173","174","175","176","177","178","179", + "180","181","182","183","184","185","186","187","188","189", + "190","191","192","193","194","195","196","197","198","199", + "200","201","202","203","204","205","206","207","208","209", + "210","211","212","213","214","215","216","217","218","219", + "220","221","222","223","224","225","226","227","228","229", + "230","231","232","233","234","235","236","237","238","239", + "240","241","242","243","244","245","246","247","248","249", + "250","251","252","253","254","255","256","257","258","259", + "260","261","262","263","264","265","266","267","268","269", + "270","271","272","273","274","275","276","277","278","279", + "280","281","282","283","284","285","286","287","288","289", + "290","291","292","293","294","295","296","297","298","299", + "300"}) + public static long NUM_ACCESS_ELEMENTS; + + @Param({"native", "array_byte", "array_int", "array_long"}) + public static String BACKING_TYPE; + + // Every array has two regions: + // - read region + // - write region + // We should make sure that the region is a multiple of 4k, so that the + // 4k-aliasing prevention trick can work. + // See VectorBulkOperationsArray.java for a deeper explanation. + // + // It would be ince to set REGION_SIZE statically, but we want to keep it rather small if possible, + // to avoid running out of cache. But it might be quite large if NUM_ACCESS_ELEMENTS is large. + public static long REGION_SIZE = -1024; + public static final long REGION_2_BYTE_OFFSET = 1024 * 2; // prevent 4k-aliasing + + // TDOO: see what is still actie up here. + + // Just one MemorySegment for all cases, backed by whatever BACKING_TYPE. + MemorySegment ms; + + // Used when we need variable values in fill. + private byte varB = 42; + private short varS = 42; + private char varC = 42; + private int varI = 42; + private long varL = 42; + private float varF = 42; + private double varD = 42; + + // Number of repetitions, to randomize the offsets. + public static final int REPETITIONS = 64 * 64; + + @CompilerControl(CompilerControl.Mode.INLINE) + public static long offsetLoad(long i) { return i & 63; } // bits 0-7, value from 0-63 + + @CompilerControl(CompilerControl.Mode.INLINE) + public static long offsetStore(long i) { return (i >> 8) & 63; } // bits 8-15, value from 0-63 + + @Param("42") + private int seed; + private Random r = new Random(seed); + + public static long roundUp4k(long i) { + return (i + 4*1024-1) & (-4*1024L); + } + + @Setup + public void init() { + // Make sure we can fit the longs, and then some whiggle room for alignment. + REGION_SIZE = roundUp4k(NUM_ACCESS_ELEMENTS * 8 + 1024 + REGION_2_BYTE_OFFSET); + ms = switch(BACKING_TYPE) { + case "native" -> Arena.ofAuto().allocate(2 * REGION_SIZE, 4 * 1024); + case "array_byte" -> MemorySegment.ofArray(new byte[(int)(2 * REGION_SIZE)]); + case "array_int" -> MemorySegment.ofArray(new int[(int)(2 * REGION_SIZE / 4)]); + case "array_long" -> MemorySegment.ofArray(new long[(int)(2 * REGION_SIZE / 8)]); + default -> throw new RuntimeException("not implemented: " + BACKING_TYPE); + }; + } + + // -------------------------------- BYTE ------------------------------ + + @Benchmark + @OperationsPerInvocation(REPETITIONS) + public void fill_zero_byte_loop() { + for (int r = 0; r < REPETITIONS; r++) { + long offset_store = offsetStore(r) + REGION_SIZE + REGION_2_BYTE_OFFSET; + for (long i = 0; i < NUM_ACCESS_ELEMENTS; i++) { + ms.set(ValueLayout.JAVA_BYTE, i + offset_store, (byte)0); + } + } + } + + @Benchmark + @OperationsPerInvocation(REPETITIONS) + public void fill_var_byte_loop() { + for (int r = 0; r < REPETITIONS; r++) { + long offset_store = offsetStore(r) + REGION_SIZE + REGION_2_BYTE_OFFSET; + for (long i = 0; i < NUM_ACCESS_ELEMENTS; i++) { + ms.set(ValueLayout.JAVA_BYTE, i + offset_store, varB); + } + } + } + + @Benchmark + @OperationsPerInvocation(REPETITIONS) + public void fill_zero_byte_MS_fill() { + for (int r = 0; r < REPETITIONS; r++) { + long offset_store = offsetStore(r) + REGION_SIZE + REGION_2_BYTE_OFFSET; + // The API does not allow us to fill a sub-segment directly, so we have to slice. + MemorySegment slice = ms.asSlice(offset_store, NUM_ACCESS_ELEMENTS); + slice.fill((byte)0); + } + } + + @Benchmark + @OperationsPerInvocation(REPETITIONS) + public void fill_var_byte_MS_fill() { + for (int r = 0; r < REPETITIONS; r++) { + long offset_store = offsetStore(r) + REGION_SIZE + REGION_2_BYTE_OFFSET; + // The API does not allow us to fill a sub-segment directly, so we have to slice. + MemorySegment slice = ms.asSlice(offset_store, NUM_ACCESS_ELEMENTS); + slice.fill(varB); + } + } + + @Benchmark + @OperationsPerInvocation(REPETITIONS) + public void copy_byte_loop() { + for (int r = 0; r < REPETITIONS; r++) { + long offset_load = offsetLoad(r); + long offset_store = offsetStore(r) + REGION_SIZE + REGION_2_BYTE_OFFSET; + for (long i = 0; i < NUM_ACCESS_ELEMENTS; i++) { + byte v = ms.get(ValueLayout.JAVA_BYTE, i + offset_load); + ms.set(ValueLayout.JAVA_BYTE, i + offset_store, v); + } + } + } + + @Benchmark + @OperationsPerInvocation(REPETITIONS) + public void copy_byte_MemorySegment_copy() { + for (int r = 0; r < REPETITIONS; r++) { + long offset_load = offsetLoad(r); + long offset_store = offsetStore(r) + REGION_SIZE + REGION_2_BYTE_OFFSET; + MemorySegment.copy(ms, offset_load, ms, offset_store, NUM_ACCESS_ELEMENTS); + } + } + + // -------------------------------- CHAR ------------------------------ + + @Benchmark + @OperationsPerInvocation(REPETITIONS) + public void fill_var_char_loop() { + for (int r = 0; r < REPETITIONS; r++) { + long offset_store = 2L * offsetStore(r) + REGION_SIZE + REGION_2_BYTE_OFFSET; + for (long i = 0; i < NUM_ACCESS_ELEMENTS; i++) { + ms.set(ValueLayout.JAVA_CHAR_UNALIGNED, 2L * i + offset_store, varC); + } + } + } + + @Benchmark + @OperationsPerInvocation(REPETITIONS) + public void copy_char_loop() { + for (int r = 0; r < REPETITIONS; r++) { + long offset_load = 2L * offsetLoad(r); + long offset_store = 2L * offsetStore(r) + REGION_SIZE + REGION_2_BYTE_OFFSET; + for (long i = 0; i < NUM_ACCESS_ELEMENTS; i++) { + char v = ms.get(ValueLayout.JAVA_CHAR_UNALIGNED, 2L * i + offset_load); + ms.set(ValueLayout.JAVA_CHAR_UNALIGNED, 2L * i + offset_store, v); + } + } + } + + // -------------------------------- SHORT ------------------------------ + + @Benchmark + @OperationsPerInvocation(REPETITIONS) + public void fill_var_short_loop() { + for (int r = 0; r < REPETITIONS; r++) { + long offset_store = 2L * offsetStore(r) + REGION_SIZE + REGION_2_BYTE_OFFSET; + for (long i = 0; i < NUM_ACCESS_ELEMENTS; i++) { + ms.set(ValueLayout.JAVA_SHORT_UNALIGNED, 2L * i + offset_store, varS); + } + } + } + + @Benchmark + @OperationsPerInvocation(REPETITIONS) + public void copy_short_loop() { + for (int r = 0; r < REPETITIONS; r++) { + long offset_load = 2L * offsetLoad(r); + long offset_store = 2L * offsetStore(r) + REGION_SIZE + REGION_2_BYTE_OFFSET; + for (long i = 0; i < NUM_ACCESS_ELEMENTS; i++) { + short v = ms.get(ValueLayout.JAVA_SHORT_UNALIGNED, 2L * i + offset_load); + ms.set(ValueLayout.JAVA_SHORT_UNALIGNED, 2L * i + offset_store, v); + } + } + } + + // -------------------------------- INT ------------------------------ + + @Benchmark + @OperationsPerInvocation(REPETITIONS) + public void fill_var_int_loop() { + for (int r = 0; r < REPETITIONS; r++) { + long offset_store = 4L * offsetStore(r) + REGION_SIZE + REGION_2_BYTE_OFFSET; + for (long i = 0; i < NUM_ACCESS_ELEMENTS; i++) { + ms.set(ValueLayout.JAVA_INT_UNALIGNED, 4L * i + offset_store, varI); + } + } + } + + @Benchmark + @OperationsPerInvocation(REPETITIONS) + public void copy_int_loop() { + for (int r = 0; r < REPETITIONS; r++) { + long offset_load = 4L * offsetLoad(r); + long offset_store = 4L * offsetStore(r) + REGION_SIZE + REGION_2_BYTE_OFFSET; + for (long i = 0; i < NUM_ACCESS_ELEMENTS; i++) { + int v = ms.get(ValueLayout.JAVA_INT_UNALIGNED, 4L * i + offset_load); + ms.set(ValueLayout.JAVA_INT_UNALIGNED, 4L * i + offset_store, v); + } + } + } + + // -------------------------------- LONG ------------------------------ + + @Benchmark + @OperationsPerInvocation(REPETITIONS) + public void fill_var_long_loop() { + for (int r = 0; r < REPETITIONS; r++) { + long offset_store = 8L * offsetStore(r) + REGION_SIZE + REGION_2_BYTE_OFFSET; + for (long i = 0; i < NUM_ACCESS_ELEMENTS; i++) { + ms.set(ValueLayout.JAVA_LONG_UNALIGNED, 8L * i + offset_store, varL); + } + } + } + + @Benchmark + @OperationsPerInvocation(REPETITIONS) + public void copy_long_loop() { + for (int r = 0; r < REPETITIONS; r++) { + long offset_load = 8L * offsetLoad(r); + long offset_store = 8L * offsetStore(r) + REGION_SIZE + REGION_2_BYTE_OFFSET; + for (long i = 0; i < NUM_ACCESS_ELEMENTS; i++) { + long v = ms.get(ValueLayout.JAVA_LONG_UNALIGNED, 8L * i + offset_load); + ms.set(ValueLayout.JAVA_LONG_UNALIGNED, 8L * i + offset_store, v); + } + } + } + + // -------------------------------- FLOAT ------------------------------ + + @Benchmark + @OperationsPerInvocation(REPETITIONS) + public void fill_var_float_loop() { + for (int r = 0; r < REPETITIONS; r++) { + long offset_store = 4L * offsetStore(r) + REGION_SIZE + REGION_2_BYTE_OFFSET; + for (long i = 0; i < NUM_ACCESS_ELEMENTS; i++) { + ms.set(ValueLayout.JAVA_FLOAT_UNALIGNED, 4L * i + offset_store, varS); + } + } + } + + @Benchmark + @OperationsPerInvocation(REPETITIONS) + public void copy_float_loop() { + for (int r = 0; r < REPETITIONS; r++) { + long offset_load = 4L * offsetLoad(r); + long offset_store = 4L * offsetStore(r) + REGION_SIZE + REGION_2_BYTE_OFFSET; + for (long i = 0; i < NUM_ACCESS_ELEMENTS; i++) { + float v = ms.get(ValueLayout.JAVA_FLOAT_UNALIGNED, 4L * i + offset_load); + ms.set(ValueLayout.JAVA_FLOAT_UNALIGNED, 4L * i + offset_store, v); + } + } + } + + // -------------------------------- DOUBLE ------------------------------ + + @Benchmark + @OperationsPerInvocation(REPETITIONS) + public void fill_var_double_loop() { + for (int r = 0; r < REPETITIONS; r++) { + long offset_store = 8L * offsetStore(r) + REGION_SIZE + REGION_2_BYTE_OFFSET; + for (long i = 0; i < NUM_ACCESS_ELEMENTS; i++) { + ms.set(ValueLayout.JAVA_DOUBLE_UNALIGNED, 8L * i + offset_store, varS); + } + } + } + + @Benchmark + @OperationsPerInvocation(REPETITIONS) + public void copy_double_loop() { + for (int r = 0; r < REPETITIONS; r++) { + long offset_load = 8L * offsetLoad(r); + long offset_store = 8L * offsetStore(r) + REGION_SIZE + REGION_2_BYTE_OFFSET; + for (long i = 0; i < NUM_ACCESS_ELEMENTS; i++) { + double v = ms.get(ValueLayout.JAVA_DOUBLE_UNALIGNED, 8L * i + offset_load); + ms.set(ValueLayout.JAVA_DOUBLE_UNALIGNED, 8L * i + offset_store, v); + } + } + } +} From dc6255261f34c65d0e87814638817c97a880eb7f Mon Sep 17 00:00:00 2001 From: Hamlin Li Date: Fri, 12 Dec 2025 09:59:33 +0000 Subject: [PATCH 265/706] 8371920: [TEST] Enable CMove tests on other platforms Reviewed-by: fyang, epeter --- .../TestConditionalMove.java | 170 +++++++------- .../{irTests => cmove}/TestFPComparison2.java | 219 ++++++++++++------ .../TestScalarConditionalMoveCmpObj.java | 3 +- 3 files changed, 231 insertions(+), 161 deletions(-) rename test/hotspot/jtreg/compiler/c2/{irTests => cmove}/TestConditionalMove.java (95%) rename test/hotspot/jtreg/compiler/c2/{irTests => cmove}/TestFPComparison2.java (91%) rename test/hotspot/jtreg/compiler/c2/{irTests => cmove}/TestScalarConditionalMoveCmpObj.java (99%) diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestConditionalMove.java b/test/hotspot/jtreg/compiler/c2/cmove/TestConditionalMove.java similarity index 95% rename from test/hotspot/jtreg/compiler/c2/irTests/TestConditionalMove.java rename to test/hotspot/jtreg/compiler/c2/cmove/TestConditionalMove.java index c531f73b71d..91197322319 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/TestConditionalMove.java +++ b/test/hotspot/jtreg/compiler/c2/cmove/TestConditionalMove.java @@ -36,7 +36,7 @@ import jdk.test.lib.Utils; * @key randomness * @summary Auto-vectorization enhancement to support vector conditional move. * @library /test/lib / - * @run driver compiler.c2.irTests.TestConditionalMove + * @run driver ${test.main.class} */ public class TestConditionalMove { @@ -601,7 +601,7 @@ public class TestConditionalMove { applyIf = {"UseVectorCmov", "false"}) @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_F, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) private static void testCMoveVFGT(float[] a, float[] b, float[] c) { for (int i = 0; i < a.length; i++) { c[i] = (a[i] > b[i]) ? a[i] : b[i]; @@ -619,7 +619,7 @@ public class TestConditionalMove { applyIf = {"UseVectorCmov", "false"}) @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_F, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) private static void testCMoveVFGTSwap(float[] a, float[] b, float[] c) { for (int i = 0; i < a.length; i++) { c[i] = (b[i] > a[i]) ? a[i] : b[i]; @@ -637,7 +637,7 @@ public class TestConditionalMove { applyIf = {"UseVectorCmov", "false"}) @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_F, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) private static void testCMoveVFLT(float[] a, float[] b, float[] c) { for (int i = 0; i < a.length; i++) { c[i] = (a[i] < b[i]) ? a[i] : b[i]; @@ -655,7 +655,7 @@ public class TestConditionalMove { applyIf = {"UseVectorCmov", "false"}) @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_F, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) private static void testCMoveVFLTSwap(float[] a, float[] b, float[] c) { for (int i = 0; i < a.length; i++) { c[i] = (b[i] < a[i]) ? a[i] : b[i]; @@ -673,7 +673,7 @@ public class TestConditionalMove { applyIf = {"UseVectorCmov", "false"}) @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_F, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) private static void testCMoveVFEQ(float[] a, float[] b, float[] c) { for (int i = 0; i < a.length; i++) { c[i] = (a[i] == b[i]) ? a[i] : b[i]; @@ -691,7 +691,7 @@ public class TestConditionalMove { applyIf = {"UseVectorCmov", "false"}) @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_D, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) private static void testCMoveVDLE(double[] a, double[] b, double[] c) { for (int i = 0; i < a.length; i++) { c[i] = (a[i] <= b[i]) ? a[i] : b[i]; @@ -709,7 +709,7 @@ public class TestConditionalMove { applyIf = {"UseVectorCmov", "false"}) @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_D, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) private static void testCMoveVDLESwap(double[] a, double[] b, double[] c) { for (int i = 0; i < a.length; i++) { c[i] = (b[i] <= a[i]) ? a[i] : b[i]; @@ -727,7 +727,7 @@ public class TestConditionalMove { applyIf = {"UseVectorCmov", "false"}) @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_D, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) private static void testCMoveVDGE(double[] a, double[] b, double[] c) { for (int i = 0; i < a.length; i++) { c[i] = (a[i] >= b[i]) ? a[i] : b[i]; @@ -745,7 +745,7 @@ public class TestConditionalMove { applyIf = {"UseVectorCmov", "false"}) @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_D, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) private static void testCMoveVDGESwap(double[] a, double[] b, double[] c) { for (int i = 0; i < a.length; i++) { c[i] = (b[i] >= a[i]) ? a[i] : b[i]; @@ -763,7 +763,7 @@ public class TestConditionalMove { applyIf = {"UseVectorCmov", "false"}) @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_D, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) private static void testCMoveVDNE(double[] a, double[] b, double[] c) { for (int i = 0; i < a.length; i++) { c[i] = (a[i] != b[i]) ? a[i] : b[i]; @@ -782,7 +782,7 @@ public class TestConditionalMove { applyIf = {"UseVectorCmov", "false"}) @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_F, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) private static void testCMoveFGTforFConst(float[] a, float[] b, float[] c) { for (int i = 0; i < a.length; i++) { c[i] = (a[i] > b[i]) ? 0.1f : -0.1f; @@ -800,7 +800,7 @@ public class TestConditionalMove { applyIf = {"UseVectorCmov", "false"}) @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_F, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) private static void testCMoveFGEforFConst(float[] a, float[] b, float[] c) { for (int i = 0; i < a.length; i++) { c[i] = (a[i] >= b[i]) ? 0.1f : -0.1f; @@ -818,7 +818,7 @@ public class TestConditionalMove { applyIf = {"UseVectorCmov", "false"}) @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_F, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) private static void testCMoveFLTforFConst(float[] a, float[] b, float[] c) { for (int i = 0; i < a.length; i++) { c[i] = (a[i] < b[i]) ? 0.1f : -0.1f; @@ -836,7 +836,7 @@ public class TestConditionalMove { applyIf = {"UseVectorCmov", "false"}) @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_F, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) private static void testCMoveFLEforFConst(float[] a, float[] b, float[] c) { for (int i = 0; i < a.length; i++) { c[i] = (a[i] <= b[i]) ? 0.1f : -0.1f; @@ -854,7 +854,7 @@ public class TestConditionalMove { applyIf = {"UseVectorCmov", "false"}) @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_F, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) private static void testCMoveFEQforFConst(float[] a, float[] b, float[] c) { for (int i = 0; i < a.length; i++) { c[i] = (a[i] == b[i]) ? 0.1f : -0.1f; @@ -872,7 +872,7 @@ public class TestConditionalMove { applyIf = {"UseVectorCmov", "false"}) @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_F, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) private static void testCMoveFNEQforFConst(float[] a, float[] b, float[] c) { for (int i = 0; i < a.length; i++) { c[i] = (a[i] != b[i]) ? 0.1f : -0.1f; @@ -896,7 +896,7 @@ public class TestConditionalMove { applyIf = {"UseVectorCmov", "false"}) @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_F, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) private static void testCMoveFLTforFConstH2(float[] a, float[] b, float[] c) { for (int i = 0; i < a.length; i+=2) { c[i+0] = (a[i+0] < b[i+0]) ? 0.1f : -0.1f; @@ -925,7 +925,7 @@ public class TestConditionalMove { applyIf = {"UseVectorCmov", "false"}) @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_F, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) private static void testCMoveFLEforFConstH2(float[] a, float[] b, float[] c) { for (int i = 0; i < a.length; i+=2) { c[i+0] = (a[i+0] <= b[i+0]) ? 0.1f : -0.1f; @@ -948,7 +948,7 @@ public class TestConditionalMove { applyIf = {"UseVectorCmov", "false"}) @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_F, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) private static void testCMoveFYYforFConstH2(float[] a, float[] b, float[] c) { for (int i = 0; i < a.length; i+=2) { c[i+0] = (a[i+0] <= b[i+0]) ? 0.1f : -0.1f; @@ -967,7 +967,7 @@ public class TestConditionalMove { applyIf = {"UseVectorCmov", "false"}) @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_F, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) private static void testCMoveFXXforFConstH2(float[] a, float[] b, float[] c) { for (int i = 0; i < a.length; i+=2) { c[i+0] = (a[i+0] < b[i+0]) ? 0.1f : -0.1f; @@ -986,7 +986,7 @@ public class TestConditionalMove { applyIf = {"UseVectorCmov", "false"}) @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_D, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) private static void testCMoveDGTforDConst(double[] a, double[] b, double[] c) { for (int i = 0; i < a.length; i++) { c[i] = (a[i] > b[i]) ? 0.1 : -0.1; @@ -1004,7 +1004,7 @@ public class TestConditionalMove { applyIf = {"UseVectorCmov", "false"}) @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_D, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) private static void testCMoveDGEforDConst(double[] a, double[] b, double[] c) { for (int i = 0; i < a.length; i++) { c[i] = (a[i] >= b[i]) ? 0.1 : -0.1; @@ -1022,7 +1022,7 @@ public class TestConditionalMove { applyIf = {"UseVectorCmov", "false"}) @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_D, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) private static void testCMoveDLTforDConst(double[] a, double[] b, double[] c) { for (int i = 0; i < a.length; i++) { c[i] = (a[i] < b[i]) ? 0.1 : -0.1; @@ -1040,7 +1040,7 @@ public class TestConditionalMove { applyIf = {"UseVectorCmov", "false"}) @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_D, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) private static void testCMoveDLEforDConst(double[] a, double[] b, double[] c) { for (int i = 0; i < a.length; i++) { c[i] = (a[i] <= b[i]) ? 0.1 : -0.1; @@ -1058,7 +1058,7 @@ public class TestConditionalMove { applyIf = {"UseVectorCmov", "false"}) @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_D, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) private static void testCMoveDEQforDConst(double[] a, double[] b, double[] c) { for (int i = 0; i < a.length; i++) { c[i] = (a[i] == b[i]) ? 0.1 : -0.1; @@ -1076,7 +1076,7 @@ public class TestConditionalMove { applyIf = {"UseVectorCmov", "false"}) @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_D, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) private static void testCMoveDNEQforDConst(double[] a, double[] b, double[] c) { for (int i = 0; i < a.length; i++) { c[i] = (a[i] != b[i]) ? 0.1 : -0.1; @@ -1094,7 +1094,7 @@ public class TestConditionalMove { applyIf = {"UseVectorCmov", "false"}) @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_D, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) private static void testCMoveDLTforDConstH2(double[] a, double[] b, double[] c) { for (int i = 0; i < a.length; i+=2) { c[i+0] = (a[i+0] < b[i+0]) ? 0.1 : -0.1; @@ -1113,7 +1113,7 @@ public class TestConditionalMove { applyIf = {"UseVectorCmov", "false"}) @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_D, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) private static void testCMoveDLEforDConstH2(double[] a, double[] b, double[] c) { for (int i = 0; i < a.length; i+=2) { c[i+0] = (a[i+0] <= b[i+0]) ? 0.1 : -0.1; @@ -1132,7 +1132,7 @@ public class TestConditionalMove { applyIf = {"UseVectorCmov", "false"}) @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_D, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) private static void testCMoveDYYforDConstH2(double[] a, double[] b, double[] c) { for (int i = 0; i < a.length; i+=2) { c[i+0] = (a[i+0] <= b[i+0]) ? 0.1 : -0.1; @@ -1151,7 +1151,7 @@ public class TestConditionalMove { applyIf = {"UseVectorCmov", "false"}) @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_D, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) private static void testCMoveDXXforDConstH2(double[] a, double[] b, double[] c) { for (int i = 0; i < a.length; i+=2) { c[i+0] = (a[i+0] < b[i+0]) ? 0.1 : -0.1; @@ -1351,7 +1351,7 @@ public class TestConditionalMove { applyIf = {"UseVectorCmov", "false"}) @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_I, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) private static void testCMoveIEQforF(int[] a, int[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -1373,7 +1373,7 @@ public class TestConditionalMove { applyIf = {"UseVectorCmov", "false"}) @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_I, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) private static void testCMoveINEforF(int[] a, int[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -1395,7 +1395,7 @@ public class TestConditionalMove { applyIf = {"UseVectorCmov", "false"}) @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_I, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) private static void testCMoveIGTforF(int[] a, int[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -1417,7 +1417,7 @@ public class TestConditionalMove { applyIf = {"UseVectorCmov", "false"}) @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_I, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) private static void testCMoveIGEforF(int[] a, int[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -1439,7 +1439,7 @@ public class TestConditionalMove { applyIf = {"UseVectorCmov", "false"}) @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_I, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) private static void testCMoveILTforF(int[] a, int[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -1461,7 +1461,7 @@ public class TestConditionalMove { applyIf = {"UseVectorCmov", "false"}) @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_I, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) private static void testCMoveILEforF(int[] a, int[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -1476,7 +1476,7 @@ public class TestConditionalMove { @IR(failOn = {IRNode.STORE_VECTOR}) @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_I, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) private static void testCMoveIEQforD(int[] a, int[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { double cc = c[i]; @@ -1490,7 +1490,7 @@ public class TestConditionalMove { @IR(failOn = {IRNode.STORE_VECTOR}) @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_I, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) private static void testCMoveINEforD(int[] a, int[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { double cc = c[i]; @@ -1504,7 +1504,7 @@ public class TestConditionalMove { @IR(failOn = {IRNode.STORE_VECTOR}) @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_I, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) private static void testCMoveIGTforD(int[] a, int[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { double cc = c[i]; @@ -1518,7 +1518,7 @@ public class TestConditionalMove { @IR(failOn = {IRNode.STORE_VECTOR}) @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_I, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) private static void testCMoveIGEforD(int[] a, int[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { double cc = c[i]; @@ -1532,7 +1532,7 @@ public class TestConditionalMove { @IR(failOn = {IRNode.STORE_VECTOR}) @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_I, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) private static void testCMoveILTforD(int[] a, int[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { double cc = c[i]; @@ -1546,7 +1546,7 @@ public class TestConditionalMove { @IR(failOn = {IRNode.STORE_VECTOR}) @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_I, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) private static void testCMoveILEforD(int[] a, int[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { double cc = c[i]; @@ -1731,7 +1731,7 @@ public class TestConditionalMove { @IR(failOn = {IRNode.STORE_VECTOR}) @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_L, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) private static void testCMoveLEQforF(long[] a, long[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -1745,7 +1745,7 @@ public class TestConditionalMove { @IR(failOn = {IRNode.STORE_VECTOR}) @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_L, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) private static void testCMoveLNEforF(long[] a, long[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -1759,7 +1759,7 @@ public class TestConditionalMove { @IR(failOn = {IRNode.STORE_VECTOR}) @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_L, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) private static void testCMoveLGTforF(long[] a, long[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -1773,7 +1773,7 @@ public class TestConditionalMove { @IR(failOn = {IRNode.STORE_VECTOR}) @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_L, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) private static void testCMoveLGEforF(long[] a, long[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -1787,7 +1787,7 @@ public class TestConditionalMove { @IR(failOn = {IRNode.STORE_VECTOR}) @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_L, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) private static void testCMoveLLTforF(long[] a, long[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -1801,7 +1801,7 @@ public class TestConditionalMove { @IR(failOn = {IRNode.STORE_VECTOR}) @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_L, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) private static void testCMoveLLEforF(long[] a, long[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -1824,7 +1824,7 @@ public class TestConditionalMove { applyIf = {"UseVectorCmov", "false"}) @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_L, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) // Requires avx2, else L is restricted to 16 byte, and D has 32. That leads to a vector elements mismatch of 2 to 4. private static void testCMoveLEQforD(long[] a, long[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { @@ -1847,7 +1847,7 @@ public class TestConditionalMove { applyIf = {"UseVectorCmov", "false"}) @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_L, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) // Requires avx2, else L is restricted to 16 byte, and D has 32. That leads to a vector elements mismatch of 2 to 4. private static void testCMoveLNEforD(long[] a, long[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { @@ -1870,7 +1870,7 @@ public class TestConditionalMove { applyIf = {"UseVectorCmov", "false"}) @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_L, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) // Requires avx2, else L is restricted to 16 byte, and D has 32. That leads to a vector elements mismatch of 2 to 4. private static void testCMoveLGTforD(long[] a, long[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { @@ -1893,7 +1893,7 @@ public class TestConditionalMove { applyIf = {"UseVectorCmov", "false"}) @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_L, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) // Requires avx2, else L is restricted to 16 byte, and D has 32. That leads to a vector elements mismatch of 2 to 4. private static void testCMoveLGEforD(long[] a, long[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { @@ -1916,7 +1916,7 @@ public class TestConditionalMove { applyIf = {"UseVectorCmov", "false"}) @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_L, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) // Requires avx2, else L is restricted to 16 byte, and D has 32. That leads to a vector elements mismatch of 2 to 4. private static void testCMoveLLTforD(long[] a, long[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { @@ -1939,7 +1939,7 @@ public class TestConditionalMove { applyIf = {"UseVectorCmov", "false"}) @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_L, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) // Requires avx2, else L is restricted to 16 byte, and D has 32. That leads to a vector elements mismatch of 2 to 4. private static void testCMoveLLEforD(long[] a, long[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { @@ -2134,7 +2134,7 @@ public class TestConditionalMove { applyIf = {"UseVectorCmov", "false"}) @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_U, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) private static void testCMoveUIEQforF(int[] a, int[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -2156,7 +2156,7 @@ public class TestConditionalMove { applyIf = {"UseVectorCmov", "false"}) @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_U, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) private static void testCMoveUINEforF(int[] a, int[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -2178,7 +2178,7 @@ public class TestConditionalMove { applyIf = {"UseVectorCmov", "false"}) @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_U, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) private static void testCMoveUIGTforF(int[] a, int[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -2200,7 +2200,7 @@ public class TestConditionalMove { applyIf = {"UseVectorCmov", "false"}) @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_U, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) private static void testCMoveUIGEforF(int[] a, int[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -2222,7 +2222,7 @@ public class TestConditionalMove { applyIf = {"UseVectorCmov", "false"}) @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_U, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) private static void testCMoveUILTforF(int[] a, int[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -2244,7 +2244,7 @@ public class TestConditionalMove { applyIf = {"UseVectorCmov", "false"}) @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_U, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) private static void testCMoveUILEforF(int[] a, int[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -2259,7 +2259,7 @@ public class TestConditionalMove { @IR(failOn = {IRNode.STORE_VECTOR}) @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_U, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) private static void testCMoveUIEQforD(int[] a, int[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { double cc = c[i]; @@ -2273,7 +2273,7 @@ public class TestConditionalMove { @IR(failOn = {IRNode.STORE_VECTOR}) @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_U, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) private static void testCMoveUINEforD(int[] a, int[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { double cc = c[i]; @@ -2287,7 +2287,7 @@ public class TestConditionalMove { @IR(failOn = {IRNode.STORE_VECTOR}) @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_U, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) private static void testCMoveUIGTforD(int[] a, int[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { double cc = c[i]; @@ -2301,7 +2301,7 @@ public class TestConditionalMove { @IR(failOn = {IRNode.STORE_VECTOR}) @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_U, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) private static void testCMoveUIGEforD(int[] a, int[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { double cc = c[i]; @@ -2315,7 +2315,7 @@ public class TestConditionalMove { @IR(failOn = {IRNode.STORE_VECTOR}) @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_U, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) private static void testCMoveUILTforD(int[] a, int[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { double cc = c[i]; @@ -2329,7 +2329,7 @@ public class TestConditionalMove { @IR(failOn = {IRNode.STORE_VECTOR}) @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_U, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) private static void testCMoveUILEforD(int[] a, int[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { double cc = c[i]; @@ -2514,7 +2514,7 @@ public class TestConditionalMove { @IR(failOn = {IRNode.STORE_VECTOR}) @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_UL, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) private static void testCMoveULEQforF(long[] a, long[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -2528,7 +2528,7 @@ public class TestConditionalMove { @IR(failOn = {IRNode.STORE_VECTOR}) @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_UL, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) private static void testCMoveULNEforF(long[] a, long[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -2542,7 +2542,7 @@ public class TestConditionalMove { @IR(failOn = {IRNode.STORE_VECTOR}) @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_UL, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) private static void testCMoveULGTforF(long[] a, long[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -2556,7 +2556,7 @@ public class TestConditionalMove { @IR(failOn = {IRNode.STORE_VECTOR}) @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_UL, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) private static void testCMoveULGEforF(long[] a, long[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -2570,7 +2570,7 @@ public class TestConditionalMove { @IR(failOn = {IRNode.STORE_VECTOR}) @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_UL, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) private static void testCMoveULLTforF(long[] a, long[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -2584,7 +2584,7 @@ public class TestConditionalMove { @IR(failOn = {IRNode.STORE_VECTOR}) @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_UL, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) private static void testCMoveULLEforF(long[] a, long[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -2607,7 +2607,7 @@ public class TestConditionalMove { applyIf = {"UseVectorCmov", "false"}) @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_UL, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) // Requires avx2, else L is restricted to 16 byte, and D has 32. That leads to a vector elements mismatch of 2 to 4. private static void testCMoveULEQforD(long[] a, long[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { @@ -2630,7 +2630,7 @@ public class TestConditionalMove { applyIf = {"UseVectorCmov", "false"}) @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_UL, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) // Requires avx2, else L is restricted to 16 byte, and D has 32. That leads to a vector elements mismatch of 2 to 4. private static void testCMoveULNEforD(long[] a, long[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { @@ -2653,7 +2653,7 @@ public class TestConditionalMove { applyIf = {"UseVectorCmov", "false"}) @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_UL, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) // Requires avx2, else L is restricted to 16 byte, and D has 32. That leads to a vector elements mismatch of 2 to 4. private static void testCMoveULGTforD(long[] a, long[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { @@ -2676,7 +2676,7 @@ public class TestConditionalMove { applyIf = {"UseVectorCmov", "false"}) @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_UL, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) // Requires avx2, else L is restricted to 16 byte, and D has 32. That leads to a vector elements mismatch of 2 to 4. private static void testCMoveULGEforD(long[] a, long[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { @@ -2699,7 +2699,7 @@ public class TestConditionalMove { applyIf = {"UseVectorCmov", "false"}) @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_UL, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) // Requires avx2, else L is restricted to 16 byte, and D has 32. That leads to a vector elements mismatch of 2 to 4. private static void testCMoveULLTforD(long[] a, long[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { @@ -2722,7 +2722,7 @@ public class TestConditionalMove { applyIf = {"UseVectorCmov", "false"}) @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_UL, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) // Requires avx2, else L is restricted to 16 byte, and D has 32. That leads to a vector elements mismatch of 2 to 4. private static void testCMoveULLEforD(long[] a, long[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { @@ -2772,7 +2772,7 @@ public class TestConditionalMove { applyIf = {"UseVectorCmov", "false"}) @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_F, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) private static void testCMoveFGTforF(float[] a, float[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -2786,7 +2786,7 @@ public class TestConditionalMove { @IR(failOn = {IRNode.STORE_VECTOR}) @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_F, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) private static void testCMoveFGTforD(float[] a, float[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { double cc = c[i]; @@ -2828,7 +2828,7 @@ public class TestConditionalMove { @IR(failOn = {IRNode.STORE_VECTOR}) @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_D, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) private static void testCMoveDGTforF(double[] a, double[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -2849,7 +2849,7 @@ public class TestConditionalMove { applyIf = {"UseVectorCmov", "false"}) @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_D, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) private static void testCMoveDGTforD(double[] a, double[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { double cc = c[i]; @@ -2871,7 +2871,7 @@ public class TestConditionalMove { applyIf = {"UseVectorCmov", "false"}) @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_F, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) private static void testCMoveFGTforFCmpCon1(float a, float[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < b.length; i++) { float cc = c[i]; @@ -2892,7 +2892,7 @@ public class TestConditionalMove { applyIf = {"UseVectorCmov", "false"}) @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_F, ">0"}, applyIf = {"UseVectorCmov", "false"}, - applyIfPlatform = {"riscv64", "true"}) + applyIfPlatformOr = {"riscv64", "true", "x64", "true", "aarch64", "true"}) private static void testCMoveFGTforFCmpCon2(float[] a, float b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestFPComparison2.java b/test/hotspot/jtreg/compiler/c2/cmove/TestFPComparison2.java similarity index 91% rename from test/hotspot/jtreg/compiler/c2/irTests/TestFPComparison2.java rename to test/hotspot/jtreg/compiler/c2/cmove/TestFPComparison2.java index 8cf3f728666..dca1f964231 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/TestFPComparison2.java +++ b/test/hotspot/jtreg/compiler/c2/cmove/TestFPComparison2.java @@ -30,10 +30,9 @@ import java.util.List; * @test * @bug 8358892 8357551 * @summary The test is to trigger code path of BoolTest::ge/gt in C2_MacroAssembler::enc_cmove_cmp_fp - * @requires os.arch == "riscv64" * @requires vm.debug * @library /test/lib / - * @run driver compiler.c2.irTests.TestFPComparison2 + * @run driver ${test.main.class} */ public class TestFPComparison2 { static final double[] DOUBLES = new double[] { @@ -109,7 +108,8 @@ public class TestFPComparison2 { class Test_ge_1 { @Test - @IR(counts = {IRNode.CMOVE_I, "1"}) + @IR(counts = {IRNode.CMOVE_I, "1"}, + applyIfPlatformOr = {"riscv64", "true", "aarch64", "true"}) public static int test_float_BoolTest_ge_fixed_1_0(float x, float y) { // return 1 // when either x or y is NaN @@ -124,7 +124,8 @@ class Test_ge_1 { } @Test - @IR(counts = {IRNode.CMOVE_I, "1"}) + @IR(counts = {IRNode.CMOVE_I, "1"}, + applyIfPlatformOr = {"riscv64", "true", "aarch64", "true"}) public static int test_double_BoolTest_ge_fixed_1_0(double x, double y) { // return 1 // when either x or y is NaN @@ -139,7 +140,8 @@ class Test_ge_1 { } @Test - @IR(counts = {IRNode.CMOVE_I, "1"}) + @IR(counts = {IRNode.CMOVE_I, "1"}, + applyIfPlatformOr = {"riscv64", "true", "aarch64", "true"}) public static int test_float_BoolTest_ge_fixed_0_1(float x, float y) { return !(x <= y) ? 0 : 1; } @@ -149,7 +151,8 @@ class Test_ge_1 { } @Test - @IR(counts = {IRNode.CMOVE_I, "1"}) + @IR(counts = {IRNode.CMOVE_I, "1"}, + applyIfPlatformOr = {"riscv64", "true", "aarch64", "true"}) public static int test_double_BoolTest_ge_fixed_0_1(double x, double y) { return !(x <= y) ? 0 : 1; } @@ -159,7 +162,8 @@ class Test_ge_1 { } @Test - @IR(counts = {IRNode.CMOVE_I, "1"}) + @IR(counts = {IRNode.CMOVE_I, "1"}, + applyIfPlatformOr = {"riscv64", "true", "aarch64", "true"}) public static int test_float_BoolTest_ge_fixed_10_20(float x, float y) { return !(x <= y) ? 10 : 20; } @@ -169,7 +173,8 @@ class Test_ge_1 { } @Test - @IR(counts = {IRNode.CMOVE_I, "1"}) + @IR(counts = {IRNode.CMOVE_I, "1"}, + applyIfPlatformOr = {"riscv64", "true", "aarch64", "true"}) public static int test_double_BoolTest_ge_fixed_10_20(double x, double y) { return !(x <= y) ? 10 : 20; } @@ -179,7 +184,8 @@ class Test_ge_1 { } @Test - @IR(counts = {IRNode.CMOVE_I, "1"}) + @IR(counts = {IRNode.CMOVE_I, "1"}, + applyIfPlatformOr = {"riscv64", "true", "aarch64", "true"}) public static int test_float_BoolTest_ge_variable_results(float x, float y, int a, int b) { return !(x <= y) ? a : b; } @@ -189,7 +195,8 @@ class Test_ge_1 { } @Test - @IR(counts = {IRNode.CMOVE_I, "1"}) + @IR(counts = {IRNode.CMOVE_I, "1"}, + applyIfPlatformOr = {"riscv64", "true", "aarch64", "true"}) public static int test_double_BoolTest_ge_variable_results(double x, double y, int a, int b) { return !(x <= y) ? a : b; } @@ -338,7 +345,8 @@ class Test_ge_1 { class Test_ge_cmove_fp_1 { @Test - @IR(counts = {IRNode.CMOVE_F, "1"}) + @IR(counts = {IRNode.CMOVE_F, "1"}, + applyIfPlatformOr = {"riscv64", "true", "aarch64", "true"}) public static float test_float_BoolTest_ge_fixed_1_0(float x, float y) { // return 1 // when either x or y is NaN @@ -353,7 +361,8 @@ class Test_ge_cmove_fp_1 { } @Test - @IR(counts = {IRNode.CMOVE_F, "1"}) + @IR(counts = {IRNode.CMOVE_F, "1"}, + applyIfPlatformOr = {"riscv64", "true", "aarch64", "true"}) public static float test_double_BoolTest_ge_fixed_1_0(double x, double y) { // return 1 // when either x or y is NaN @@ -368,7 +377,8 @@ class Test_ge_cmove_fp_1 { } @Test - @IR(counts = {IRNode.CMOVE_F, "1"}) + @IR(counts = {IRNode.CMOVE_F, "1"}, + applyIfPlatformOr = {"riscv64", "true", "aarch64", "true"}) public static float test_float_BoolTest_ge_fixed_0_1(float x, float y) { return !(x <= y) ? 0.0f : 1.0f; } @@ -378,7 +388,8 @@ class Test_ge_cmove_fp_1 { } @Test - @IR(counts = {IRNode.CMOVE_F, "1"}) + @IR(counts = {IRNode.CMOVE_F, "1"}, + applyIfPlatformOr = {"riscv64", "true", "aarch64", "true"}) public static float test_double_BoolTest_ge_fixed_0_1(double x, double y) { return !(x <= y) ? 0.0f : 1.0f; } @@ -388,7 +399,8 @@ class Test_ge_cmove_fp_1 { } @Test - @IR(counts = {IRNode.CMOVE_F, "1"}) + @IR(counts = {IRNode.CMOVE_F, "1"}, + applyIfPlatformOr = {"riscv64", "true", "aarch64", "true"}) public static float test_float_BoolTest_ge_fixed_10_20(float x, float y) { return !(x <= y) ? 10.0f : 20.0f; } @@ -398,7 +410,8 @@ class Test_ge_cmove_fp_1 { } @Test - @IR(counts = {IRNode.CMOVE_F, "1"}) + @IR(counts = {IRNode.CMOVE_F, "1"}, + applyIfPlatformOr = {"riscv64", "true", "aarch64", "true"}) public static float test_double_BoolTest_ge_fixed_10_20(double x, double y) { return !(x <= y) ? 10.0f : 20.0f; } @@ -408,7 +421,8 @@ class Test_ge_cmove_fp_1 { } @Test - @IR(counts = {IRNode.CMOVE_F, "1"}) + @IR(counts = {IRNode.CMOVE_F, "1"}, + applyIfPlatformOr = {"riscv64", "true", "aarch64", "true"}) public static float test_float_BoolTest_ge_variable_results(float x, float y, float a, float b) { return !(x <= y) ? a : b; } @@ -418,7 +432,8 @@ class Test_ge_cmove_fp_1 { } @Test - @IR(counts = {IRNode.CMOVE_F, "1"}) + @IR(counts = {IRNode.CMOVE_F, "1"}, + applyIfPlatformOr = {"riscv64", "true", "aarch64", "true"}) public static float test_double_BoolTest_ge_variable_results(double x, double y, float a, float b) { return !(x <= y) ? a : b; } @@ -566,7 +581,8 @@ class Test_ge_cmove_fp_1 { class Test_ge_2 { @Test - @IR(counts = {IRNode.CMOVE_I, "1"}) + @IR(counts = {IRNode.CMOVE_I, "1"}, + applyIfPlatformOr = {"riscv64", "true", "aarch64", "true"}) public static int test_float_BoolTest_ge_fixed_1_0(float x, float y) { // return 1 // when either x or y is NaN @@ -581,7 +597,8 @@ class Test_ge_2 { } @Test - @IR(counts = {IRNode.CMOVE_I, "1"}) + @IR(counts = {IRNode.CMOVE_I, "1"}, + applyIfPlatformOr = {"riscv64", "true", "aarch64", "true"}) public static int test_double_BoolTest_ge_fixed_1_0(double x, double y) { // return 1 // when either x or y is NaN @@ -596,7 +613,8 @@ class Test_ge_2 { } @Test - @IR(counts = {IRNode.CMOVE_I, "1"}) + @IR(counts = {IRNode.CMOVE_I, "1"}, + applyIfPlatformOr = {"riscv64", "true", "aarch64", "true"}) public static int test_float_BoolTest_ge_fixed_0_1(float x, float y) { return !(x >= y) ? 0 : 1; } @@ -606,7 +624,8 @@ class Test_ge_2 { } @Test - @IR(counts = {IRNode.CMOVE_I, "1"}) + @IR(counts = {IRNode.CMOVE_I, "1"}, + applyIfPlatformOr = {"riscv64", "true", "aarch64", "true"}) public static int test_double_BoolTest_ge_fixed_0_1(double x, double y) { return !(x >= y) ? 0 : 1; } @@ -616,7 +635,8 @@ class Test_ge_2 { } @Test - @IR(counts = {IRNode.CMOVE_I, "1"}) + @IR(counts = {IRNode.CMOVE_I, "1"}, + applyIfPlatformOr = {"riscv64", "true", "aarch64", "true"}) public static int test_float_BoolTest_ge_fixed_10_20(float x, float y) { return !(x >= y) ? 10 : 20; } @@ -626,7 +646,8 @@ class Test_ge_2 { } @Test - @IR(counts = {IRNode.CMOVE_I, "1"}) + @IR(counts = {IRNode.CMOVE_I, "1"}, + applyIfPlatformOr = {"riscv64", "true", "aarch64", "true"}) public static int test_double_BoolTest_ge_fixed_10_20(double x, double y) { return !(x >= y) ? 10 : 20; } @@ -636,7 +657,8 @@ class Test_ge_2 { } @Test - @IR(counts = {IRNode.CMOVE_I, "1"}) + @IR(counts = {IRNode.CMOVE_I, "1"}, + applyIfPlatformOr = {"riscv64", "true", "aarch64", "true"}) public static int test_float_BoolTest_ge_variable_results(float x, float y, int a, int b) { return !(x >= y) ? a : b; } @@ -646,7 +668,8 @@ class Test_ge_2 { } @Test - @IR(counts = {IRNode.CMOVE_I, "1"}) + @IR(counts = {IRNode.CMOVE_I, "1"}, + applyIfPlatformOr = {"riscv64", "true", "aarch64", "true"}) public static int test_double_BoolTest_ge_variable_results(double x, double y, int a, int b) { return !(x >= y) ? a : b; } @@ -794,7 +817,8 @@ class Test_ge_2 { class Test_ge_cmove_fp_2 { @Test - @IR(counts = {IRNode.CMOVE_F, "1"}) + @IR(counts = {IRNode.CMOVE_F, "1"}, + applyIfPlatformOr = {"riscv64", "true", "aarch64", "true"}) public static float test_float_BoolTest_ge_fixed_1_0(float x, float y) { // return 1 // when either x or y is NaN @@ -809,7 +833,8 @@ class Test_ge_cmove_fp_2 { } @Test - @IR(counts = {IRNode.CMOVE_F, "1"}) + @IR(counts = {IRNode.CMOVE_F, "1"}, + applyIfPlatformOr = {"riscv64", "true", "aarch64", "true"}) public static float test_double_BoolTest_ge_fixed_1_0(double x, double y) { // return 1 // when either x or y is NaN @@ -824,7 +849,8 @@ class Test_ge_cmove_fp_2 { } @Test - @IR(counts = {IRNode.CMOVE_F, "1"}) + @IR(counts = {IRNode.CMOVE_F, "1"}, + applyIfPlatformOr = {"riscv64", "true", "aarch64", "true"}) public static float test_float_BoolTest_ge_fixed_0_1(float x, float y) { return !(x >= y) ? 0.0f : 1.0f; } @@ -834,7 +860,8 @@ class Test_ge_cmove_fp_2 { } @Test - @IR(counts = {IRNode.CMOVE_F, "1"}) + @IR(counts = {IRNode.CMOVE_F, "1"}, + applyIfPlatformOr = {"riscv64", "true", "aarch64", "true"}) public static float test_double_BoolTest_ge_fixed_0_1(double x, double y) { return !(x >= y) ? 0.0f : 1.0f; } @@ -844,7 +871,8 @@ class Test_ge_cmove_fp_2 { } @Test - @IR(counts = {IRNode.CMOVE_F, "1"}) + @IR(counts = {IRNode.CMOVE_F, "1"}, + applyIfPlatformOr = {"riscv64", "true", "aarch64", "true"}) public static float test_float_BoolTest_ge_fixed_10_20(float x, float y) { return !(x >= y) ? 10.0f : 20.0f; } @@ -854,7 +882,8 @@ class Test_ge_cmove_fp_2 { } @Test - @IR(counts = {IRNode.CMOVE_F, "1"}) + @IR(counts = {IRNode.CMOVE_F, "1"}, + applyIfPlatformOr = {"riscv64", "true", "aarch64", "true"}) public static float test_double_BoolTest_ge_fixed_10_20(double x, double y) { return !(x >= y) ? 10.0f : 20.0f; } @@ -864,7 +893,8 @@ class Test_ge_cmove_fp_2 { } @Test - @IR(counts = {IRNode.CMOVE_F, "1"}) + @IR(counts = {IRNode.CMOVE_F, "1"}, + applyIfPlatformOr = {"riscv64", "true", "aarch64", "true"}) public static float test_float_BoolTest_ge_variable_results(float x, float y, float a, float b) { return !(x >= y) ? a : b; } @@ -874,7 +904,8 @@ class Test_ge_cmove_fp_2 { } @Test - @IR(counts = {IRNode.CMOVE_F, "1"}) + @IR(counts = {IRNode.CMOVE_F, "1"}, + applyIfPlatformOr = {"riscv64", "true", "aarch64", "true"}) public static float test_double_BoolTest_ge_variable_results(double x, double y, float a, float b) { return !(x >= y) ? a : b; } @@ -1022,7 +1053,8 @@ class Test_ge_cmove_fp_2 { class Test_gt_1 { @Test - @IR(counts = {IRNode.CMOVE_I, "1"}) + @IR(counts = {IRNode.CMOVE_I, "1"}, + applyIfPlatformOr = {"riscv64", "true", "aarch64", "true"}) public static int test_float_BoolTest_gt_fixed_1_0(float x, float y) { // return 1 // when either x or y is NaN @@ -1037,7 +1069,8 @@ class Test_gt_1 { } @Test - @IR(counts = {IRNode.CMOVE_I, "1"}) + @IR(counts = {IRNode.CMOVE_I, "1"}, + applyIfPlatformOr = {"riscv64", "true", "aarch64", "true"}) public static int test_double_BoolTest_gt_fixed_1_0(double x, double y) { // return 1 // when either x or y is NaN @@ -1052,7 +1085,8 @@ class Test_gt_1 { } @Test - @IR(counts = {IRNode.CMOVE_I, "1"}) + @IR(counts = {IRNode.CMOVE_I, "1"}, + applyIfPlatformOr = {"riscv64", "true", "aarch64", "true"}) public static int test_float_BoolTest_gt_fixed_0_1(float x, float y) { return !(x < y) ? 0 : 1; } @@ -1062,7 +1096,8 @@ class Test_gt_1 { } @Test - @IR(counts = {IRNode.CMOVE_I, "1"}) + @IR(counts = {IRNode.CMOVE_I, "1"}, + applyIfPlatformOr = {"riscv64", "true", "aarch64", "true"}) public static int test_double_BoolTest_gt_fixed_0_1(double x, double y) { return !(x < y) ? 0 : 1; } @@ -1072,7 +1107,8 @@ class Test_gt_1 { } @Test - @IR(counts = {IRNode.CMOVE_I, "1"}) + @IR(counts = {IRNode.CMOVE_I, "1"}, + applyIfPlatformOr = {"riscv64", "true", "aarch64", "true"}) public static int test_float_BoolTest_gt_fixed_10_20(float x, float y) { return !(x < y) ? 10 : 20; } @@ -1082,7 +1118,8 @@ class Test_gt_1 { } @Test - @IR(counts = {IRNode.CMOVE_I, "1"}) + @IR(counts = {IRNode.CMOVE_I, "1"}, + applyIfPlatformOr = {"riscv64", "true", "aarch64", "true"}) public static int test_double_BoolTest_gt_fixed_10_20(double x, double y) { return !(x < y) ? 10 : 20; } @@ -1092,7 +1129,8 @@ class Test_gt_1 { } @Test - @IR(counts = {IRNode.CMOVE_I, "1"}) + @IR(counts = {IRNode.CMOVE_I, "1"}, + applyIfPlatformOr = {"riscv64", "true", "aarch64", "true"}) public static int test_float_BoolTest_gt_variable_results(float x, float y, int a, int b) { return !(x < y) ? a : b; } @@ -1102,7 +1140,8 @@ class Test_gt_1 { } @Test - @IR(counts = {IRNode.CMOVE_I, "1"}) + @IR(counts = {IRNode.CMOVE_I, "1"}, + applyIfPlatformOr = {"riscv64", "true", "aarch64", "true"}) public static int test_double_BoolTest_gt_variable_results(double x, double y, int a, int b) { return !(x < y) ? a : b; } @@ -1250,7 +1289,8 @@ class Test_gt_1 { class Test_gt_cmove_fp_1 { @Test - @IR(counts = {IRNode.CMOVE_F, "1"}) + @IR(counts = {IRNode.CMOVE_F, "1"}, + applyIfPlatformOr = {"riscv64", "true", "aarch64", "true"}) public static float test_float_BoolTest_gt_fixed_1_0(float x, float y) { // return 1 // when either x or y is NaN @@ -1265,7 +1305,8 @@ class Test_gt_cmove_fp_1 { } @Test - @IR(counts = {IRNode.CMOVE_F, "1"}) + @IR(counts = {IRNode.CMOVE_F, "1"}, + applyIfPlatformOr = {"riscv64", "true", "aarch64", "true"}) public static float test_double_BoolTest_gt_fixed_1_0(double x, double y) { // return 1 // when either x or y is NaN @@ -1280,7 +1321,8 @@ class Test_gt_cmove_fp_1 { } @Test - @IR(counts = {IRNode.CMOVE_F, "1"}) + @IR(counts = {IRNode.CMOVE_F, "1"}, + applyIfPlatformOr = {"riscv64", "true", "aarch64", "true"}) public static float test_float_BoolTest_gt_fixed_0_1(float x, float y) { return !(x < y) ? 0.0f : 1.0f; } @@ -1290,7 +1332,8 @@ class Test_gt_cmove_fp_1 { } @Test - @IR(counts = {IRNode.CMOVE_F, "1"}) + @IR(counts = {IRNode.CMOVE_F, "1"}, + applyIfPlatformOr = {"riscv64", "true", "aarch64", "true"}) public static float test_double_BoolTest_gt_fixed_0_1(double x, double y) { return !(x < y) ? 0.0f : 1.0f; } @@ -1300,7 +1343,8 @@ class Test_gt_cmove_fp_1 { } @Test - @IR(counts = {IRNode.CMOVE_F, "1"}) + @IR(counts = {IRNode.CMOVE_F, "1"}, + applyIfPlatformOr = {"riscv64", "true", "aarch64", "true"}) public static float test_float_BoolTest_gt_fixed_10_20(float x, float y) { return !(x < y) ? 10.0f : 20.0f; } @@ -1310,7 +1354,8 @@ class Test_gt_cmove_fp_1 { } @Test - @IR(counts = {IRNode.CMOVE_F, "1"}) + @IR(counts = {IRNode.CMOVE_F, "1"}, + applyIfPlatformOr = {"riscv64", "true", "aarch64", "true"}) public static float test_double_BoolTest_gt_fixed_10_20(double x, double y) { return !(x < y) ? 10.0f : 20.0f; } @@ -1320,7 +1365,8 @@ class Test_gt_cmove_fp_1 { } @Test - @IR(counts = {IRNode.CMOVE_F, "1"}) + @IR(counts = {IRNode.CMOVE_F, "1"}, + applyIfPlatformOr = {"riscv64", "true", "aarch64", "true"}) public static float test_float_BoolTest_gt_variable_results(float x, float y, float a, float b) { return !(x < y) ? a : b; } @@ -1330,7 +1376,8 @@ class Test_gt_cmove_fp_1 { } @Test - @IR(counts = {IRNode.CMOVE_F, "1"}) + @IR(counts = {IRNode.CMOVE_F, "1"}, + applyIfPlatformOr = {"riscv64", "true", "aarch64", "true"}) public static float test_double_BoolTest_gt_variable_results(double x, double y, float a, float b) { return !(x < y) ? a : b; } @@ -1478,7 +1525,8 @@ class Test_gt_cmove_fp_1 { class Test_gt_2 { @Test - @IR(counts = {IRNode.CMOVE_I, "1"}) + @IR(counts = {IRNode.CMOVE_I, "1"}, + applyIfPlatformOr = {"riscv64", "true", "aarch64", "true"}) public static int test_float_BoolTest_gt_fixed_1_0(float x, float y) { // return 1 // when either x or y is NaN @@ -1493,7 +1541,8 @@ class Test_gt_2 { } @Test - @IR(counts = {IRNode.CMOVE_I, "1"}) + @IR(counts = {IRNode.CMOVE_I, "1"}, + applyIfPlatformOr = {"riscv64", "true", "aarch64", "true"}) public static int test_double_BoolTest_gt_fixed_1_0(double x, double y) { // return 1 // when either x or y is NaN @@ -1508,7 +1557,8 @@ class Test_gt_2 { } @Test - @IR(counts = {IRNode.CMOVE_I, "1"}) + @IR(counts = {IRNode.CMOVE_I, "1"}, + applyIfPlatformOr = {"riscv64", "true", "aarch64", "true"}) public static int test_float_BoolTest_gt_fixed_0_1(float x, float y) { return !(x > y) ? 0 : 1; } @@ -1518,7 +1568,8 @@ class Test_gt_2 { } @Test - @IR(counts = {IRNode.CMOVE_I, "1"}) + @IR(counts = {IRNode.CMOVE_I, "1"}, + applyIfPlatformOr = {"riscv64", "true", "aarch64", "true"}) public static int test_double_BoolTest_gt_fixed_0_1(double x, double y) { return !(x > y) ? 0 : 1; } @@ -1528,7 +1579,8 @@ class Test_gt_2 { } @Test - @IR(counts = {IRNode.CMOVE_I, "1"}) + @IR(counts = {IRNode.CMOVE_I, "1"}, + applyIfPlatformOr = {"riscv64", "true", "aarch64", "true"}) public static int test_float_BoolTest_gt_fixed_10_20(float x, float y) { return !(x > y) ? 10 : 20; } @@ -1538,7 +1590,8 @@ class Test_gt_2 { } @Test - @IR(counts = {IRNode.CMOVE_I, "1"}) + @IR(counts = {IRNode.CMOVE_I, "1"}, + applyIfPlatformOr = {"riscv64", "true", "aarch64", "true"}) public static int test_double_BoolTest_gt_fixed_10_20(double x, double y) { return !(x > y) ? 10 : 20; } @@ -1548,7 +1601,8 @@ class Test_gt_2 { } @Test - @IR(counts = {IRNode.CMOVE_I, "1"}) + @IR(counts = {IRNode.CMOVE_I, "1"}, + applyIfPlatformOr = {"riscv64", "true", "aarch64", "true"}) public static int test_float_BoolTest_gt_variable_results(float x, float y, int a, int b) { return !(x > y) ? a : b; } @@ -1558,7 +1612,8 @@ class Test_gt_2 { } @Test - @IR(counts = {IRNode.CMOVE_I, "1"}) + @IR(counts = {IRNode.CMOVE_I, "1"}, + applyIfPlatformOr = {"riscv64", "true", "aarch64", "true"}) public static int test_double_BoolTest_gt_variable_results(double x, double y, int a, int b) { return !(x > y) ? a : b; } @@ -1706,7 +1761,8 @@ class Test_gt_2 { class Test_gt_cmove_fp_2 { @Test - @IR(counts = {IRNode.CMOVE_F, "1"}) + @IR(counts = {IRNode.CMOVE_F, "1"}, + applyIfPlatformOr = {"riscv64", "true", "aarch64", "true"}) public static float test_float_BoolTest_gt_fixed_1_0(float x, float y) { // return 1 // when either x or y is NaN @@ -1721,7 +1777,8 @@ class Test_gt_cmove_fp_2 { } @Test - @IR(counts = {IRNode.CMOVE_F, "1"}) + @IR(counts = {IRNode.CMOVE_F, "1"}, + applyIfPlatformOr = {"riscv64", "true", "aarch64", "true"}) public static float test_double_BoolTest_gt_fixed_1_0(double x, double y) { // return 1 // when either x or y is NaN @@ -1736,7 +1793,8 @@ class Test_gt_cmove_fp_2 { } @Test - @IR(counts = {IRNode.CMOVE_F, "1"}) + @IR(counts = {IRNode.CMOVE_F, "1"}, + applyIfPlatformOr = {"riscv64", "true", "aarch64", "true"}) public static float test_float_BoolTest_gt_fixed_0_1(float x, float y) { return !(x > y) ? 0.0f : 1.0f; } @@ -1746,7 +1804,8 @@ class Test_gt_cmove_fp_2 { } @Test - @IR(counts = {IRNode.CMOVE_F, "1"}) + @IR(counts = {IRNode.CMOVE_F, "1"}, + applyIfPlatformOr = {"riscv64", "true", "aarch64", "true"}) public static float test_double_BoolTest_gt_fixed_0_1(double x, double y) { return !(x > y) ? 0.0f : 1.0f; } @@ -1756,7 +1815,8 @@ class Test_gt_cmove_fp_2 { } @Test - @IR(counts = {IRNode.CMOVE_F, "1"}) + @IR(counts = {IRNode.CMOVE_F, "1"}, + applyIfPlatformOr = {"riscv64", "true", "aarch64", "true"}) public static float test_float_BoolTest_gt_fixed_10_20(float x, float y) { return !(x > y) ? 10.0f : 20.0f; } @@ -1766,7 +1826,8 @@ class Test_gt_cmove_fp_2 { } @Test - @IR(counts = {IRNode.CMOVE_F, "1"}) + @IR(counts = {IRNode.CMOVE_F, "1"}, + applyIfPlatformOr = {"riscv64", "true", "aarch64", "true"}) public static float test_double_BoolTest_gt_fixed_10_20(double x, double y) { return !(x > y) ? 10.0f : 20.0f; } @@ -1776,7 +1837,8 @@ class Test_gt_cmove_fp_2 { } @Test - @IR(counts = {IRNode.CMOVE_F, "1"}) + @IR(counts = {IRNode.CMOVE_F, "1"}, + applyIfPlatformOr = {"riscv64", "true", "aarch64", "true"}) public static float test_float_BoolTest_gt_variable_results(float x, float y, float a, float b) { return !(x > y) ? a : b; } @@ -1786,7 +1848,8 @@ class Test_gt_cmove_fp_2 { } @Test - @IR(counts = {IRNode.CMOVE_F, "1"}) + @IR(counts = {IRNode.CMOVE_F, "1"}, + applyIfPlatformOr = {"riscv64", "true", "aarch64", "true"}) public static float test_double_BoolTest_gt_variable_results(double x, double y, float a, float b) { return !(x > y) ? a : b; } @@ -1934,7 +1997,8 @@ class Test_gt_cmove_fp_2 { class Test_cmov_fp_cmp_fp_ge_3 { @Test - @IR(counts = {IRNode.CMOVE_F, "1"}) + @IR(counts = {IRNode.CMOVE_F, "1"}, + applyIfPlatformOr = {"riscv64", "true", "aarch64", "true"}) public static float test_float_BoolTest_gt_x_lt_0(float x) { return x < 0 ? 0 : x; } @@ -1944,7 +2008,8 @@ class Test_cmov_fp_cmp_fp_ge_3 { } @Test - @IR(counts = {IRNode.CMOVE_F, "1"}) + @IR(counts = {IRNode.CMOVE_F, "1"}, + applyIfPlatformOr = {"riscv64", "true", "aarch64", "true"}) public static float test_float_BoolTest_gt_x_gt_0(float x) { return x > 0 ? 0 : x; } @@ -1954,7 +2019,8 @@ class Test_cmov_fp_cmp_fp_ge_3 { } @Test - @IR(counts = {IRNode.CMOVE_F, "1"}) + @IR(counts = {IRNode.CMOVE_F, "1"}, + applyIfPlatformOr = {"riscv64", "true", "aarch64", "true"}) public static float test_float_BoolTest_gt_neg_x_lt_0(float x) { return !(x < 0) ? 0 : x; } @@ -1964,7 +2030,8 @@ class Test_cmov_fp_cmp_fp_ge_3 { } @Test - @IR(counts = {IRNode.CMOVE_F, "1"}) + @IR(counts = {IRNode.CMOVE_F, "1"}, + applyIfPlatformOr = {"riscv64", "true", "aarch64", "true"}) public static float test_float_BoolTest_gt_neg_x_gt_0(float x) { return !(x > 0) ? 0 : x; } @@ -2038,7 +2105,8 @@ class Test_cmov_fp_cmp_fp_ge_3 { class Test_cmov_fp_cmp_fp_ge_4 { @Test - @IR(counts = {IRNode.CMOVE_F, "1"}) + @IR(counts = {IRNode.CMOVE_F, "1"}, + applyIfPlatformOr = {"riscv64", "true", "aarch64", "true"}) public static float test_float_BoolTest_ge_x_le_0(float x) { return x <= 0 ? 0 : x; } @@ -2048,7 +2116,8 @@ class Test_cmov_fp_cmp_fp_ge_4 { } @Test - @IR(counts = {IRNode.CMOVE_F, "1"}) + @IR(counts = {IRNode.CMOVE_F, "1"}, + applyIfPlatformOr = {"riscv64", "true", "aarch64", "true"}) public static float test_float_BoolTest_ge_x_ge_0(float x) { return x >= 0 ? 0 : x; } @@ -2058,7 +2127,8 @@ class Test_cmov_fp_cmp_fp_ge_4 { } @Test - @IR(counts = {IRNode.CMOVE_F, "1"}) + @IR(counts = {IRNode.CMOVE_F, "1"}, + applyIfPlatformOr = {"riscv64", "true", "aarch64", "true"}) public static float test_float_BoolTest_ge_neg_x_le_0(float x) { return !(x <= 0) ? 0 : x; } @@ -2068,7 +2138,8 @@ class Test_cmov_fp_cmp_fp_ge_4 { } @Test - @IR(counts = {IRNode.CMOVE_F, "1"}) + @IR(counts = {IRNode.CMOVE_F, "1"}, + applyIfPlatformOr = {"riscv64", "true", "aarch64", "true"}) public static float test_float_BoolTest_ge_neg_x_ge_0(float x) { return !(x >= 0) ? 0 : x; } diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestScalarConditionalMoveCmpObj.java b/test/hotspot/jtreg/compiler/c2/cmove/TestScalarConditionalMoveCmpObj.java similarity index 99% rename from test/hotspot/jtreg/compiler/c2/irTests/TestScalarConditionalMoveCmpObj.java rename to test/hotspot/jtreg/compiler/c2/cmove/TestScalarConditionalMoveCmpObj.java index e332ac9e293..63d6f6fba7f 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/TestScalarConditionalMoveCmpObj.java +++ b/test/hotspot/jtreg/compiler/c2/cmove/TestScalarConditionalMoveCmpObj.java @@ -31,9 +31,8 @@ import jdk.test.lib.Utils; /* * @test * @summary Test conditional move + compare object. - * @requires vm.simpleArch == "riscv64" * @library /test/lib / - * @run driver compiler.c2.irTests.TestScalarConditionalMoveCmpObj + * @run driver ${test.main.class} */ public class TestScalarConditionalMoveCmpObj { From 180d8c1b57efb29f8f016843d66daca59bb5934f Mon Sep 17 00:00:00 2001 From: Daisuke Yamazaki Date: Fri, 12 Dec 2025 12:04:20 +0000 Subject: [PATCH 266/706] 8372746: Some httpserver files could benefit from some formatting cleanup Reviewed-by: jpai, mikael, michaelm, djelinski, dfuchs --- .../com/sun/net/httpserver/Authenticator.java | 14 +- .../net/httpserver/BasicAuthenticator.java | 34 +- .../com/sun/net/httpserver/Filter.java | 16 +- .../com/sun/net/httpserver/Headers.java | 14 +- .../com/sun/net/httpserver/HttpContext.java | 4 +- .../com/sun/net/httpserver/HttpExchange.java | 6 +- .../com/sun/net/httpserver/HttpHandler.java | 4 +- .../com/sun/net/httpserver/HttpServer.java | 10 +- .../sun/net/httpserver/HttpsConfigurator.java | 14 +- .../com/sun/net/httpserver/HttpsServer.java | 6 +- .../sun/net/httpserver/SimpleFileServer.java | 4 +- .../com/sun/net/httpserver/package-info.java | 33 +- .../httpserver/spi/HttpServerProvider.java | 4 +- .../sun/net/httpserver/AuthFilter.java | 32 +- .../net/httpserver/ChunkedInputStream.java | 40 +- .../net/httpserver/ChunkedOutputStream.java | 32 +- .../classes/sun/net/httpserver/Code.java | 4 +- .../sun/net/httpserver/ContextList.java | 34 +- .../httpserver/DefaultHttpServerProvider.java | 10 +- .../sun/net/httpserver/ExchangeImpl.java | 136 +++---- .../httpserver/FixedLengthInputStream.java | 20 +- .../httpserver/FixedLengthOutputStream.java | 18 +- .../sun/net/httpserver/HttpConnection.java | 46 +-- .../sun/net/httpserver/HttpContextImpl.java | 42 +-- .../classes/sun/net/httpserver/HttpError.java | 6 +- .../sun/net/httpserver/HttpExchangeImpl.java | 48 +-- .../sun/net/httpserver/HttpServerImpl.java | 40 +- .../sun/net/httpserver/HttpsExchangeImpl.java | 52 +-- .../sun/net/httpserver/HttpsServerImpl.java | 46 +-- .../net/httpserver/LeftOverInputStream.java | 34 +- .../classes/sun/net/httpserver/Request.java | 106 +++--- .../sun/net/httpserver/SSLStreams.java | 168 ++++----- .../sun/net/httpserver/ServerImpl.java | 342 +++++++++--------- .../httpserver/UndefLengthOutputStream.java | 16 +- .../net/httpserver/UnmodifiableHeaders.java | 22 +- .../simpleserver/FileServerHandler.java | 2 +- 36 files changed, 729 insertions(+), 730 deletions(-) diff --git a/src/jdk.httpserver/share/classes/com/sun/net/httpserver/Authenticator.java b/src/jdk.httpserver/share/classes/com/sun/net/httpserver/Authenticator.java index ddef30f0c5c..6bb97e0799a 100644 --- a/src/jdk.httpserver/share/classes/com/sun/net/httpserver/Authenticator.java +++ b/src/jdk.httpserver/share/classes/com/sun/net/httpserver/Authenticator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2025, 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 @@ -40,7 +40,7 @@ public abstract class Authenticator { /** * Constructor for subclasses to call. */ - protected Authenticator () { } + protected Authenticator() { } /** * Base class for return type from {@link #authenticate(HttpExchange)} method. @@ -50,7 +50,7 @@ public abstract class Authenticator { /** * Constructor for subclasses to call. */ - protected Result () {} + protected Result() {} } /** @@ -67,7 +67,7 @@ public abstract class Authenticator { * @param responseCode the response code to associate with this * {@code Failure} instance */ - public Failure (int responseCode) { + public Failure(int responseCode) { this.responseCode = responseCode; } @@ -94,7 +94,7 @@ public abstract class Authenticator { * * @param p the authenticated user you wish to set as {@code Principal} */ - public Success (HttpPrincipal p) { + public Success(HttpPrincipal p) { principal = p; } @@ -126,7 +126,7 @@ public abstract class Authenticator { * @param responseCode the response code to associate with this * {@code Retry} instance */ - public Retry (int responseCode) { + public Retry(int responseCode) { this.responseCode = responseCode; } @@ -158,5 +158,5 @@ public abstract class Authenticator { * @param exch the {@code HttpExchange} upon which authenticate is called * @return the result */ - public abstract Result authenticate (HttpExchange exch); + public abstract Result authenticate(HttpExchange exch); } diff --git a/src/jdk.httpserver/share/classes/com/sun/net/httpserver/BasicAuthenticator.java b/src/jdk.httpserver/share/classes/com/sun/net/httpserver/BasicAuthenticator.java index b2cf78dd992..8c306888370 100644 --- a/src/jdk.httpserver/share/classes/com/sun/net/httpserver/BasicAuthenticator.java +++ b/src/jdk.httpserver/share/classes/com/sun/net/httpserver/BasicAuthenticator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2025, 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,7 +35,7 @@ import static java.nio.charset.StandardCharsets.UTF_8; /** * BasicAuthenticator provides an implementation of HTTP Basic * authentication. It is an abstract class and must be extended - * to provide an implementation of {@link #checkCredentials(String,String)} + * to provide an implementation of {@link #checkCredentials(String, String)} * which is called to verify each incoming request. * * @since 1.6 @@ -104,34 +104,34 @@ public abstract class BasicAuthenticator extends Authenticator { * * @return the authenticator's realm string */ - public String getRealm () { + public String getRealm() { return realm; } - public Result authenticate (HttpExchange t) + public Result authenticate(HttpExchange t) { Headers rmap = t.getRequestHeaders(); /* * look for auth token */ - String auth = rmap.getFirst ("Authorization"); + String auth = rmap.getFirst("Authorization"); if (auth == null) { setAuthHeader(t); - return new Authenticator.Retry (401); + return new Authenticator.Retry(401); } - int sp = auth.indexOf (' '); + int sp = auth.indexOf(' '); if (sp == -1 || !auth.substring(0, sp).equalsIgnoreCase("Basic")) { - return new Authenticator.Failure (401); + return new Authenticator.Failure(401); } byte[] b = Base64.getDecoder().decode(auth.substring(sp+1)); - String userpass = new String (b, charset); - int colon = userpass.indexOf (':'); - String uname = userpass.substring (0, colon); - String pass = userpass.substring (colon+1); + String userpass = new String(b, charset); + int colon = userpass.indexOf(':'); + String uname = userpass.substring(0, colon); + String pass = userpass.substring(colon+1); - if (checkCredentials (uname, pass)) { - return new Authenticator.Success ( - new HttpPrincipal ( + if (checkCredentials(uname, pass)) { + return new Authenticator.Success( + new HttpPrincipal( uname, realm ) ); @@ -146,7 +146,7 @@ public abstract class BasicAuthenticator extends Authenticator { Headers map = t.getResponseHeaders(); var authString = "Basic realm=" + "\"" + realm + "\"" + (isUTF8 ? ", charset=\"UTF-8\"" : ""); - map.set ("WWW-Authenticate", authString); + map.set("WWW-Authenticate", authString); } /** @@ -159,6 +159,6 @@ public abstract class BasicAuthenticator extends Authenticator { * @param password the password from the request * @return {@code true} if the credentials are valid, {@code false} otherwise */ - public abstract boolean checkCredentials (String username, String password); + public abstract boolean checkCredentials(String username, String password); } diff --git a/src/jdk.httpserver/share/classes/com/sun/net/httpserver/Filter.java b/src/jdk.httpserver/share/classes/com/sun/net/httpserver/Filter.java index 7dacefcb59b..906e8448c54 100644 --- a/src/jdk.httpserver/share/classes/com/sun/net/httpserver/Filter.java +++ b/src/jdk.httpserver/share/classes/com/sun/net/httpserver/Filter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -53,7 +53,7 @@ public abstract class Filter { /** * Constructor for subclasses to call. */ - protected Filter () {} + protected Filter() {} /** * A chain of filters associated with a {@link HttpServer}. @@ -76,7 +76,7 @@ public abstract class Filter { * @param handler the {@link HttpHandler} that will be invoked after * the final {@code Filter} has finished */ - public Chain (List filters, HttpHandler handler) { + public Chain(List filters, HttpHandler handler) { iter = filters.listIterator(); this.handler = handler; } @@ -93,12 +93,12 @@ public abstract class Filter { * @throws IOException if an I/O error occurs * @throws NullPointerException if exchange is {@code null} */ - public void doFilter (HttpExchange exchange) throws IOException { + public void doFilter(HttpExchange exchange) throws IOException { if (!iter.hasNext()) { - handler.handle (exchange); + handler.handle(exchange); } else { Filter f = iter.next(); - f.doFilter (exchange, this); + f.doFilter(exchange, this); } } } @@ -135,14 +135,14 @@ public abstract class Filter { * must be rethrown again * @throws NullPointerException if either exchange or chain are {@code null} */ - public abstract void doFilter (HttpExchange exchange, Chain chain) + public abstract void doFilter(HttpExchange exchange, Chain chain) throws IOException; /** * Returns a short description of this {@code Filter}. * * @return a {@code String} describing the {@code Filter} */ - public abstract String description (); + public abstract String description(); /** * Returns a pre-processing {@code Filter} with the given description and diff --git a/src/jdk.httpserver/share/classes/com/sun/net/httpserver/Headers.java b/src/jdk.httpserver/share/classes/com/sun/net/httpserver/Headers.java index 7d11bd42c94..2decd48c806 100644 --- a/src/jdk.httpserver/share/classes/com/sun/net/httpserver/Headers.java +++ b/src/jdk.httpserver/share/classes/com/sun/net/httpserver/Headers.java @@ -62,9 +62,9 @@ import sun.net.httpserver.UnmodifiableHeaders; *

        *
      • {@link #getFirst(String)} returns a single valued header or the first * value of a multi-valued header. - *
      • {@link #add(String,String)} adds the given header value to the list + *
      • {@link #add(String, String)} adds the given header value to the list * for the given key. - *
      • {@link #set(String,String)} sets the given header field to the single + *
      • {@link #set(String, String)} sets the given header field to the single * value given overwriting any existing values in the value list. *
      * @@ -80,9 +80,9 @@ import sun.net.httpserver.UnmodifiableHeaders; * {@code null} keys will never be present in HTTP request or response headers. * @since 1.6 */ -public class Headers implements Map> { +public class Headers implements Map> { - HashMap> map; + HashMap> map; /** * Creates an empty instance of {@code Headers}. @@ -99,7 +99,7 @@ public class Headers implements Map> { * null. * @since 18 */ - public Headers(Map> headers) { + public Headers(Map> headers) { Objects.requireNonNull(headers); var h = headers.entrySet().stream() .collect(Collectors.toUnmodifiableMap( @@ -234,7 +234,7 @@ public class Headers implements Map> { List l = map.get(k); if (l == null) { l = new LinkedList<>(); - map.put(k,l); + map.put(k, l); } l.add(value); } @@ -372,7 +372,7 @@ public class Headers implements Map> { * null. * @since 18 */ - public static Headers of(Map> headers) { + public static Headers of(Map> headers) { return new UnmodifiableHeaders(new Headers(headers)); } } diff --git a/src/jdk.httpserver/share/classes/com/sun/net/httpserver/HttpContext.java b/src/jdk.httpserver/share/classes/com/sun/net/httpserver/HttpContext.java index 12529d88385..1c9e41e866c 100644 --- a/src/jdk.httpserver/share/classes/com/sun/net/httpserver/HttpContext.java +++ b/src/jdk.httpserver/share/classes/com/sun/net/httpserver/HttpContext.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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,7 +90,7 @@ public abstract class HttpContext { * * @return a {@code Map} containing the attributes of this context */ - public abstract Map getAttributes() ; + public abstract Map getAttributes() ; /** * Returns this context's {@link List} of {@linkplain Filter filters}. This diff --git a/src/jdk.httpserver/share/classes/com/sun/net/httpserver/HttpExchange.java b/src/jdk.httpserver/share/classes/com/sun/net/httpserver/HttpExchange.java index 7ea43c0418e..a56c20b53af 100644 --- a/src/jdk.httpserver/share/classes/com/sun/net/httpserver/HttpExchange.java +++ b/src/jdk.httpserver/share/classes/com/sun/net/httpserver/HttpExchange.java @@ -48,7 +48,7 @@ import java.net.URI; * should be closed. *
    • {@link #getResponseHeaders()} to set any response headers, except * content-length. - *
    • {@link #sendResponseHeaders(int,long)} to send the response headers. + *
    • {@link #sendResponseHeaders(int, long)} to send the response headers. * Must be called before next step. *
    • {@link #getResponseBody()} to get a {@link OutputStream} to * send the response body. When the response body has been written, the @@ -73,7 +73,7 @@ public abstract class HttpExchange implements AutoCloseable, Request { /* * Symbolic values for the responseLength parameter of - * sendResponseHeaders(int,long) + * sendResponseHeaders(int, long) */ /** @@ -163,7 +163,7 @@ public abstract class HttpExchange implements AutoCloseable, Request { /** * Returns a stream to which the response body must be - * written. {@link #sendResponseHeaders(int,long)}) must be called prior to + * written. {@link #sendResponseHeaders(int, long)}) must be called prior to * calling this method. Multiple calls to this method (for the same exchange) * will return the same stream. In order to correctly terminate each exchange, * the output stream must be closed, even if no response body is being sent. diff --git a/src/jdk.httpserver/share/classes/com/sun/net/httpserver/HttpHandler.java b/src/jdk.httpserver/share/classes/com/sun/net/httpserver/HttpHandler.java index 1f1fc129c9d..447001a4f53 100644 --- a/src/jdk.httpserver/share/classes/com/sun/net/httpserver/HttpHandler.java +++ b/src/jdk.httpserver/share/classes/com/sun/net/httpserver/HttpHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -44,5 +44,5 @@ public interface HttpHandler { * @throws NullPointerException if exchange is {@code null} * @throws IOException if an I/O error occurs */ - public abstract void handle (HttpExchange exchange) throws IOException; + public abstract void handle(HttpExchange exchange) throws IOException; } diff --git a/src/jdk.httpserver/share/classes/com/sun/net/httpserver/HttpServer.java b/src/jdk.httpserver/share/classes/com/sun/net/httpserver/HttpServer.java index 8ed0172690f..a0271fed146 100644 --- a/src/jdk.httpserver/share/classes/com/sun/net/httpserver/HttpServer.java +++ b/src/jdk.httpserver/share/classes/com/sun/net/httpserver/HttpServer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -44,7 +44,7 @@ import java.util.concurrent.Executor; * a root URI path which represents the location of the application or service * on this server. The mapping of a handler to a {@code HttpServer} is * encapsulated by a {@link HttpContext} object. HttpContexts are created by - * calling {@link #createContext(String,HttpHandler)}. + * calling {@link #createContext(String, HttpHandler)}. * Any request for which no handler can be found is rejected with a 404 response. * Management of threads can be done external to this object by providing a * {@link java.util.concurrent.Executor} object. If none is provided a default @@ -117,13 +117,13 @@ public abstract class HttpServer { * Creates a {@code HttpServer} instance which is initially not bound to any * local address/port. The {@code HttpServer} is acquired from the currently * installed {@link HttpServerProvider}. The server must be bound using - * {@link #bind(InetSocketAddress,int)} before it can be used. + * {@link #bind(InetSocketAddress, int)} before it can be used. * * @throws IOException if an I/O error occurs * @return an instance of {@code HttpServer} */ public static HttpServer create() throws IOException { - return create (null, 0); + return create(null, 0); } /** @@ -149,7 +149,7 @@ public abstract class HttpServer { public static HttpServer create(InetSocketAddress addr, int backlog) throws IOException { HttpServerProvider provider = HttpServerProvider.provider(); - return provider.createHttpServer (addr, backlog); + return provider.createHttpServer(addr, backlog); } /** diff --git a/src/jdk.httpserver/share/classes/com/sun/net/httpserver/HttpsConfigurator.java b/src/jdk.httpserver/share/classes/com/sun/net/httpserver/HttpsConfigurator.java index 8cd9e3affa2..7f329e02f47 100644 --- a/src/jdk.httpserver/share/classes/com/sun/net/httpserver/HttpsConfigurator.java +++ b/src/jdk.httpserver/share/classes/com/sun/net/httpserver/HttpsConfigurator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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,11 +38,11 @@ import javax.net.ssl.SSLParameters; *

      The following example shows how this may be done: * *

      - * SSLContext sslContext = SSLContext.getInstance (....);
      + * SSLContext sslContext = SSLContext.getInstance(....);
        * HttpsServer server = HttpsServer.create();
        *
      - * server.setHttpsConfigurator (new HttpsConfigurator(sslContext) {
      - *     public void configure (HttpsParameters params) {
      + * server.setHttpsConfigurator(new HttpsConfigurator(sslContext) {
      + *     public void configure(HttpsParameters params) {
        *
        *         // get the remote address if needed
        *         InetSocketAddress remote = params.getClientAddress();
      @@ -51,7 +51,7 @@ import javax.net.ssl.SSLParameters;
        *
        *         // get the default parameters
        *         SSLParameters sslparams = c.getDefaultSSLParameters();
      - *         if (remote.equals (...) ) {
      + *         if (remote.equals(...)) {
        *             // modify the default set for client x
        *         }
        *
      @@ -74,7 +74,7 @@ public class HttpsConfigurator {
            */
           public HttpsConfigurator(SSLContext context) {
               if (context == null) {
      -            throw new NullPointerException ("null SSLContext");
      +            throw new NullPointerException("null SSLContext");
               }
               this.context = context;
           }
      @@ -107,6 +107,6 @@ public class HttpsConfigurator {
           * @since 1.6
           */
           public void configure(HttpsParameters params) {
      -        params.setSSLParameters (getSSLContext().getDefaultSSLParameters());
      +        params.setSSLParameters(getSSLContext().getDefaultSSLParameters());
           }
       }
      diff --git a/src/jdk.httpserver/share/classes/com/sun/net/httpserver/HttpsServer.java b/src/jdk.httpserver/share/classes/com/sun/net/httpserver/HttpsServer.java
      index 7b3dafd5582..192b8c3d697 100644
      --- a/src/jdk.httpserver/share/classes/com/sun/net/httpserver/HttpsServer.java
      +++ b/src/jdk.httpserver/share/classes/com/sun/net/httpserver/HttpsServer.java
      @@ -1,5 +1,5 @@
       /*
      - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved.
      + * Copyright (c) 2005, 2025, 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
      @@ -57,7 +57,7 @@ public abstract class HttpsServer extends HttpServer {
            * Creates a {@code HttpsServer} instance which is initially not bound to any
            * local address/port. The {@code HttpsServer} is acquired from the currently
            * installed {@link HttpServerProvider}. The server must be bound using
      -     * {@link #bind(InetSocketAddress,int)} before it can be used. The server
      +     * {@link #bind(InetSocketAddress, int)} before it can be used. The server
            * must also have a {@code HttpsConfigurator} established with
            * {@link #setHttpsConfigurator(HttpsConfigurator)}.
            *
      @@ -80,7 +80,7 @@ public abstract class HttpsServer extends HttpServer {
            * established with {@link #setHttpsConfigurator(HttpsConfigurator)}.
            *
            * @param addr the address to listen on, if {@code null} then
      -     *             {@link #bind(InetSocketAddress,int)} must be called to set
      +     *             {@link #bind(InetSocketAddress, int)} must be called to set
            *             the address
            * @param backlog the socket backlog. If this value is less than or equal to
            *               zero, then a system default value is used.
      diff --git a/src/jdk.httpserver/share/classes/com/sun/net/httpserver/SimpleFileServer.java b/src/jdk.httpserver/share/classes/com/sun/net/httpserver/SimpleFileServer.java
      index 551f24d3cf0..ba93b81db5a 100644
      --- a/src/jdk.httpserver/share/classes/com/sun/net/httpserver/SimpleFileServer.java
      +++ b/src/jdk.httpserver/share/classes/com/sun/net/httpserver/SimpleFileServer.java
      @@ -1,5 +1,5 @@
       /*
      - * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved.
      + * Copyright (c) 2021, 2025, 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,7 +55,7 @@ import sun.net.httpserver.simpleserver.OutputFilter;
        *
        * 

      Simple file server

      * - *

      The {@link #createFileServer(InetSocketAddress,Path,OutputLevel) createFileServer} + *

      The {@link #createFileServer(InetSocketAddress, Path, OutputLevel) createFileServer} * static factory method returns an {@link HttpServer HttpServer} that is a * simple out-of-the-box file server. The server comes with an initial handler * that serves files from a given directory path (and its subdirectories). diff --git a/src/jdk.httpserver/share/classes/com/sun/net/httpserver/package-info.java b/src/jdk.httpserver/share/classes/com/sun/net/httpserver/package-info.java index 3b9de3520fb..466b76a6c4a 100644 --- a/src/jdk.httpserver/share/classes/com/sun/net/httpserver/package-info.java +++ b/src/jdk.httpserver/share/classes/com/sun/net/httpserver/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -117,26 +117,25 @@ The following code shows how the SSLContext is then used in a HttpsConfigurator and how the SSLContext and HttpsConfigurator are linked to the HttpsServer.

      -    server.setHttpsConfigurator (new HttpsConfigurator(sslContext) {
      -        public void configure (HttpsParameters params) {
      +   server.setHttpsConfigurator(new HttpsConfigurator(sslContext) {
      +       public void configure(HttpsParameters params) {
       
      -        // get the remote address if needed
      -        InetSocketAddress remote = params.getClientAddress();
      +           // get the remote address if needed
      +           InetSocketAddress remote = params.getClientAddress();
       
      -        SSLContext c = getSSLContext();
      +           SSLContext c = getSSLContext();
       
      -        // get the default parameters
      -        SSLParameters sslparams = c.getDefaultSSLParameters();
      -        if (remote.equals (...) ) {
      -            // modify the default set for client x
      -        }
      +           // get the default parameters
      +           SSLParameters sslparams = c.getDefaultSSLParameters();
      +           if (remote.equals(...)) {
      +               // modify the default set for client x
      +           }
       
      -        params.setSSLParameters(sslparams);
      -        // statement above could throw IAE if any params invalid.
      -        // eg. if app has a UI and parameters supplied by a user.
      -
      -        }
      -    });
      +           params.setSSLParameters(sslparams);
      +           // statement above could throw IAE if any params invalid.
      +           // eg. if app has a UI and parameters supplied by a user.
      +       }
      +   });
          
      @since 1.6 */ diff --git a/src/jdk.httpserver/share/classes/com/sun/net/httpserver/spi/HttpServerProvider.java b/src/jdk.httpserver/share/classes/com/sun/net/httpserver/spi/HttpServerProvider.java index d025e90cf87..9d73f0e7340 100644 --- a/src/jdk.httpserver/share/classes/com/sun/net/httpserver/spi/HttpServerProvider.java +++ b/src/jdk.httpserver/share/classes/com/sun/net/httpserver/spi/HttpServerProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -152,7 +152,7 @@ public abstract class HttpServerProvider { * * @return The system-wide default HttpServerProvider */ - public static HttpServerProvider provider () { + public static HttpServerProvider provider() { synchronized (lock) { if (provider != null) return provider; diff --git a/src/jdk.httpserver/share/classes/sun/net/httpserver/AuthFilter.java b/src/jdk.httpserver/share/classes/sun/net/httpserver/AuthFilter.java index 468fa19fe16..4641325af92 100644 --- a/src/jdk.httpserver/share/classes/sun/net/httpserver/AuthFilter.java +++ b/src/jdk.httpserver/share/classes/sun/net/httpserver/AuthFilter.java @@ -33,48 +33,48 @@ public class AuthFilter extends Filter { private Authenticator authenticator; - public AuthFilter (Authenticator authenticator) { + public AuthFilter(Authenticator authenticator) { this.authenticator = authenticator; } - public String description () { + public String description() { return "Authentication filter"; } - public void setAuthenticator (Authenticator a) { + public void setAuthenticator(Authenticator a) { authenticator = a; } - public void consumeInput (HttpExchange t) throws IOException { + public void consumeInput(HttpExchange t) throws IOException { InputStream i = t.getRequestBody(); byte[] b = new byte [4096]; - while (i.read (b) != -1); - i.close (); + while (i.read(b) != -1); + i.close(); } /** * The filter's implementation, which is invoked by the server */ - public void doFilter (HttpExchange t, Filter.Chain chain) throws IOException + public void doFilter(HttpExchange t, Filter.Chain chain) throws IOException { if (authenticator != null) { - Authenticator.Result r = authenticator.authenticate (t); + Authenticator.Result r = authenticator.authenticate(t); if (r instanceof Authenticator.Success) { Authenticator.Success s = (Authenticator.Success)r; - ExchangeImpl e = ExchangeImpl.get (t); - e.setPrincipal (s.getPrincipal()); - chain.doFilter (t); + ExchangeImpl e = ExchangeImpl.get(t); + e.setPrincipal(s.getPrincipal()); + chain.doFilter(t); } else if (r instanceof Authenticator.Retry) { Authenticator.Retry ry = (Authenticator.Retry)r; - consumeInput (t); - t.sendResponseHeaders (ry.getResponseCode(), RSPBODY_EMPTY); + consumeInput(t); + t.sendResponseHeaders(ry.getResponseCode(), RSPBODY_EMPTY); } else if (r instanceof Authenticator.Failure) { Authenticator.Failure f = (Authenticator.Failure)r; - consumeInput (t); - t.sendResponseHeaders (f.getResponseCode(), RSPBODY_EMPTY); + consumeInput(t); + t.sendResponseHeaders(f.getResponseCode(), RSPBODY_EMPTY); } } else { - chain.doFilter (t); + chain.doFilter(t); } } } diff --git a/src/jdk.httpserver/share/classes/sun/net/httpserver/ChunkedInputStream.java b/src/jdk.httpserver/share/classes/sun/net/httpserver/ChunkedInputStream.java index 34ac72e1fee..0c003378d77 100644 --- a/src/jdk.httpserver/share/classes/sun/net/httpserver/ChunkedInputStream.java +++ b/src/jdk.httpserver/share/classes/sun/net/httpserver/ChunkedInputStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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,7 +31,7 @@ import com.sun.net.httpserver.*; import com.sun.net.httpserver.spi.*; class ChunkedInputStream extends LeftOverInputStream { - ChunkedInputStream (ExchangeImpl t, InputStream src) { + ChunkedInputStream(ExchangeImpl t, InputStream src) { super (t, src); } @@ -48,7 +48,7 @@ class ChunkedInputStream extends LeftOverInputStream { */ private static final int MAX_CHUNK_HEADER_SIZE = 2050; - private int numeric (char[] arr, int nchars) throws IOException { + private int numeric(char[] arr, int nchars) throws IOException { assert arr.length >= nchars; int len = 0; for (int i=0; i='A' && c<= 'F') { val = c - 'A' + 10; } else { - throw new IOException ("invalid chunk length"); + throw new IOException("invalid chunk length"); } len = len * 16 + val; } @@ -71,10 +71,10 @@ class ChunkedInputStream extends LeftOverInputStream { /* read the chunk header line and return the chunk length * any chunk extensions are ignored */ - private int readChunkHeader () throws IOException { + private int readChunkHeader() throws IOException { boolean gotCR = false; int c; - char[] len_arr = new char [16]; + char[] len_arr = new char[16]; int len_size = 0; boolean end_of_len = false; int read = 0; @@ -85,11 +85,11 @@ class ChunkedInputStream extends LeftOverInputStream { if ((len_size == len_arr.length -1) || (read > MAX_CHUNK_HEADER_SIZE)) { - throw new IOException ("invalid chunk header"); + throw new IOException("invalid chunk header"); } if (gotCR) { if (ch == LF) { - int l = numeric (len_arr, len_size); + int l = numeric(len_arr, len_size); return l; } else { gotCR = false; @@ -107,10 +107,10 @@ class ChunkedInputStream extends LeftOverInputStream { } } } - throw new IOException ("end of stream reading chunk header"); + throw new IOException("end of stream reading chunk header"); } - protected int readImpl (byte[]b, int off, int len) throws IOException { + protected int readImpl(byte[] b, int off, int len) throws IOException { if (eof) { return -1; } @@ -119,7 +119,7 @@ class ChunkedInputStream extends LeftOverInputStream { if (remaining == 0) { eof = true; consumeCRLF(); - t.getServerImpl().requestCompleted (t.getConnection()); + t.getServerImpl().requestCompleted(t.getConnection()); return -1; } needToReadHeader = false; @@ -140,15 +140,15 @@ class ChunkedInputStream extends LeftOverInputStream { return n; } - private void consumeCRLF () throws IOException { + private void consumeCRLF() throws IOException { char c; c = (char)in.read(); /* CR */ if (c != CR) { - throw new IOException ("invalid chunk end"); + throw new IOException("invalid chunk end"); } c = (char)in.read(); /* LF */ if (c != LF) { - throw new IOException ("invalid chunk end"); + throw new IOException("invalid chunk end"); } } @@ -158,7 +158,7 @@ class ChunkedInputStream extends LeftOverInputStream { * limitation for the moment. It only affects potential efficiency * rather than correctness. */ - public int available () throws IOException { + public int available() throws IOException { if (eof || closed) { return 0; } @@ -170,17 +170,17 @@ class ChunkedInputStream extends LeftOverInputStream { * have been read from the underlying channel * and buffered internally */ - public boolean isDataBuffered () throws IOException { + public boolean isDataBuffered() throws IOException { assert eof; return in.available() > 0; } - public boolean markSupported () {return false;} + public boolean markSupported() {return false;} - public void mark (int l) { + public void mark(int l) { } - public void reset () throws IOException { - throw new IOException ("mark/reset not supported"); + public void reset() throws IOException { + throw new IOException("mark/reset not supported"); } } diff --git a/src/jdk.httpserver/share/classes/sun/net/httpserver/ChunkedOutputStream.java b/src/jdk.httpserver/share/classes/sun/net/httpserver/ChunkedOutputStream.java index e8e84eb8edd..fd1a940c0a5 100644 --- a/src/jdk.httpserver/share/classes/sun/net/httpserver/ChunkedOutputStream.java +++ b/src/jdk.httpserver/share/classes/sun/net/httpserver/ChunkedOutputStream.java @@ -57,14 +57,14 @@ class ChunkedOutputStream extends FilterOutputStream private byte[] buf = new byte [CHUNK_SIZE+OFFSET+2]; ExchangeImpl t; - ChunkedOutputStream (ExchangeImpl t, OutputStream src) { - super (src); + ChunkedOutputStream(ExchangeImpl t, OutputStream src) { + super(src); this.t = t; } - public void write (int b) throws IOException { + public void write(int b) throws IOException { if (closed) { - throw new StreamClosedException (); + throw new StreamClosedException(); } buf [pos++] = (byte)b; count ++; @@ -74,23 +74,23 @@ class ChunkedOutputStream extends FilterOutputStream assert count < CHUNK_SIZE; } - public void write (byte[]b, int off, int len) throws IOException { + public void write(byte[] b, int off, int len) throws IOException { Objects.checkFromIndexSize(off, len, b.length); if (len == 0) { return; } if (closed) { - throw new StreamClosedException (); + throw new StreamClosedException(); } int remain = CHUNK_SIZE - count; if (len > remain) { - System.arraycopy (b,off,buf,pos,remain); + System.arraycopy(b, off, buf, pos, remain); count = CHUNK_SIZE; writeChunk(); len -= remain; off += remain; while (len >= CHUNK_SIZE) { - System.arraycopy (b,off,buf,OFFSET,CHUNK_SIZE); + System.arraycopy(b, off, buf, OFFSET, CHUNK_SIZE); len -= CHUNK_SIZE; off += CHUNK_SIZE; count = CHUNK_SIZE; @@ -98,7 +98,7 @@ class ChunkedOutputStream extends FilterOutputStream } } if (len > 0) { - System.arraycopy (b,off,buf,pos,len); + System.arraycopy(b, off, buf, pos, len); count += len; pos += len; } @@ -112,8 +112,8 @@ class ChunkedOutputStream extends FilterOutputStream * chunk does not have to be CHUNK_SIZE bytes * count must == number of user bytes (<= CHUNK_SIZE) */ - private void writeChunk () throws IOException { - char[] c = Integer.toHexString (count).toCharArray(); + private void writeChunk() throws IOException { + char[] c = Integer.toHexString(count).toCharArray(); int clen = c.length; int startByte = 4 - clen; int i; @@ -124,12 +124,12 @@ class ChunkedOutputStream extends FilterOutputStream buf[startByte + (i++)] = '\n'; buf[startByte + (i++) + count] = '\r'; buf[startByte + (i++) + count] = '\n'; - out.write (buf, startByte, i+count); + out.write(buf, startByte, i+count); count = 0; pos = OFFSET; } - public void close () throws IOException { + public void close() throws IOException { if (closed) { return; } @@ -156,12 +156,12 @@ class ChunkedOutputStream extends FilterOutputStream } Event e = new Event.WriteFinished(t); - t.getHttpContext().getServerImpl().addEvent (e); + t.getHttpContext().getServerImpl().addEvent(e); } - public void flush () throws IOException { + public void flush() throws IOException { if (closed) { - throw new StreamClosedException (); + throw new StreamClosedException(); } if (count > 0) { writeChunk(); diff --git a/src/jdk.httpserver/share/classes/sun/net/httpserver/Code.java b/src/jdk.httpserver/share/classes/sun/net/httpserver/Code.java index 6b86b8fa5bd..c5391343f96 100644 --- a/src/jdk.httpserver/share/classes/sun/net/httpserver/Code.java +++ b/src/jdk.httpserver/share/classes/sun/net/httpserver/Code.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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,7 +64,7 @@ class Code { public static final int HTTP_GATEWAY_TIMEOUT = 504; public static final int HTTP_VERSION = 505; - static String msg (int code) { + static String msg(int code) { switch (code) { case HTTP_OK: return " OK"; diff --git a/src/jdk.httpserver/share/classes/sun/net/httpserver/ContextList.java b/src/jdk.httpserver/share/classes/sun/net/httpserver/ContextList.java index cbedb6ca860..96b55575928 100644 --- a/src/jdk.httpserver/share/classes/sun/net/httpserver/ContextList.java +++ b/src/jdk.httpserver/share/classes/sun/net/httpserver/ContextList.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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,30 +31,30 @@ class ContextList { private final LinkedList list = new LinkedList<>(); - public synchronized void add (HttpContextImpl ctx) { + public synchronized void add(HttpContextImpl ctx) { assert ctx.getPath() != null; if (contains(ctx)) { - throw new IllegalArgumentException ("cannot add context to list"); + throw new IllegalArgumentException("cannot add context to list"); } - list.add (ctx); + list.add(ctx); } boolean contains(HttpContextImpl ctx) { return findContext(ctx.getProtocol(), ctx.getPath(), true) != null; } - public synchronized int size () { + public synchronized int size() { return list.size(); } /* initially contexts are located only by protocol:path. * Context with longest prefix matches (currently case-sensitive) */ - synchronized HttpContextImpl findContext (String protocol, String path) { - return findContext (protocol, path, false); + synchronized HttpContextImpl findContext(String protocol, String path) { + return findContext(protocol, path, false); } - synchronized HttpContextImpl findContext (String protocol, String path, boolean exact) { + synchronized HttpContextImpl findContext(String protocol, String path, boolean exact) { protocol = protocol.toLowerCase(Locale.ROOT); String longest = ""; HttpContextImpl lc = null; @@ -63,7 +63,7 @@ class ContextList { continue; } String cpath = ctx.getPath(); - if (exact && !cpath.equals (path)) { + if (exact && !cpath.equals(path)) { continue; } else if (!exact && !path.startsWith(cpath)) { continue; @@ -76,25 +76,25 @@ class ContextList { return lc; } - public synchronized void remove (String protocol, String path) + public synchronized void remove(String protocol, String path) throws IllegalArgumentException { - HttpContextImpl ctx = findContext (protocol, path, true); + HttpContextImpl ctx = findContext(protocol, path, true); if (ctx == null) { - throw new IllegalArgumentException ("cannot remove element from list"); + throw new IllegalArgumentException("cannot remove element from list"); } - list.remove (ctx); + list.remove(ctx); } - public synchronized void remove (HttpContextImpl context) + public synchronized void remove(HttpContextImpl context) throws IllegalArgumentException { for (HttpContextImpl ctx: list) { - if (ctx.equals (context)) { - list.remove (ctx); + if (ctx.equals(context)) { + list.remove(ctx); return; } } - throw new IllegalArgumentException ("no such context in list"); + throw new IllegalArgumentException("no such context in list"); } } diff --git a/src/jdk.httpserver/share/classes/sun/net/httpserver/DefaultHttpServerProvider.java b/src/jdk.httpserver/share/classes/sun/net/httpserver/DefaultHttpServerProvider.java index fe746befb9f..7b54ef45e72 100644 --- a/src/jdk.httpserver/share/classes/sun/net/httpserver/DefaultHttpServerProvider.java +++ b/src/jdk.httpserver/share/classes/sun/net/httpserver/DefaultHttpServerProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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,11 +31,11 @@ import com.sun.net.httpserver.*; import com.sun.net.httpserver.spi.*; public class DefaultHttpServerProvider extends HttpServerProvider { - public HttpServer createHttpServer (InetSocketAddress addr, int backlog) throws IOException { - return new HttpServerImpl (addr, backlog); + public HttpServer createHttpServer(InetSocketAddress addr, int backlog) throws IOException { + return new HttpServerImpl(addr, backlog); } - public HttpsServer createHttpsServer (InetSocketAddress addr, int backlog) throws IOException { - return new HttpsServerImpl (addr, backlog); + public HttpsServer createHttpsServer(InetSocketAddress addr, int backlog) throws IOException { + return new HttpsServerImpl(addr, backlog); } } diff --git a/src/jdk.httpserver/share/classes/sun/net/httpserver/ExchangeImpl.java b/src/jdk.httpserver/share/classes/sun/net/httpserver/ExchangeImpl.java index 17dff13d4e5..8da98cdcfa5 100644 --- a/src/jdk.httpserver/share/classes/sun/net/httpserver/ExchangeImpl.java +++ b/src/jdk.httpserver/share/classes/sun/net/httpserver/ExchangeImpl.java @@ -82,12 +82,12 @@ class ExchangeImpl { PlaceholderOutputStream uos_orig; boolean sentHeaders; /* true after response headers sent */ - final Map attributes; + final Map attributes; int rcode = -1; HttpPrincipal principal; ServerImpl server; - ExchangeImpl ( + ExchangeImpl( String m, URI u, Request req, long len, HttpConnection connection ) throws IOException { this.req = req; @@ -107,23 +107,23 @@ class ExchangeImpl { server.startExchange(); } - public Headers getRequestHeaders () { + public Headers getRequestHeaders() { return reqHdrs; } - public Headers getResponseHeaders () { + public Headers getResponseHeaders() { return rspHdrs; } - public URI getRequestURI () { + public URI getRequestURI() { return uri; } - public String getRequestMethod (){ + public String getRequestMethod() { return method; } - public HttpContextImpl getHttpContext (){ + public HttpContextImpl getHttpContext() { return connection.getHttpContext(); } @@ -131,7 +131,7 @@ class ExchangeImpl { return HEAD.equals(getRequestMethod()); } - public void close () { + public void close() { if (closed) { return; } @@ -160,38 +160,38 @@ class ExchangeImpl { } } - public InputStream getRequestBody () { + public InputStream getRequestBody() { if (uis != null) { return uis; } if (reqContentLen == -1L) { - uis_orig = new ChunkedInputStream (this, ris); + uis_orig = new ChunkedInputStream(this, ris); uis = uis_orig; } else { - uis_orig = new FixedLengthInputStream (this, ris, reqContentLen); + uis_orig = new FixedLengthInputStream(this, ris, reqContentLen); uis = uis_orig; } return uis; } - LeftOverInputStream getOriginalInputStream () { + LeftOverInputStream getOriginalInputStream() { return uis_orig; } - public int getResponseCode () { + public int getResponseCode() { return rcode; } - public OutputStream getResponseBody () { + public OutputStream getResponseBody() { /* TODO. Change spec to remove restriction below. Filters * cannot work with this restriction * * if (!sentHeaders) { - * throw new IllegalStateException ("headers not sent"); + * throw new IllegalStateException("headers not sent"); * } */ if (uos == null) { - uos_orig = new PlaceholderOutputStream (null); + uos_orig = new PlaceholderOutputStream(null); uos = uos_orig; } return uos; @@ -202,37 +202,37 @@ class ExchangeImpl { * returned from the 1st call to getResponseBody() * The "real" ouputstream is then placed inside this */ - PlaceholderOutputStream getPlaceholderResponseBody () { + PlaceholderOutputStream getPlaceholderResponseBody() { getResponseBody(); return uos_orig; } - public void sendResponseHeaders (int rCode, long contentLen) + public void sendResponseHeaders(int rCode, long contentLen) throws IOException { final Logger logger = server.getLogger(); if (sentHeaders) { - throw new IOException ("headers already sent"); + throw new IOException("headers already sent"); } this.rcode = rCode; - String statusLine = "HTTP/1.1 "+rCode+Code.msg(rCode)+"\r\n"; + String statusLine = "HTTP/1.1 " + rCode + Code.msg(rCode) + "\r\n"; ByteArrayOutputStream tmpout = new ByteArrayOutputStream(); PlaceholderOutputStream o = getPlaceholderResponseBody(); - tmpout.write (bytes(statusLine, 0), 0, statusLine.length()); + tmpout.write(bytes(statusLine, 0), 0, statusLine.length()); boolean noContentToSend = false; // assume there is content boolean noContentLengthHeader = false; // must not send Content-length is set rspHdrs.set("Date", FORMATTER.format(Instant.now())); /* check for response type that is not allowed to send a body */ - if ((rCode>=100 && rCode <200) /* informational */ + if ((rCode >= 100 && rCode < 200) /* informational */ ||(rCode == 204) /* no content */ ||(rCode == 304)) /* not modified */ { if (contentLen != RSPBODY_EMPTY) { - String msg = "sendResponseHeaders: rCode = "+ rCode + String msg = "sendResponseHeaders: rCode = " + rCode + ": forcing contentLen = RSPBODY_EMPTY"; - logger.log (Level.WARNING, msg); + logger.log(Level.WARNING, msg); } contentLen = RSPBODY_EMPTY; noContentLengthHeader = (rCode != 304); @@ -245,19 +245,19 @@ class ExchangeImpl { if (contentLen >= 0) { String msg = "sendResponseHeaders: being invoked with a content length for a HEAD request"; - logger.log (Level.WARNING, msg); + logger.log(Level.WARNING, msg); } noContentToSend = true; contentLen = 0; - o.setWrappedStream (new FixedLengthOutputStream (this, ros, contentLen)); + o.setWrappedStream(new FixedLengthOutputStream(this, ros, contentLen)); } else { /* not a HEAD request or 304 response */ if (contentLen == RSPBODY_CHUNKED) { if (http10) { - o.setWrappedStream (new UndefLengthOutputStream (this, ros)); + o.setWrappedStream(new UndefLengthOutputStream(this, ros)); close = true; } else { - rspHdrs.set ("Transfer-encoding", "chunked"); - o.setWrappedStream (new ChunkedOutputStream (this, ros)); + rspHdrs.set("Transfer-encoding", "chunked"); + o.setWrappedStream(new ChunkedOutputStream(this, ros)); } } else { if (contentLen == RSPBODY_EMPTY) { @@ -267,7 +267,7 @@ class ExchangeImpl { if (!noContentLengthHeader) { rspHdrs.set("Content-length", Long.toString(contentLen)); } - o.setWrappedStream (new FixedLengthOutputStream (this, ros, contentLen)); + o.setWrappedStream(new FixedLengthOutputStream(this, ros, contentLen)); } } @@ -280,12 +280,12 @@ class ExchangeImpl { Optional.ofNullable(rspHdrs.get("Connection")) .map(List::stream).orElse(Stream.empty()); if (conheader.anyMatch("close"::equalsIgnoreCase)) { - logger.log (Level.DEBUG, "Connection: close requested by handler"); + logger.log(Level.DEBUG, "Connection: close requested by handler"); close = true; } } - write (rspHdrs, tmpout); + write(rspHdrs, tmpout); this.rspContentLen = contentLen; tmpout.writeTo(ros); sentHeaders = true; @@ -294,33 +294,33 @@ class ExchangeImpl { ros.flush(); close(); } - server.logReply (rCode, req.requestLine(), null); + server.logReply(rCode, req.requestLine(), null); } - void write (Headers map, OutputStream os) throws IOException { - Set>> entries = map.entrySet(); - for (Map.Entry> entry : entries) { + void write(Headers map, OutputStream os) throws IOException { + Set>> entries = map.entrySet(); + for (Map.Entry> entry : entries) { String key = entry.getKey(); byte[] buf; List values = entry.getValue(); for (String val : values) { int i = key.length(); - buf = bytes (key, 2); + buf = bytes(key, 2); buf[i++] = ':'; buf[i++] = ' '; - os.write (buf, 0, i); - buf = bytes (val, 2); + os.write(buf, 0, i); + buf = bytes(val, 2); i = val.length(); buf[i++] = '\r'; buf[i++] = '\n'; - os.write (buf, 0, i); + os.write(buf, 0, i); } } - os.write ('\r'); - os.write ('\n'); + os.write('\r'); + os.write('\n'); } - private byte[] rspbuf = new byte [128]; // used by bytes() + private byte[] rspbuf = new byte[128]; // used by bytes() /** * convert string to byte[], using rspbuf @@ -328,7 +328,7 @@ class ExchangeImpl { * of rspbuf. Reallocate rspbuf if not big enough. * caller must check return value to see if rspbuf moved */ - private byte[] bytes (String s, int extra) { + private byte[] bytes(String s, int extra) { int slen = s.length(); if (slen+extra > rspbuf.length) { int diff = slen + extra - rspbuf.length; @@ -341,27 +341,27 @@ class ExchangeImpl { return rspbuf; } - public InetSocketAddress getRemoteAddress (){ + public InetSocketAddress getRemoteAddress() { Socket s = connection.getChannel().socket(); InetAddress ia = s.getInetAddress(); int port = s.getPort(); - return new InetSocketAddress (ia, port); + return new InetSocketAddress(ia, port); } - public InetSocketAddress getLocalAddress (){ + public InetSocketAddress getLocalAddress() { Socket s = connection.getChannel().socket(); InetAddress ia = s.getLocalAddress(); int port = s.getLocalPort(); - return new InetSocketAddress (ia, port); + return new InetSocketAddress(ia, port); } - public String getProtocol (){ + public String getProtocol() { String reqline = req.requestLine(); - int index = reqline.lastIndexOf (' '); - return reqline.substring (index+1); + int index = reqline.lastIndexOf(' '); + return reqline.substring(index+1); } - public SSLSession getSSLSession () { + public SSLSession getSSLSession() { SSLEngine e = connection.getSSLEngine(); if (e == null) { return null; @@ -369,11 +369,11 @@ class ExchangeImpl { return e.getSession(); } - public Object getAttribute (String name) { + public Object getAttribute(String name) { return attributes.get(Objects.requireNonNull(name, "null name parameter")); } - public void setAttribute (String name, Object value) { + public void setAttribute(String name, Object value) { var key = Objects.requireNonNull(name, "null name parameter"); if (value != null) { attributes.put(key, value); @@ -382,7 +382,7 @@ class ExchangeImpl { } } - public void setStreams (InputStream i, OutputStream o) { + public void setStreams(InputStream i, OutputStream o) { assert uis != null; if (i != null) { uis = i; @@ -395,23 +395,23 @@ class ExchangeImpl { /** * PP */ - HttpConnection getConnection () { + HttpConnection getConnection() { return connection; } - ServerImpl getServerImpl () { + ServerImpl getServerImpl() { return getHttpContext().getServerImpl(); } - public HttpPrincipal getPrincipal () { + public HttpPrincipal getPrincipal() { return principal; } - void setPrincipal (HttpPrincipal principal) { + void setPrincipal(HttpPrincipal principal) { this.principal = principal; } - static ExchangeImpl get (HttpExchange t) { + static ExchangeImpl get(HttpExchange t) { if (t instanceof HttpExchangeImpl) { return ((HttpExchangeImpl)t).getExchangeImpl(); } else { @@ -432,37 +432,37 @@ class PlaceholderOutputStream extends java.io.OutputStream { OutputStream wrapped; - PlaceholderOutputStream (OutputStream os) { + PlaceholderOutputStream(OutputStream os) { wrapped = os; } - void setWrappedStream (OutputStream os) { + void setWrappedStream(OutputStream os) { wrapped = os; } - boolean isWrapped () { + boolean isWrapped() { return wrapped != null; } - private void checkWrap () throws IOException { + private void checkWrap() throws IOException { if (wrapped == null) { - throw new IOException ("response headers not sent yet"); + throw new IOException("response headers not sent yet"); } } public void write(int b) throws IOException { checkWrap(); - wrapped.write (b); + wrapped.write(b); } public void write(byte b[]) throws IOException { checkWrap(); - wrapped.write (b); + wrapped.write(b); } public void write(byte b[], int off, int len) throws IOException { checkWrap(); - wrapped.write (b, off, len); + wrapped.write(b, off, len); } public void flush() throws IOException { diff --git a/src/jdk.httpserver/share/classes/sun/net/httpserver/FixedLengthInputStream.java b/src/jdk.httpserver/share/classes/sun/net/httpserver/FixedLengthInputStream.java index ac6fb7be005..100ba9e1b3b 100644 --- a/src/jdk.httpserver/share/classes/sun/net/httpserver/FixedLengthInputStream.java +++ b/src/jdk.httpserver/share/classes/sun/net/httpserver/FixedLengthInputStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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,15 +39,15 @@ import com.sun.net.httpserver.spi.*; class FixedLengthInputStream extends LeftOverInputStream { private long remaining; - FixedLengthInputStream (ExchangeImpl t, InputStream src, long len) { - super (t, src); + FixedLengthInputStream(ExchangeImpl t, InputStream src, long len) { + super(t, src); if (len < 0) { throw new IllegalArgumentException("Content-Length: " + len); } this.remaining = len; } - protected int readImpl (byte[]b, int off, int len) throws IOException { + protected int readImpl(byte[] b, int off, int len) throws IOException { eof = (remaining == 0L); if (eof) { @@ -60,7 +60,7 @@ class FixedLengthInputStream extends LeftOverInputStream { if (n > -1) { remaining -= n; if (remaining == 0) { - t.getServerImpl().requestCompleted (t.getConnection()); + t.getServerImpl().requestCompleted(t.getConnection()); } } if (n < 0 && !eof) @@ -68,7 +68,7 @@ class FixedLengthInputStream extends LeftOverInputStream { return n; } - public int available () throws IOException { + public int available() throws IOException { if (eof) { return 0; } @@ -76,12 +76,12 @@ class FixedLengthInputStream extends LeftOverInputStream { return n < remaining? n: (int)remaining; } - public boolean markSupported () {return false;} + public boolean markSupported() {return false;} - public void mark (int l) { + public void mark(int l) { } - public void reset () throws IOException { - throw new IOException ("mark/reset not supported"); + public void reset() throws IOException { + throw new IOException("mark/reset not supported"); } } diff --git a/src/jdk.httpserver/share/classes/sun/net/httpserver/FixedLengthOutputStream.java b/src/jdk.httpserver/share/classes/sun/net/httpserver/FixedLengthOutputStream.java index f800bdaba18..95de03d27fa 100644 --- a/src/jdk.httpserver/share/classes/sun/net/httpserver/FixedLengthOutputStream.java +++ b/src/jdk.httpserver/share/classes/sun/net/httpserver/FixedLengthOutputStream.java @@ -42,7 +42,7 @@ class FixedLengthOutputStream extends FilterOutputStream private boolean closed = false; ExchangeImpl t; - FixedLengthOutputStream (ExchangeImpl t, OutputStream src, long len) { + FixedLengthOutputStream(ExchangeImpl t, OutputStream src, long len) { super (src); if (len < 0) { throw new IllegalArgumentException("Content-Length: " + len); @@ -51,9 +51,9 @@ class FixedLengthOutputStream extends FilterOutputStream this.remaining = len; } - public void write (int b) throws IOException { + public void write(int b) throws IOException { if (closed) { - throw new IOException ("stream closed"); + throw new IOException("stream closed"); } if (remaining == 0) { throw new StreamClosedException(); @@ -62,30 +62,30 @@ class FixedLengthOutputStream extends FilterOutputStream remaining --; } - public void write (byte[]b, int off, int len) throws IOException { + public void write(byte[] b, int off, int len) throws IOException { Objects.checkFromIndexSize(off, len, b.length); if (len == 0) { return; } if (closed) { - throw new IOException ("stream closed"); + throw new IOException("stream closed"); } if (len > remaining) { // stream is still open, caller can retry - throw new IOException ("too many bytes to write to stream"); + throw new IOException("too many bytes to write to stream"); } out.write(b, off, len); remaining -= len; } - public void close () throws IOException { + public void close() throws IOException { if (closed) { return; } closed = true; if (remaining > 0) { t.close(); - throw new IOException ("insufficient bytes written to stream"); + throw new IOException("insufficient bytes written to stream"); } flush(); LeftOverInputStream is = t.getOriginalInputStream(); @@ -95,7 +95,7 @@ class FixedLengthOutputStream extends FilterOutputStream } catch (IOException e) {} } Event e = new Event.WriteFinished(t); - t.getHttpContext().getServerImpl().addEvent (e); + t.getHttpContext().getServerImpl().addEvent(e); } // flush is a pass-through diff --git a/src/jdk.httpserver/share/classes/sun/net/httpserver/HttpConnection.java b/src/jdk.httpserver/share/classes/sun/net/httpserver/HttpConnection.java index 38aabe1136e..2be4a37d432 100644 --- a/src/jdk.httpserver/share/classes/sun/net/httpserver/HttpConnection.java +++ b/src/jdk.httpserver/share/classes/sun/net/httpserver/HttpConnection.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -73,14 +73,14 @@ class HttpConnection { return sb.toString(); } - HttpConnection () { + HttpConnection() { } - void setChannel (SocketChannel c) { + void setChannel(SocketChannel c) { chan = c; } - void setContext (HttpContextImpl ctx) { + void setContext(HttpContextImpl ctx) { context = ctx; } @@ -88,11 +88,11 @@ class HttpConnection { return state; } - void setState (State s) { + void setState(State s) { state = s; } - void setParameters ( + void setParameters( InputStream in, OutputStream rawout, SocketChannel chan, SSLEngine engine, SSLStreams sslStreams, SSLContext sslContext, String protocol, HttpContextImpl context, InputStream raw @@ -110,21 +110,21 @@ class HttpConnection { this.logger = context.getLogger(); } - SocketChannel getChannel () { + SocketChannel getChannel() { return chan; } - synchronized void close () { + synchronized void close() { if (closed) { return; } closed = true; if (logger != null && chan != null) { - logger.log (Level.TRACE, "Closing connection: " + chan.toString()); + logger.log(Level.TRACE, "Closing connection: " + chan.toString()); } if (!chan.isOpen()) { - ServerImpl.dprint ("Channel already closed"); + ServerImpl.dprint("Channel already closed"); return; } try { @@ -133,65 +133,65 @@ class HttpConnection { raw.close(); } } catch (IOException e) { - ServerImpl.dprint (e); + ServerImpl.dprint(e); } try { if (rawout != null) { rawout.close(); } } catch (IOException e) { - ServerImpl.dprint (e); + ServerImpl.dprint(e); } try { if (sslStreams != null) { sslStreams.close(); } } catch (IOException e) { - ServerImpl.dprint (e); + ServerImpl.dprint(e); } try { chan.close(); } catch (IOException e) { - ServerImpl.dprint (e); + ServerImpl.dprint(e); } } /* remaining is the number of bytes left on the lowest level inputstream * after the exchange is finished */ - void setRemaining (int r) { + void setRemaining(int r) { remaining = r; } - int getRemaining () { + int getRemaining() { return remaining; } - SelectionKey getSelectionKey () { + SelectionKey getSelectionKey() { return selectionKey; } - InputStream getInputStream () { + InputStream getInputStream() { return i; } - OutputStream getRawOutputStream () { + OutputStream getRawOutputStream() { return rawout; } - String getProtocol () { + String getProtocol() { return protocol; } - SSLEngine getSSLEngine () { + SSLEngine getSSLEngine() { return engine; } - SSLContext getSSLContext () { + SSLContext getSSLContext() { return sslContext; } - HttpContextImpl getHttpContext () { + HttpContextImpl getHttpContext() { return context; } } diff --git a/src/jdk.httpserver/share/classes/sun/net/httpserver/HttpContextImpl.java b/src/jdk.httpserver/share/classes/sun/net/httpserver/HttpContextImpl.java index f1583954115..10cd116a3a0 100644 --- a/src/jdk.httpserver/share/classes/sun/net/httpserver/HttpContextImpl.java +++ b/src/jdk.httpserver/share/classes/sun/net/httpserver/HttpContextImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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,7 +35,7 @@ import com.sun.net.httpserver.*; * to a {@link HttpHandler} which is invoked to handle requests destined * for the protocol/path on the associated HttpServer. *

      - * HttpContext instances are created by {@link HttpServer#createContext(String,String,HttpHandler,Object)} + * HttpContext instances are created by {@link HttpServer#createContext(String, String, HttpHandler, Object)} *

      */ class HttpContextImpl extends HttpContext { @@ -44,7 +44,7 @@ class HttpContextImpl extends HttpContext { private final String protocol; private final ServerImpl server; private final AuthFilter authfilter; - private final Map attributes = new ConcurrentHashMap<>(); + private final Map attributes = new ConcurrentHashMap<>(); /* system filters, not visible to applications */ private final List sfilters = new CopyOnWriteArrayList<>(); /* user filters, set by applications */ @@ -55,35 +55,35 @@ class HttpContextImpl extends HttpContext { /** * constructor is package private. */ - HttpContextImpl (String protocol, String path, HttpHandler cb, ServerImpl server) { + HttpContextImpl(String protocol, String path, HttpHandler cb, ServerImpl server) { if (path == null || protocol == null || path.length() < 1 || path.charAt(0) != '/') { - throw new IllegalArgumentException ("Illegal value for path or protocol"); + throw new IllegalArgumentException("Illegal value for path or protocol"); } this.protocol = protocol.toLowerCase(Locale.ROOT); this.path = path; - if (!this.protocol.equals ("http") && !this.protocol.equals ("https")) { - throw new IllegalArgumentException ("Illegal value for protocol"); + if (!this.protocol.equals("http") && !this.protocol.equals("https")) { + throw new IllegalArgumentException("Illegal value for protocol"); } this.handler = cb; this.server = server; authfilter = new AuthFilter(null); - sfilters.add (authfilter); + sfilters.add(authfilter); } /** * returns the handler for this context * @return the HttpHandler for this context */ - public HttpHandler getHandler () { + public HttpHandler getHandler() { return handler; } - public void setHandler (HttpHandler h) { + public void setHandler(HttpHandler h) { if (h == null) { - throw new NullPointerException ("Null handler parameter"); + throw new NullPointerException("Null handler parameter"); } if (handler != null) { - throw new IllegalArgumentException ("handler already set"); + throw new IllegalArgumentException("handler already set"); } handler = h; } @@ -100,11 +100,11 @@ class HttpContextImpl extends HttpContext { * returns the server this context was created with * @return this context's server */ - public HttpServer getServer () { + public HttpServer getServer() { return server.getWrapper(); } - ServerImpl getServerImpl () { + ServerImpl getServerImpl() { return server; } @@ -124,29 +124,29 @@ class HttpContextImpl extends HttpContext { * Every attribute stored in this Map will be visible to * every HttpExchange processed by this context */ - public Map getAttributes() { + public Map getAttributes() { return attributes; } - public List getFilters () { + public List getFilters() { return ufilters; } - List getSystemFilters () { + List getSystemFilters() { return sfilters; } - public Authenticator setAuthenticator (Authenticator auth) { + public Authenticator setAuthenticator(Authenticator auth) { Authenticator old = authenticator; authenticator = auth; - authfilter.setAuthenticator (auth); + authfilter.setAuthenticator(auth); return old; } - public Authenticator getAuthenticator () { + public Authenticator getAuthenticator() { return authenticator; } - Logger getLogger () { + Logger getLogger() { return server.getLogger(); } } diff --git a/src/jdk.httpserver/share/classes/sun/net/httpserver/HttpError.java b/src/jdk.httpserver/share/classes/sun/net/httpserver/HttpError.java index de9dfba8cfb..b201c822193 100644 --- a/src/jdk.httpserver/share/classes/sun/net/httpserver/HttpError.java +++ b/src/jdk.httpserver/share/classes/sun/net/httpserver/HttpError.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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,7 +31,7 @@ package sun.net.httpserver; class HttpError extends RuntimeException { private static final long serialVersionUID = 8769596371344178179L; - public HttpError (String msg) { - super (msg); + public HttpError(String msg) { + super(msg); } } diff --git a/src/jdk.httpserver/share/classes/sun/net/httpserver/HttpExchangeImpl.java b/src/jdk.httpserver/share/classes/sun/net/httpserver/HttpExchangeImpl.java index 420ef3d9e64..d4606019c56 100644 --- a/src/jdk.httpserver/share/classes/sun/net/httpserver/HttpExchangeImpl.java +++ b/src/jdk.httpserver/share/classes/sun/net/httpserver/HttpExchangeImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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,82 +38,82 @@ class HttpExchangeImpl extends HttpExchange { ExchangeImpl impl; - HttpExchangeImpl (ExchangeImpl impl) { + HttpExchangeImpl(ExchangeImpl impl) { this.impl = impl; } - public Headers getRequestHeaders () { + public Headers getRequestHeaders() { return impl.getRequestHeaders(); } - public Headers getResponseHeaders () { + public Headers getResponseHeaders() { return impl.getResponseHeaders(); } - public URI getRequestURI () { + public URI getRequestURI() { return impl.getRequestURI(); } - public String getRequestMethod (){ + public String getRequestMethod() { return impl.getRequestMethod(); } - public HttpContextImpl getHttpContext (){ + public HttpContextImpl getHttpContext() { return impl.getHttpContext(); } - public void close () { + public void close() { impl.close(); } - public InputStream getRequestBody () { + public InputStream getRequestBody() { return impl.getRequestBody(); } - public int getResponseCode () { + public int getResponseCode() { return impl.getResponseCode(); } - public OutputStream getResponseBody () { + public OutputStream getResponseBody() { return impl.getResponseBody(); } - public void sendResponseHeaders (int rCode, long contentLen) + public void sendResponseHeaders(int rCode, long contentLen) throws IOException { - impl.sendResponseHeaders (rCode, contentLen); + impl.sendResponseHeaders(rCode, contentLen); } - public InetSocketAddress getRemoteAddress (){ + public InetSocketAddress getRemoteAddress() { return impl.getRemoteAddress(); } - public InetSocketAddress getLocalAddress (){ + public InetSocketAddress getLocalAddress() { return impl.getLocalAddress(); } - public String getProtocol (){ + public String getProtocol() { return impl.getProtocol(); } - public Object getAttribute (String name) { - return impl.getAttribute (name); + public Object getAttribute(String name) { + return impl.getAttribute(name); } - public void setAttribute (String name, Object value) { - impl.setAttribute (name, value); + public void setAttribute(String name, Object value) { + impl.setAttribute(name, value); } - public void setStreams (InputStream i, OutputStream o) { - impl.setStreams (i, o); + public void setStreams(InputStream i, OutputStream o) { + impl.setStreams(i, o); } - public HttpPrincipal getPrincipal () { + public HttpPrincipal getPrincipal() { return impl.getPrincipal(); } - ExchangeImpl getExchangeImpl () { + ExchangeImpl getExchangeImpl() { return impl; } } diff --git a/src/jdk.httpserver/share/classes/sun/net/httpserver/HttpServerImpl.java b/src/jdk.httpserver/share/classes/sun/net/httpserver/HttpServerImpl.java index dd09957c0c6..93ace4e7bd2 100644 --- a/src/jdk.httpserver/share/classes/sun/net/httpserver/HttpServerImpl.java +++ b/src/jdk.httpserver/share/classes/sun/net/httpserver/HttpServerImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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,50 +35,50 @@ public class HttpServerImpl extends HttpServer { ServerImpl server; - HttpServerImpl () throws IOException { - this (new InetSocketAddress(80), 0); + HttpServerImpl() throws IOException { + this(new InetSocketAddress(80), 0); } - HttpServerImpl ( + HttpServerImpl( InetSocketAddress addr, int backlog ) throws IOException { - server = new ServerImpl (this, "http", addr, backlog); + server = new ServerImpl(this, "http", addr, backlog); } - public void bind (InetSocketAddress addr, int backlog) throws IOException { - server.bind (addr, backlog); + public void bind(InetSocketAddress addr, int backlog) throws IOException { + server.bind(addr, backlog); } - public void start () { + public void start() { server.start(); } - public void setExecutor (Executor executor) { + public void setExecutor(Executor executor) { server.setExecutor(executor); } - public Executor getExecutor () { + public Executor getExecutor() { return server.getExecutor(); } - public void stop (int delay) { - server.stop (delay); + public void stop(int delay) { + server.stop(delay); } - public HttpContextImpl createContext (String path, HttpHandler handler) { - return server.createContext (path, handler); + public HttpContextImpl createContext(String path, HttpHandler handler) { + return server.createContext(path, handler); } - public HttpContextImpl createContext (String path) { - return server.createContext (path); + public HttpContextImpl createContext(String path) { + return server.createContext(path); } - public void removeContext (String path) throws IllegalArgumentException { - server.removeContext (path); + public void removeContext(String path) throws IllegalArgumentException { + server.removeContext(path); } - public void removeContext (HttpContext context) throws IllegalArgumentException { - server.removeContext (context); + public void removeContext(HttpContext context) throws IllegalArgumentException { + server.removeContext(context); } public InetSocketAddress getAddress() { diff --git a/src/jdk.httpserver/share/classes/sun/net/httpserver/HttpsExchangeImpl.java b/src/jdk.httpserver/share/classes/sun/net/httpserver/HttpsExchangeImpl.java index f7f43d7feca..939b88d3928 100644 --- a/src/jdk.httpserver/share/classes/sun/net/httpserver/HttpsExchangeImpl.java +++ b/src/jdk.httpserver/share/classes/sun/net/httpserver/HttpsExchangeImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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,86 +38,86 @@ class HttpsExchangeImpl extends HttpsExchange { ExchangeImpl impl; - HttpsExchangeImpl (ExchangeImpl impl) throws IOException { + HttpsExchangeImpl(ExchangeImpl impl) throws IOException { this.impl = impl; } - public Headers getRequestHeaders () { + public Headers getRequestHeaders() { return impl.getRequestHeaders(); } - public Headers getResponseHeaders () { + public Headers getResponseHeaders() { return impl.getResponseHeaders(); } - public URI getRequestURI () { + public URI getRequestURI() { return impl.getRequestURI(); } - public String getRequestMethod (){ + public String getRequestMethod() { return impl.getRequestMethod(); } - public HttpContextImpl getHttpContext (){ + public HttpContextImpl getHttpContext() { return impl.getHttpContext(); } - public void close () { + public void close() { impl.close(); } - public InputStream getRequestBody () { + public InputStream getRequestBody() { return impl.getRequestBody(); } - public int getResponseCode () { + public int getResponseCode() { return impl.getResponseCode(); } - public OutputStream getResponseBody () { + public OutputStream getResponseBody() { return impl.getResponseBody(); } - public void sendResponseHeaders (int rCode, long contentLen) + public void sendResponseHeaders(int rCode, long contentLen) throws IOException { - impl.sendResponseHeaders (rCode, contentLen); + impl.sendResponseHeaders(rCode, contentLen); } - public InetSocketAddress getRemoteAddress (){ + public InetSocketAddress getRemoteAddress() { return impl.getRemoteAddress(); } - public InetSocketAddress getLocalAddress (){ + public InetSocketAddress getLocalAddress() { return impl.getLocalAddress(); } - public String getProtocol (){ + public String getProtocol() { return impl.getProtocol(); } - public SSLSession getSSLSession () { - return impl.getSSLSession (); + public SSLSession getSSLSession() { + return impl.getSSLSession(); } - public Object getAttribute (String name) { - return impl.getAttribute (name); + public Object getAttribute(String name) { + return impl.getAttribute(name); } - public void setAttribute (String name, Object value) { - impl.setAttribute (name, value); + public void setAttribute(String name, Object value) { + impl.setAttribute(name, value); } - public void setStreams (InputStream i, OutputStream o) { - impl.setStreams (i, o); + public void setStreams(InputStream i, OutputStream o) { + impl.setStreams(i, o); } - public HttpPrincipal getPrincipal () { + public HttpPrincipal getPrincipal() { return impl.getPrincipal(); } - ExchangeImpl getExchangeImpl () { + ExchangeImpl getExchangeImpl() { return impl; } } diff --git a/src/jdk.httpserver/share/classes/sun/net/httpserver/HttpsServerImpl.java b/src/jdk.httpserver/share/classes/sun/net/httpserver/HttpsServerImpl.java index 97312ec29e6..8ef179c1194 100644 --- a/src/jdk.httpserver/share/classes/sun/net/httpserver/HttpsServerImpl.java +++ b/src/jdk.httpserver/share/classes/sun/net/httpserver/HttpsServerImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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,58 +35,58 @@ public class HttpsServerImpl extends HttpsServer { ServerImpl server; - HttpsServerImpl () throws IOException { - this (new InetSocketAddress(443), 0); + HttpsServerImpl() throws IOException { + this(new InetSocketAddress(443), 0); } - HttpsServerImpl ( + HttpsServerImpl( InetSocketAddress addr, int backlog ) throws IOException { - server = new ServerImpl (this, "https", addr, backlog); + server = new ServerImpl(this, "https", addr, backlog); } - public void setHttpsConfigurator (HttpsConfigurator config) { - server.setHttpsConfigurator (config); + public void setHttpsConfigurator(HttpsConfigurator config) { + server.setHttpsConfigurator(config); } - public HttpsConfigurator getHttpsConfigurator () { + public HttpsConfigurator getHttpsConfigurator() { return server.getHttpsConfigurator(); } - public void bind (InetSocketAddress addr, int backlog) throws IOException { - server.bind (addr, backlog); + public void bind(InetSocketAddress addr, int backlog) throws IOException { + server.bind(addr, backlog); } - public void start () { + public void start() { server.start(); } - public void setExecutor (Executor executor) { + public void setExecutor(Executor executor) { server.setExecutor(executor); } - public Executor getExecutor () { + public Executor getExecutor() { return server.getExecutor(); } - public void stop (int delay) { - server.stop (delay); + public void stop(int delay) { + server.stop(delay); } - public HttpContextImpl createContext (String path, HttpHandler handler) { - return server.createContext (path, handler); + public HttpContextImpl createContext(String path, HttpHandler handler) { + return server.createContext(path, handler); } - public HttpContextImpl createContext (String path) { - return server.createContext (path); + public HttpContextImpl createContext(String path) { + return server.createContext(path); } - public void removeContext (String path) throws IllegalArgumentException { - server.removeContext (path); + public void removeContext(String path) throws IllegalArgumentException { + server.removeContext(path); } - public void removeContext (HttpContext context) throws IllegalArgumentException { - server.removeContext (context); + public void removeContext(HttpContext context) throws IllegalArgumentException { + server.removeContext(context); } public InetSocketAddress getAddress() { diff --git a/src/jdk.httpserver/share/classes/sun/net/httpserver/LeftOverInputStream.java b/src/jdk.httpserver/share/classes/sun/net/httpserver/LeftOverInputStream.java index 772fa621076..ea904835770 100644 --- a/src/jdk.httpserver/share/classes/sun/net/httpserver/LeftOverInputStream.java +++ b/src/jdk.httpserver/share/classes/sun/net/httpserver/LeftOverInputStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -45,47 +45,47 @@ abstract class LeftOverInputStream extends FilterInputStream { final ServerImpl server; protected boolean closed = false; protected boolean eof = false; - byte[] one = new byte [1]; + byte[] one = new byte[1]; private static final int MAX_SKIP_BUFFER_SIZE = 2048; - public LeftOverInputStream (ExchangeImpl t, InputStream src) { - super (src); + public LeftOverInputStream(ExchangeImpl t, InputStream src) { + super(src); this.t = t; this.server = t.getServerImpl(); } /** * if bytes are left over buffered on *the UNDERLYING* stream */ - public boolean isDataBuffered () throws IOException { + public boolean isDataBuffered() throws IOException { assert eof; return super.available() > 0; } - public void close () throws IOException { + public void close() throws IOException { if (closed) { return; } closed = true; if (!eof) { - eof = drain (ServerConfig.getDrainAmount()); + eof = drain(ServerConfig.getDrainAmount()); } } - public boolean isClosed () { + public boolean isClosed() { return closed; } - public boolean isEOF () { + public boolean isEOF() { return eof; } - protected abstract int readImpl (byte[]b, int off, int len) throws IOException; + protected abstract int readImpl(byte[] b, int off, int len) throws IOException; - public synchronized int read () throws IOException { + public synchronized int read() throws IOException { if (closed) { - throw new IOException ("Stream is closed"); + throw new IOException("Stream is closed"); } - int c = readImpl (one, 0, 1); + int c = readImpl(one, 0, 1); if (c == -1 || c == 0) { return c; } else { @@ -93,11 +93,11 @@ abstract class LeftOverInputStream extends FilterInputStream { } } - public synchronized int read (byte[]b, int off, int len) throws IOException { + public synchronized int read(byte[] b, int off, int len) throws IOException { if (closed) { - throw new IOException ("Stream is closed"); + throw new IOException("Stream is closed"); } - return readImpl (b, off, len); + return readImpl(b, off, len); } @Override @@ -132,7 +132,7 @@ abstract class LeftOverInputStream extends FilterInputStream { * is at eof (ie. all bytes were read) or false if not * (still bytes to be read) */ - public boolean drain (long l) throws IOException { + public boolean drain(long l) throws IOException { while (l > 0) { long skip = skip(l); if (skip <= 0) break; // might return 0 if isFinishing or EOF diff --git a/src/jdk.httpserver/share/classes/sun/net/httpserver/Request.java b/src/jdk.httpserver/share/classes/sun/net/httpserver/Request.java index 6c0c2c271ed..4a4afc8d7ce 100644 --- a/src/jdk.httpserver/share/classes/sun/net/httpserver/Request.java +++ b/src/jdk.httpserver/share/classes/sun/net/httpserver/Request.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -46,7 +46,7 @@ class Request { private OutputStream os; private final int maxReqHeaderSize; - Request (InputStream rawInputStream, OutputStream rawout) throws IOException { + Request(InputStream rawInputStream, OutputStream rawout) throws IOException { this.maxReqHeaderSize = ServerConfig.getMaxReqHeaderSize(); is = rawInputStream; os = rawout; @@ -57,15 +57,15 @@ class Request { } - char[] buf = new char [BUF_LEN]; + char[] buf = new char[BUF_LEN]; int pos; StringBuffer lineBuf; - public InputStream inputStream () { + public InputStream inputStream() { return is; } - public OutputStream outputStream () { + public OutputStream outputStream() { return os; } @@ -74,7 +74,7 @@ class Request { * Not used for reading headers. */ - public String readLine () throws IOException { + public String readLine() throws IOException { boolean gotCR = false, gotLF = false; pos = 0; lineBuf = new StringBuffer(); long lsize = 32; @@ -88,15 +88,15 @@ class Request { gotLF = true; } else { gotCR = false; - consume (CR); - consume (c); + consume(CR); + consume(c); lsize = lsize + 2; } } else { if (c == CR) { gotCR = true; } else { - consume (c); + consume(c); lsize = lsize + 1; } } @@ -106,13 +106,13 @@ class Request { ServerConfig.getMaxReqHeaderSize() + "."); } } - lineBuf.append (buf, 0, pos); - return new String (lineBuf); + lineBuf.append(buf, 0, pos); + return new String(lineBuf); } - private void consume (int c) throws IOException { + private void consume(int c) throws IOException { if (pos == BUF_LEN) { - lineBuf.append (buf); + lineBuf.append(buf); pos = 0; } buf[pos++] = (char)c; @@ -121,13 +121,13 @@ class Request { /** * returns the request line (first line of a request) */ - public String requestLine () { + public String requestLine() { return startLine; } Headers hdrs = null; @SuppressWarnings("fallthrough") - Headers headers () throws IOException { + Headers headers() throws IOException { if (hdrs != null) { return hdrs; } @@ -239,7 +239,7 @@ class Request { if (k == null) { // Headers disallows null keys, use empty string k = ""; // instead to represent invalid key } - hdrs.add (k,v); + hdrs.add(k, v); len = 0; } return hdrs; @@ -262,21 +262,21 @@ class Request { ServerImpl server; static final int BUFSIZE = 8 * 1024; - public ReadStream (ServerImpl server, SocketChannel chan) throws IOException { + public ReadStream(ServerImpl server, SocketChannel chan) throws IOException { this.channel = chan; this.server = server; - chanbuf = ByteBuffer.allocate (BUFSIZE); + chanbuf = ByteBuffer.allocate(BUFSIZE); chanbuf.clear(); one = new byte[1]; closed = marked = reset = false; } - public synchronized int read (byte[] b) throws IOException { - return read (b, 0, b.length); + public synchronized int read(byte[] b) throws IOException { + return read(b, 0, b.length); } - public synchronized int read () throws IOException { - int result = read (one, 0, 1); + public synchronized int read() throws IOException { + int result = read(one, 0, 1); if (result == 1) { return one[0] & 0xFF; } else { @@ -284,12 +284,12 @@ class Request { } } - public synchronized int read (byte[] b, int off, int srclen) throws IOException { + public synchronized int read(byte[] b, int off, int srclen) throws IOException { int canreturn, willreturn; if (closed) - throw new IOException ("Stream closed"); + throw new IOException("Stream closed"); if (eof) { return -1; @@ -300,30 +300,30 @@ class Request { Objects.checkFromIndexSize(off, srclen, b.length); if (reset) { /* satisfy from markBuf */ - canreturn = markBuf.remaining (); + canreturn = markBuf.remaining(); willreturn = canreturn>srclen ? srclen : canreturn; markBuf.get(b, off, willreturn); if (canreturn == willreturn) { reset = false; } } else { /* satisfy from channel */ - chanbuf.clear (); + chanbuf.clear(); if (srclen < BUFSIZE) { - chanbuf.limit (srclen); + chanbuf.limit(srclen); } do { - willreturn = channel.read (chanbuf); + willreturn = channel.read(chanbuf); } while (willreturn == 0); if (willreturn == -1) { eof = true; return -1; } - chanbuf.flip (); + chanbuf.flip(); chanbuf.get(b, off, willreturn); if (marked) { /* copy into markBuf */ try { - markBuf.put (b, off, willreturn); + markBuf.put(b, off, willreturn); } catch (BufferOverflowException e) { marked = false; } @@ -332,14 +332,14 @@ class Request { return willreturn; } - public boolean markSupported () { + public boolean markSupported() { return true; } /* Does not query the OS socket */ - public synchronized int available () throws IOException { + public synchronized int available() throws IOException { if (closed) - throw new IOException ("Stream is closed"); + throw new IOException("Stream is closed"); if (eof) return -1; @@ -350,31 +350,31 @@ class Request { return chanbuf.remaining(); } - public void close () throws IOException { + public void close() throws IOException { if (closed) { return; } - channel.close (); + channel.close(); closed = true; } - public synchronized void mark (int readlimit) { + public synchronized void mark(int readlimit) { if (closed) return; this.readlimit = readlimit; - markBuf = ByteBuffer.allocate (readlimit); + markBuf = ByteBuffer.allocate(readlimit); marked = true; reset = false; } - public synchronized void reset () throws IOException { + public synchronized void reset() throws IOException { if (closed ) return; if (!marked) - throw new IOException ("Stream not marked"); + throw new IOException("Stream not marked"); marked = false; reset = true; - markBuf.flip (); + markBuf.flip(); } } @@ -386,50 +386,50 @@ class Request { byte[] one; ServerImpl server; - public WriteStream (ServerImpl server, SocketChannel channel) throws IOException { + public WriteStream(ServerImpl server, SocketChannel channel) throws IOException { this.channel = channel; this.server = server; assert channel.isBlocking(); closed = false; one = new byte [1]; - buf = ByteBuffer.allocate (4096); + buf = ByteBuffer.allocate(4096); } - public synchronized void write (int b) throws IOException { + public synchronized void write(int b) throws IOException { one[0] = (byte)b; write (one, 0, 1); } - public synchronized void write (byte[] b) throws IOException { + public synchronized void write(byte[] b) throws IOException { write (b, 0, b.length); } - public synchronized void write (byte[] b, int off, int len) throws IOException { + public synchronized void write(byte[] b, int off, int len) throws IOException { int l = len; if (closed) - throw new IOException ("stream is closed"); + throw new IOException("stream is closed"); int cap = buf.capacity(); if (cap < len) { int diff = len - cap; - buf = ByteBuffer.allocate (2*(cap+diff)); + buf = ByteBuffer.allocate(2*(cap+diff)); } buf.clear(); - buf.put (b, off, len); - buf.flip (); + buf.put(b, off, len); + buf.flip(); int n; - while ((n = channel.write (buf)) < l) { + while ((n = channel.write(buf)) < l) { l -= n; if (l == 0) return; } } - public void close () throws IOException { + public void close() throws IOException { if (closed) return; - //server.logStackTrace ("Request.OS.close: isOpen="+channel.isOpen()); - channel.close (); + //server.logStackTrace("Request.OS.close: isOpen="+channel.isOpen()); + channel.close(); closed = true; } } diff --git a/src/jdk.httpserver/share/classes/sun/net/httpserver/SSLStreams.java b/src/jdk.httpserver/share/classes/sun/net/httpserver/SSLStreams.java index 5cc16befa96..5f5eef0c684 100644 --- a/src/jdk.httpserver/share/classes/sun/net/httpserver/SSLStreams.java +++ b/src/jdk.httpserver/share/classes/sun/net/httpserver/SSLStreams.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -53,35 +53,35 @@ class SSLStreams { /* held by thread doing the hand-shake on this connection */ Lock handshaking = new ReentrantLock(); - SSLStreams (ServerImpl server, SSLContext sslctx, SocketChannel chan) throws IOException { + SSLStreams(ServerImpl server, SSLContext sslctx, SocketChannel chan) throws IOException { this.server = server; this.sslctx= sslctx; this.chan= chan; InetSocketAddress addr = (InetSocketAddress)chan.socket().getRemoteSocketAddress(); - engine = sslctx.createSSLEngine (addr.getHostName(), addr.getPort()); - engine.setUseClientMode (false); + engine = sslctx.createSSLEngine(addr.getHostName(), addr.getPort()); + engine.setUseClientMode(false); HttpsConfigurator cfg = server.getHttpsConfigurator(); - configureEngine (cfg, addr); - wrapper = new EngineWrapper (chan, engine); + configureEngine(cfg, addr); + wrapper = new EngineWrapper(chan, engine); } @SuppressWarnings("deprecation") - private void configureEngine(HttpsConfigurator cfg, InetSocketAddress addr){ + private void configureEngine(HttpsConfigurator cfg, InetSocketAddress addr) { if (cfg != null) { - Parameters params = new Parameters (cfg, addr); + Parameters params = new Parameters(cfg, addr); //BEGIN_TIGER_EXCLUDE - cfg.configure (params); + cfg.configure(params); SSLParameters sslParams = params.getSSLParameters(); if (sslParams != null) { - engine.setSSLParameters (sslParams); + engine.setSSLParameters(sslParams); } else //END_TIGER_EXCLUDE { /* tiger compatibility */ if (params.getCipherSuites() != null) { try { - engine.setEnabledCipherSuites ( + engine.setEnabledCipherSuites( params.getCipherSuites() ); } catch (IllegalArgumentException e) { /* LOG */} @@ -93,7 +93,7 @@ class SSLStreams { } if (params.getProtocols() != null) { try { - engine.setEnabledProtocols ( + engine.setEnabledProtocols( params.getProtocols() ); } catch (IllegalArgumentException e) { /* LOG */} @@ -106,11 +106,11 @@ class SSLStreams { InetSocketAddress addr; HttpsConfigurator cfg; - Parameters (HttpsConfigurator cfg, InetSocketAddress addr) { + Parameters(HttpsConfigurator cfg, InetSocketAddress addr) { this.addr = addr; this.cfg = cfg; } - public InetSocketAddress getClientAddress () { + public InetSocketAddress getClientAddress() { return addr; } public HttpsConfigurator getHttpsConfigurator() { @@ -118,10 +118,10 @@ class SSLStreams { } //BEGIN_TIGER_EXCLUDE SSLParameters params; - public void setSSLParameters (SSLParameters p) { + public void setSSLParameters(SSLParameters p) { params = p; } - SSLParameters getSSLParameters () { + SSLParameters getSSLParameters() { return params; } //END_TIGER_EXCLUDE @@ -130,14 +130,14 @@ class SSLStreams { /** * cleanup resources allocated inside this object */ - void close () throws IOException { + void close() throws IOException { wrapper.close(); } /** * return the SSL InputStream */ - InputStream getInputStream () throws IOException { + InputStream getInputStream() throws IOException { if (is == null) { is = new InputStream(); } @@ -147,14 +147,14 @@ class SSLStreams { /** * return the SSL OutputStream */ - OutputStream getOutputStream () throws IOException { + OutputStream getOutputStream() throws IOException { if (os == null) { os = new OutputStream(); } return os; } - SSLEngine getSSLEngine () { + SSLEngine getSSLEngine() { return engine; } @@ -183,11 +183,11 @@ class SSLStreams { PACKET, APPLICATION }; - private ByteBuffer allocate (BufType type) { - return allocate (type, -1); + private ByteBuffer allocate(BufType type) { + return allocate(type, -1); } - private ByteBuffer allocate (BufType type, int len) { + private ByteBuffer allocate(BufType type, int len) { assert engine != null; synchronized (this) { int size; @@ -210,7 +210,7 @@ class SSLStreams { } size = app_buf_size; } - return ByteBuffer.allocate (size); + return ByteBuffer.allocate(size); } } @@ -222,10 +222,10 @@ class SSLStreams { * flip is set to true if the old buffer needs to be flipped * before it is copied. */ - private ByteBuffer realloc (ByteBuffer b, boolean flip, BufType type) { + private ByteBuffer realloc(ByteBuffer b, boolean flip, BufType type) { synchronized (this) { int nsize = 2 * b.capacity(); - ByteBuffer n = allocate (type, nsize); + ByteBuffer n = allocate(type, nsize); if (flip) { b.flip(); } @@ -252,7 +252,7 @@ class SSLStreams { boolean closed = false; int u_remaining; // the number of bytes left in unwrap_src after an unwrap() - EngineWrapper (SocketChannel chan, SSLEngine engine) throws IOException { + EngineWrapper(SocketChannel chan, SSLEngine engine) throws IOException { this.chan = chan; this.engine = engine; wrapLock = new Object(); @@ -261,7 +261,7 @@ class SSLStreams { wrap_dst = allocate(BufType.PACKET); } - void close () throws IOException { + void close() throws IOException { } /* try to wrap and send the data in src. Handles OVERFLOW. @@ -275,17 +275,17 @@ class SSLStreams { WrapperResult wrapAndSendX(ByteBuffer src, boolean ignoreClose) throws IOException { if (closed && !ignoreClose) { - throw new IOException ("Engine is closed"); + throw new IOException("Engine is closed"); } Status status; WrapperResult r = new WrapperResult(); synchronized (wrapLock) { wrap_dst.clear(); do { - r.result = engine.wrap (src, wrap_dst); + r.result = engine.wrap(src, wrap_dst); status = r.result.getStatus(); if (status == Status.BUFFER_OVERFLOW) { - wrap_dst = realloc (wrap_dst, true, BufType.PACKET); + wrap_dst = realloc(wrap_dst, true, BufType.PACKET); } } while (status == Status.BUFFER_OVERFLOW); if (status == Status.CLOSED && !ignoreClose) { @@ -296,7 +296,7 @@ class SSLStreams { int l = wrap_dst.remaining(); assert l == r.result.bytesProduced(); while (l>0) { - l -= chan.write (wrap_dst); + l -= chan.write(wrap_dst); } } } @@ -313,7 +313,7 @@ class SSLStreams { WrapperResult r = new WrapperResult(); r.buf = dst; if (closed) { - throw new IOException ("Engine is closed"); + throw new IOException("Engine is closed"); } boolean needData; if (u_remaining > 0) { @@ -329,19 +329,19 @@ class SSLStreams { do { if (needData) { do { - x = chan.read (unwrap_src); + x = chan.read(unwrap_src); } while (x == 0); if (x == -1) { - throw new IOException ("connection closed for reading"); + throw new IOException("connection closed for reading"); } unwrap_src.flip(); } - r.result = engine.unwrap (unwrap_src, r.buf); + r.result = engine.unwrap(unwrap_src, r.buf); status = r.result.getStatus(); if (status == Status.BUFFER_UNDERFLOW) { if (unwrap_src.limit() == unwrap_src.capacity()) { /* buffer not big enough */ - unwrap_src = realloc ( + unwrap_src = realloc( unwrap_src, false, BufType.PACKET ); } else { @@ -349,12 +349,12 @@ class SSLStreams { * data off the channel. Reset pointers * for reading off SocketChannel */ - unwrap_src.position (unwrap_src.limit()); - unwrap_src.limit (unwrap_src.capacity()); + unwrap_src.position(unwrap_src.limit()); + unwrap_src.limit(unwrap_src.capacity()); } needData = true; } else if (status == Status.BUFFER_OVERFLOW) { - r.buf = realloc (r.buf, true, BufType.APPLICATION); + r.buf = realloc(r.buf, true, BufType.APPLICATION); needData = false; } else if (status == Status.CLOSED) { closed = true; @@ -374,13 +374,13 @@ class SSLStreams { * all of the given user data has been sent and any handshake has been * completed. Caller should check if engine has been closed. */ - public WrapperResult sendData (ByteBuffer src) throws IOException { + public WrapperResult sendData(ByteBuffer src) throws IOException { WrapperResult r=null; while (src.remaining() > 0) { r = wrapper.wrapAndSend(src); Status status = r.result.getStatus(); if (status == Status.CLOSED) { - doClosure (); + doClosure(); return r; } HandshakeStatus hs_status = r.result.getHandshakeStatus(); @@ -399,16 +399,16 @@ class SSLStreams { * and returned. This call handles handshaking automatically. * Caller should check if engine has been closed. */ - public WrapperResult recvData (ByteBuffer dst) throws IOException { + public WrapperResult recvData(ByteBuffer dst) throws IOException { /* we wait until some user data arrives */ WrapperResult r = null; assert dst.position() == 0; while (dst.position() == 0) { - r = wrapper.recvAndUnwrap (dst); + r = wrapper.recvAndUnwrap(dst); dst = (r.buf != dst) ? r.buf: dst; Status status = r.result.getStatus(); if (status == Status.CLOSED) { - doClosure (); + doClosure(); return r; } @@ -416,7 +416,7 @@ class SSLStreams { if (hs_status != HandshakeStatus.FINISHED && hs_status != HandshakeStatus.NOT_HANDSHAKING) { - doHandshake (hs_status); + doHandshake(hs_status); } } dst.flip(); @@ -426,7 +426,7 @@ class SSLStreams { /* we've received a close notify. Need to call wrap to send * the response */ - void doClosure () throws IOException { + void doClosure() throws IOException { try { handshaking.lock(); ByteBuffer tmp = allocate(BufType.APPLICATION); @@ -435,8 +435,8 @@ class SSLStreams { HandshakeStatus hs; do { tmp.clear(); - tmp.flip (); - r = wrapper.wrapAndSendX (tmp, true); + tmp.flip(); + r = wrapper.wrapAndSendX(tmp, true); hs = r.result.getHandshakeStatus(); st = r.result.getStatus(); } while (st != Status.CLOSED && @@ -452,7 +452,7 @@ class SSLStreams { * is called with no data to send then there must be no problem */ @SuppressWarnings("fallthrough") - void doHandshake (HandshakeStatus hs_status) throws IOException { + void doHandshake(HandshakeStatus hs_status) throws IOException { try { handshaking.lock(); ByteBuffer tmp = allocate(BufType.APPLICATION); @@ -478,7 +478,7 @@ class SSLStreams { case NEED_UNWRAP: tmp.clear(); - r = wrapper.recvAndUnwrap (tmp); + r = wrapper.recvAndUnwrap(tmp); if (r.buf != tmp) { tmp = r.buf; } @@ -507,27 +507,27 @@ class SSLStreams { boolean needData = true; - InputStream () { - bbuf = allocate (BufType.APPLICATION); + InputStream() { + bbuf = allocate(BufType.APPLICATION); } - public int read (byte[] buf, int off, int len) throws IOException { + public int read(byte[] buf, int off, int len) throws IOException { if (closed) { - throw new IOException ("SSL stream is closed"); + throw new IOException("SSL stream is closed"); } if (eof) { return -1; } - int available=0; + int available = 0; if (!needData) { available = bbuf.remaining(); - needData = (available==0); + needData = (available == 0); } if (needData) { bbuf.clear(); - WrapperResult r = recvData (bbuf); - bbuf = r.buf== bbuf? bbuf: r.buf; - if ((available=bbuf.remaining()) == 0) { + WrapperResult r = recvData(bbuf); + bbuf = r.buf == bbuf ? bbuf: r.buf; + if ((available = bbuf.remaining()) == 0) { eof = true; return -1; } else { @@ -538,26 +538,26 @@ class SSLStreams { if (len > available) { len = available; } - bbuf.get (buf, off, len); + bbuf.get(buf, off, len); return len; } - public int available () throws IOException { + public int available() throws IOException { return bbuf.remaining(); } - public boolean markSupported () { + public boolean markSupported() { return false; /* not possible with SSLEngine */ } - public void reset () throws IOException { - throw new IOException ("mark/reset not supported"); + public void reset() throws IOException { + throw new IOException("mark/reset not supported"); } - public long skip (long s) throws IOException { + public long skip(long s) throws IOException { int n = (int)s; if (closed) { - throw new IOException ("SSL stream is closed"); + throw new IOException("SSL stream is closed"); } if (eof) { return 0; @@ -565,13 +565,13 @@ class SSLStreams { int ret = n; while (n > 0) { if (bbuf.remaining() >= n) { - bbuf.position (bbuf.position()+n); + bbuf.position(bbuf.position()+n); return ret; } else { n -= bbuf.remaining(); bbuf.clear(); - WrapperResult r = recvData (bbuf); - bbuf = r.buf==bbuf? bbuf: r.buf; + WrapperResult r = recvData(bbuf); + bbuf = r.buf == bbuf ? bbuf: r.buf; } } return ret; /* not reached */ @@ -582,22 +582,22 @@ class SSLStreams { * before this is called. Otherwise an exception will be thrown. * [Note. May need to revisit this. not quite the normal close() semantics */ - public void close () throws IOException { + public void close() throws IOException { eof = true; - engine.closeInbound (); + engine.closeInbound(); } - public int read (byte[] buf) throws IOException { - return read (buf, 0, buf.length); + public int read(byte[] buf) throws IOException { + return read(buf, 0, buf.length); } byte single[] = new byte [1]; - public int read () throws IOException { + public int read() throws IOException { if (eof) { return -1; } - int n = read (single, 0, 1); + int n = read(single, 0, 1); if (n <= 0) { return -1; } else { @@ -622,28 +622,28 @@ class SSLStreams { public void write(int b) throws IOException { single[0] = (byte)b; - write (single, 0, 1); + write(single, 0, 1); } public void write(byte b[]) throws IOException { - write (b, 0, b.length); + write(b, 0, b.length); } public void write(byte b[], int off, int len) throws IOException { if (closed) { - throw new IOException ("output stream is closed"); + throw new IOException("output stream is closed"); } while (len > 0) { int l = len > buf.capacity() ? buf.capacity() : len; buf.clear(); - buf.put (b, off, l); + buf.put(b, off, l); len -= l; off += l; buf.flip(); - WrapperResult r = sendData (buf); + WrapperResult r = sendData(buf); if (r.result.getStatus() == Status.CLOSED) { closed = true; if (len > 0) { - throw new IOException ("output stream is closed"); + throw new IOException("output stream is closed"); } } } @@ -654,13 +654,13 @@ class SSLStreams { } public void close() throws IOException { - WrapperResult r=null; + WrapperResult r = null; engine.closeOutbound(); closed = true; HandshakeStatus stat = HandshakeStatus.NEED_WRAP; buf.clear(); while (stat == HandshakeStatus.NEED_WRAP) { - r = wrapper.wrapAndSend (buf); + r = wrapper.wrapAndSend(buf); stat = r.result.getHandshakeStatus(); } assert r.result.getStatus() == Status.CLOSED diff --git a/src/jdk.httpserver/share/classes/sun/net/httpserver/ServerImpl.java b/src/jdk.httpserver/share/classes/sun/net/httpserver/ServerImpl.java index 217ae86f5d3..1eb918b4e66 100644 --- a/src/jdk.httpserver/share/classes/sun/net/httpserver/ServerImpl.java +++ b/src/jdk.httpserver/share/classes/sun/net/httpserver/ServerImpl.java @@ -128,61 +128,61 @@ class ServerImpl { private final Logger logger; private Thread dispatcherThread; - ServerImpl ( + ServerImpl( HttpServer wrapper, String protocol, InetSocketAddress addr, int backlog ) throws IOException { this.protocol = protocol; this.wrapper = wrapper; - this.logger = System.getLogger ("com.sun.net.httpserver"); - ServerConfig.checkLegacyProperties (logger); - https = protocol.equalsIgnoreCase ("https"); + this.logger = System.getLogger("com.sun.net.httpserver"); + ServerConfig.checkLegacyProperties(logger); + https = protocol.equalsIgnoreCase("https"); this.address = addr; contexts = new ContextList(); schan = ServerSocketChannel.open(); if (addr != null) { ServerSocket socket = schan.socket(); - socket.bind (addr, backlog); + socket.bind(addr, backlog); bound = true; } - selector = Selector.open (); - schan.configureBlocking (false); - listenerKey = schan.register (selector, SelectionKey.OP_ACCEPT); + selector = Selector.open(); + schan.configureBlocking(false); + listenerKey = schan.register(selector, SelectionKey.OP_ACCEPT); dispatcher = new Dispatcher(); - idleConnections = Collections.synchronizedSet (new HashSet()); - allConnections = Collections.synchronizedSet (new HashSet()); - reqConnections = Collections.synchronizedSet (new HashSet()); - rspConnections = Collections.synchronizedSet (new HashSet()); + idleConnections = Collections.synchronizedSet(new HashSet()); + allConnections = Collections.synchronizedSet(new HashSet()); + reqConnections = Collections.synchronizedSet(new HashSet()); + rspConnections = Collections.synchronizedSet(new HashSet()); newlyAcceptedConnections = Collections.synchronizedSet(new HashSet<>()); - timer = new Timer ("idle-timeout-task", true); - timer.schedule (new IdleTimeoutTask(), IDLE_TIMER_TASK_SCHEDULE, IDLE_TIMER_TASK_SCHEDULE); + timer = new Timer("idle-timeout-task", true); + timer.schedule(new IdleTimeoutTask(), IDLE_TIMER_TASK_SCHEDULE, IDLE_TIMER_TASK_SCHEDULE); if (reqRspTimeoutEnabled) { - timer1 = new Timer ("req-rsp-timeout-task", true); - timer1.schedule (new ReqRspTimeoutTask(), REQ_RSP_TIMER_SCHEDULE, REQ_RSP_TIMER_SCHEDULE); + timer1 = new Timer("req-rsp-timeout-task", true); + timer1.schedule(new ReqRspTimeoutTask(), REQ_RSP_TIMER_SCHEDULE, REQ_RSP_TIMER_SCHEDULE); logger.log(Level.DEBUG, "HttpServer request/response timeout task schedule ms: ", REQ_RSP_TIMER_SCHEDULE); - logger.log (Level.DEBUG, "MAX_REQ_TIME: "+MAX_REQ_TIME); - logger.log (Level.DEBUG, "MAX_RSP_TIME: "+MAX_RSP_TIME); + logger.log(Level.DEBUG, "MAX_REQ_TIME: "+MAX_REQ_TIME); + logger.log(Level.DEBUG, "MAX_RSP_TIME: "+MAX_RSP_TIME); } events = new ArrayList<>(); - logger.log (Level.DEBUG, "HttpServer created "+protocol+" "+ addr); + logger.log(Level.DEBUG, "HttpServer created "+protocol+" "+ addr); } - public void bind (InetSocketAddress addr, int backlog) throws IOException { + public void bind(InetSocketAddress addr, int backlog) throws IOException { if (bound) { - throw new BindException ("HttpServer already bound"); + throw new BindException("HttpServer already bound"); } if (addr == null) { - throw new NullPointerException ("null address"); + throw new NullPointerException("null address"); } ServerSocket socket = schan.socket(); - socket.bind (addr, backlog); + socket.bind(addr, backlog); bound = true; } - public void start () { + public void start() { if (!bound || started || finished()) { - throw new IllegalStateException ("server in wrong state"); + throw new IllegalStateException("server in wrong state"); } if (executor == null) { executor = new DefaultExecutor(); @@ -192,39 +192,39 @@ class ServerImpl { dispatcherThread.start(); } - public void setExecutor (Executor executor) { + public void setExecutor(Executor executor) { if (started) { - throw new IllegalStateException ("server already started"); + throw new IllegalStateException("server already started"); } this.executor = executor; } private static class DefaultExecutor implements Executor { - public void execute (Runnable task) { + public void execute(Runnable task) { task.run(); } } - public Executor getExecutor () { + public Executor getExecutor() { return executor; } - public void setHttpsConfigurator (HttpsConfigurator config) { + public void setHttpsConfigurator(HttpsConfigurator config) { if (config == null) { - throw new NullPointerException ("null HttpsConfigurator"); + throw new NullPointerException("null HttpsConfigurator"); } if (started) { - throw new IllegalStateException ("server already started"); + throw new IllegalStateException("server already started"); } this.httpsConfig = config; sslContext = config.getSSLContext(); } - public HttpsConfigurator getHttpsConfigurator () { + public HttpsConfigurator getHttpsConfigurator() { return httpsConfig; } - private final boolean finished(){ + private final boolean finished() { // if the latch is 0, the server is finished return finishedLatch.getCount() == 0; } @@ -242,9 +242,9 @@ class ServerImpl { * * @param delay maximum delay to wait for exchanges completion, in seconds */ - public void stop (int delay) { + public void stop(int delay) { if (delay < 0) { - throw new IllegalArgumentException ("negative delay parameter"); + throw new IllegalArgumentException("negative delay parameter"); } logger.log(Level.TRACE, "stopping"); @@ -298,49 +298,49 @@ class ServerImpl { Dispatcher dispatcher; - public synchronized HttpContextImpl createContext (String path, HttpHandler handler) { + public synchronized HttpContextImpl createContext(String path, HttpHandler handler) { if (handler == null || path == null) { - throw new NullPointerException ("null handler, or path parameter"); + throw new NullPointerException("null handler, or path parameter"); } - HttpContextImpl context = new HttpContextImpl (protocol, path, handler, this); - contexts.add (context); - logger.log (Level.DEBUG, "context created: " + path); + HttpContextImpl context = new HttpContextImpl(protocol, path, handler, this); + contexts.add(context); + logger.log(Level.DEBUG, "context created: " + path); return context; } - public synchronized HttpContextImpl createContext (String path) { + public synchronized HttpContextImpl createContext(String path) { if (path == null) { - throw new NullPointerException ("null path parameter"); + throw new NullPointerException("null path parameter"); } - HttpContextImpl context = new HttpContextImpl (protocol, path, null, this); - contexts.add (context); - logger.log (Level.DEBUG, "context created: " + path); + HttpContextImpl context = new HttpContextImpl(protocol, path, null, this); + contexts.add(context); + logger.log(Level.DEBUG, "context created: " + path); return context; } - public synchronized void removeContext (String path) throws IllegalArgumentException { + public synchronized void removeContext(String path) throws IllegalArgumentException { if (path == null) { - throw new NullPointerException ("null path parameter"); + throw new NullPointerException("null path parameter"); } - contexts.remove (protocol, path); - logger.log (Level.DEBUG, "context removed: " + path); + contexts.remove(protocol, path); + logger.log(Level.DEBUG, "context removed: " + path); } - public synchronized void removeContext (HttpContext context) throws IllegalArgumentException { + public synchronized void removeContext(HttpContext context) throws IllegalArgumentException { if (!(context instanceof HttpContextImpl)) { - throw new IllegalArgumentException ("wrong HttpContext type"); + throw new IllegalArgumentException("wrong HttpContext type"); } - contexts.remove ((HttpContextImpl)context); - logger.log (Level.DEBUG, "context removed: " + context.getPath()); + contexts.remove((HttpContextImpl)context); + logger.log(Level.DEBUG, "context removed: " + context.getPath()); } public InetSocketAddress getAddress() { return (InetSocketAddress) schan.socket().getLocalSocketAddress(); } - void addEvent (Event r) { + void addEvent(Event r) { synchronized (lolock) { - events.add (r); + events.add(r); selector.wakeup(); } } @@ -413,7 +413,7 @@ class ServerImpl { */ class Dispatcher implements Runnable { - private void handleEvent (Event r) { + private void handleEvent(Event r) { // Stopping marking the state as finished if stop is requested, // termination is in progress and exchange count is 0 @@ -450,22 +450,22 @@ class ServerImpl { requestCompleted(c); } } - responseCompleted (c); + responseCompleted(c); if (t.close) { c.close(); - allConnections.remove (c); + allConnections.remove(c); } else { if (is.isDataBuffered()) { /* don't re-enable the interestops, just handle it */ - requestStarted (c); - handle (c.getChannel(), c); + requestStarted(c); + handle(c.getChannel(), c); } else { - connsToRegister.add (c); + connsToRegister.add(c); } } } } catch (IOException e) { - logger.log ( + logger.log( Level.TRACE, "Dispatcher (1)", e ); c.close(); @@ -474,18 +474,18 @@ class ServerImpl { final ArrayList connsToRegister = new ArrayList<>(); - void reRegister (HttpConnection c) { + void reRegister(HttpConnection c) { /* re-register with selector */ try { SocketChannel chan = c.getChannel(); - chan.configureBlocking (false); - SelectionKey key = chan.register (selector, SelectionKey.OP_READ); - key.attach (c); + chan.configureBlocking(false); + SelectionKey key = chan.register(selector, SelectionKey.OP_READ); + key.attach(c); c.selectionKey = key; markIdle(c); } catch (IOException e) { dprint(e); - logger.log (Level.TRACE, "Dispatcher(8)", e); + logger.log(Level.TRACE, "Dispatcher (8)", e); c.close(); } } @@ -504,7 +504,7 @@ class ServerImpl { if (list != null) { for (Event r: list) { - handleEvent (r); + handleEvent(r); } } @@ -525,7 +525,7 @@ class ServerImpl { for (final SelectionKey key : selected.toArray(SelectionKey[]::new)) { // remove the key from the original selected keys (live) Set selected.remove(key); - if (key.equals (listenerKey)) { + if (key.equals(listenerKey)) { if (terminating) { continue; } @@ -546,15 +546,15 @@ class ServerImpl { if (ServerConfig.noDelay()) { chan.socket().setTcpNoDelay(true); } - chan.configureBlocking (false); + chan.configureBlocking(false); SelectionKey newkey = - chan.register (selector, SelectionKey.OP_READ); - HttpConnection c = new HttpConnection (); + chan.register(selector, SelectionKey.OP_READ); + HttpConnection c = new HttpConnection(); c.selectionKey = newkey; - c.setChannel (chan); - newkey.attach (c); + c.setChannel(chan); + newkey.attach(c); markNewlyAccepted(c); - allConnections.add (c); + allConnections.add(c); } } else { try { @@ -563,7 +563,7 @@ class ServerImpl { HttpConnection conn = (HttpConnection)key.attachment(); key.cancel(); - chan.configureBlocking (true); + chan.configureBlocking(true); // check if connection is being closed if (newlyAcceptedConnections.remove(conn) || idleConnections.remove(conn)) { @@ -571,7 +571,7 @@ class ServerImpl { // connection. In either case, we mark that the request // has now started on this connection. requestStarted(conn); - handle (chan, conn); + handle(chan, conn); } } else { assert false : "Unexpected non-readable key:" + key; @@ -586,56 +586,56 @@ class ServerImpl { // call the selector just to process the cancelled keys selector.selectNow(); } catch (IOException e) { - logger.log (Level.TRACE, "Dispatcher (4)", e); + logger.log(Level.TRACE, "Dispatcher (4)", e); } catch (Exception e) { - logger.log (Level.TRACE, "Dispatcher (7)", e); + logger.log(Level.TRACE, "Dispatcher (7)", e); } } - try {selector.close(); } catch (Exception e) {} + try { selector.close(); } catch (Exception e) {} } - private void handleException (SelectionKey key, Exception e) { + private void handleException(SelectionKey key, Exception e) { HttpConnection conn = (HttpConnection)key.attachment(); if (e != null) { - logger.log (Level.TRACE, "Dispatcher (2)", e); + logger.log(Level.TRACE, "Dispatcher (2)", e); } closeConnection(conn); } - public void handle (SocketChannel chan, HttpConnection conn) + public void handle(SocketChannel chan, HttpConnection conn) { try { - Exchange t = new Exchange (chan, protocol, conn); - executor.execute (t); + Exchange t = new Exchange(chan, protocol, conn); + executor.execute(t); } catch (HttpError e1) { - logger.log (Level.TRACE, "Dispatcher (4)", e1); + logger.log(Level.TRACE, "Dispatcher (4)", e1); closeConnection(conn); } catch (IOException e) { - logger.log (Level.TRACE, "Dispatcher (5)", e); + logger.log(Level.TRACE, "Dispatcher (5)", e); closeConnection(conn); } catch (Throwable e) { - logger.log (Level.TRACE, "Dispatcher (6)", e); + logger.log(Level.TRACE, "Dispatcher (6)", e); closeConnection(conn); } } } - static boolean debug = ServerConfig.debugEnabled (); + static boolean debug = ServerConfig.debugEnabled(); - static synchronized void dprint (String s) { + static synchronized void dprint(String s) { if (debug) { - System.out.println (s); + System.out.println(s); } } - static synchronized void dprint (Exception e) { + static synchronized void dprint(Exception e) { if (debug) { - System.out.println (e); + System.out.println(e); e.printStackTrace(); } } - Logger getLogger () { + Logger getLogger() { return logger; } @@ -675,13 +675,13 @@ class ServerImpl { HttpContextImpl ctx; boolean rejected = false; - Exchange (SocketChannel chan, String protocol, HttpConnection conn) throws IOException { + Exchange(SocketChannel chan, String protocol, HttpConnection conn) throws IOException { this.chan = chan; this.connection = conn; this.protocol = protocol; } - public void run () { + public void run() { /* context will be null for new connections */ logger.log(Level.TRACE, "exchange started"); @@ -702,7 +702,7 @@ class ServerImpl { String requestLine = null; SSLStreams sslStreams = null; try { - if (context != null ) { + if (context != null) { this.rawin = connection.getInputStream(); this.rawout = connection.getRawOutputStream(); newconnection = false; @@ -711,21 +711,21 @@ class ServerImpl { newconnection = true; if (https) { if (sslContext == null) { - logger.log (Level.WARNING, + logger.log(Level.WARNING, "SSL connection received. No https context created"); - throw new HttpError ("No SSL context established"); + throw new HttpError("No SSL context established"); } - sslStreams = new SSLStreams (ServerImpl.this, sslContext, chan); + sslStreams = new SSLStreams(ServerImpl.this, sslContext, chan); rawin = sslStreams.getInputStream(); rawout = sslStreams.getOutputStream(); engine = sslStreams.getSSLEngine(); connection.sslStreams = sslStreams; } else { rawin = new BufferedInputStream( - new Request.ReadStream ( + new Request.ReadStream( ServerImpl.this, chan )); - rawout = new Request.WriteStream ( + rawout = new Request.WriteStream( ServerImpl.this, chan ); } @@ -733,7 +733,7 @@ class ServerImpl { connection.raw = rawin; connection.rawout = rawout; } - Request req = new Request (rawin, rawout); + Request req = new Request(rawin, rawout); requestLine = req.requestLine(); if (requestLine == null) { /* connection closed */ @@ -742,31 +742,31 @@ class ServerImpl { return; } logger.log(Level.DEBUG, "Exchange request line: {0}", requestLine); - int space = requestLine.indexOf (' '); + int space = requestLine.indexOf(' '); if (space == -1) { - reject (Code.HTTP_BAD_REQUEST, + reject(Code.HTTP_BAD_REQUEST, requestLine, "Bad request line"); return; } - String method = requestLine.substring (0, space); + String method = requestLine.substring(0, space); int start = space+1; space = requestLine.indexOf(' ', start); if (space == -1) { - reject (Code.HTTP_BAD_REQUEST, + reject(Code.HTTP_BAD_REQUEST, requestLine, "Bad request line"); return; } - String uriStr = requestLine.substring (start, space); + String uriStr = requestLine.substring(start, space); URI uri; try { - uri = new URI (uriStr); + uri = new URI(uriStr); } catch (URISyntaxException e3) { reject(Code.HTTP_BAD_REQUEST, requestLine, "URISyntaxException thrown"); return; } start = space+1; - String version = requestLine.substring (start); + String version = requestLine.substring(start); Headers headers = req.headers(); /* check key for illegal characters */ for (var k : headers.keySet()) { @@ -817,32 +817,32 @@ class ServerImpl { requestCompleted(connection); } } - ctx = contexts.findContext (protocol, uri.getPath()); + ctx = contexts.findContext(protocol, uri.getPath()); if (ctx == null) { - reject (Code.HTTP_NOT_FOUND, + reject(Code.HTTP_NOT_FOUND, requestLine, "No context found for request"); return; } - connection.setContext (ctx); + connection.setContext(ctx); if (ctx.getHandler() == null) { - reject (Code.HTTP_INTERNAL_ERROR, + reject(Code.HTTP_INTERNAL_ERROR, requestLine, "No handler for context"); return; } - tx = new ExchangeImpl ( + tx = new ExchangeImpl( method, uri, req, clen, connection ); String chdr = headers.getFirst("Connection"); Headers rheaders = tx.getResponseHeaders(); - if (chdr != null && chdr.equalsIgnoreCase ("close")) { + if (chdr != null && chdr.equalsIgnoreCase("close")) { tx.close = true; } - if (version.equalsIgnoreCase ("http/1.0")) { + if (version.equalsIgnoreCase("http/1.0")) { tx.http10 = true; if (chdr == null) { tx.close = true; - rheaders.set ("Connection", "close"); + rheaders.set("Connection", "close"); } else if (chdr.equalsIgnoreCase("keep-alive")) { rheaders.set("Connection", "keep-alive"); int idleSeconds = (int) (ServerConfig.getIdleIntervalMillis() / 1000); @@ -852,7 +852,7 @@ class ServerImpl { } if (newconnection) { - connection.setParameters ( + connection.setParameters( rawin, rawout, chan, engine, sslStreams, sslContext, protocol, ctx, rawin ); @@ -863,9 +863,9 @@ class ServerImpl { * be involved in this process. */ String exp = headers.getFirst("Expect"); - if (exp != null && exp.equalsIgnoreCase ("100-continue")) { - logReply (100, requestLine, null); - sendReply ( + if (exp != null && exp.equalsIgnoreCase("100-continue")) { + logReply(100, requestLine, null); + sendReply( Code.HTTP_CONTINUE, false, null ); } @@ -880,19 +880,19 @@ class ServerImpl { final List uf = ctx.getFilters(); final Filter.Chain sc = new Filter.Chain(sf, ctx.getHandler()); - final Filter.Chain uc = new Filter.Chain(uf, new LinkHandler (sc)); + final Filter.Chain uc = new Filter.Chain(uf, new LinkHandler(sc)); /* set up the two stream references */ tx.getRequestBody(); tx.getResponseBody(); if (https) { - uc.doFilter (new HttpsExchangeImpl (tx)); + uc.doFilter(new HttpsExchangeImpl(tx)); } else { - uc.doFilter (new HttpExchangeImpl (tx)); + uc.doFilter(new HttpExchangeImpl(tx)); } } catch (Exception e) { - logger.log (Level.TRACE, "ServerImpl.Exchange", e); + logger.log(Level.TRACE, "ServerImpl.Exchange", e); if (tx == null || !tx.writefinished) { closeConnection(connection); } @@ -907,59 +907,59 @@ class ServerImpl { class LinkHandler implements HttpHandler { Filter.Chain nextChain; - LinkHandler (Filter.Chain nextChain) { + LinkHandler(Filter.Chain nextChain) { this.nextChain = nextChain; } - public void handle (HttpExchange exchange) throws IOException { - nextChain.doFilter (exchange); + public void handle(HttpExchange exchange) throws IOException { + nextChain.doFilter(exchange); } } - void reject (int code, String requestStr, String message) { + void reject(int code, String requestStr, String message) { rejected = true; - logReply (code, requestStr, message); - sendReply ( + logReply(code, requestStr, message); + sendReply( code, true, "

      "+code+Code.msg(code)+"

      "+message ); } - void sendReply ( + void sendReply( int code, boolean closeNow, String text) { try { - StringBuilder builder = new StringBuilder (512); - builder.append ("HTTP/1.1 ") - .append (code).append (Code.msg(code)).append ("\r\n"); + StringBuilder builder = new StringBuilder(512); + builder.append("HTTP/1.1 ") + .append(code).append(Code.msg(code)).append("\r\n"); if (text != null && text.length() != 0) { - builder.append ("Content-Length: ") - .append (text.length()).append ("\r\n") - .append ("Content-Type: text/html\r\n"); + builder.append("Content-Length: ") + .append(text.length()).append("\r\n") + .append("Content-Type: text/html\r\n"); } else { - builder.append ("Content-Length: 0\r\n"); + builder.append("Content-Length: 0\r\n"); text = ""; } if (closeNow) { - builder.append ("Connection: close\r\n"); + builder.append("Connection: close\r\n"); } - builder.append ("\r\n").append (text); + builder.append("\r\n").append(text); String s = builder.toString(); byte[] b = s.getBytes(ISO_8859_1); - rawout.write (b); + rawout.write(b); rawout.flush(); if (closeNow) { closeConnection(connection); } } catch (IOException e) { - logger.log (Level.TRACE, "ServerImpl.sendReply", e); + logger.log(Level.TRACE, "ServerImpl.sendReply", e); closeConnection(connection); } } } - void logReply (int code, String requestStr, String text) { + void logReply(int code, String requestStr, String text) { if (!logger.isLoggable(Level.DEBUG)) { return; } @@ -968,18 +968,18 @@ class ServerImpl { } String r; if (requestStr.length() > 80) { - r = requestStr.substring (0, 80) + ""; + r = requestStr.substring(0, 80) + ""; } else { r = requestStr; } String message = r + " [" + code + " " + Code.msg(code) + "] ("+text+")"; - logger.log (Level.DEBUG, message); + logger.log(Level.DEBUG, message); } private int exchangeCount = 0; - synchronized void startExchange () { + synchronized void startExchange() { exchangeCount ++; } @@ -987,20 +987,20 @@ class ServerImpl { return exchangeCount; } - synchronized int endExchange () { + synchronized int endExchange() { exchangeCount --; assert exchangeCount >= 0; return exchangeCount; } - HttpServer getWrapper () { + HttpServer getWrapper() { return wrapper; } - void requestStarted (HttpConnection c) { + void requestStarted(HttpConnection c) { c.reqStartedTime = System.currentTimeMillis(); - c.setState (State.REQUEST); - reqConnections.add (c); + c.setState(State.REQUEST); + reqConnections.add(c); } void markIdle(HttpConnection c) { @@ -1037,21 +1037,21 @@ class ServerImpl { // that ensures the client reads the response in a timely // fashion. - void requestCompleted (HttpConnection c) { + void requestCompleted(HttpConnection c) { State s = c.getState(); assert s == State.REQUEST : "State is not REQUEST ("+s+")"; - reqConnections.remove (c); + reqConnections.remove(c); c.rspStartedTime = System.currentTimeMillis(); - rspConnections.add (c); - c.setState (State.RESPONSE); + rspConnections.add(c); + c.setState(State.RESPONSE); } // called after response has been sent - void responseCompleted (HttpConnection c) { + void responseCompleted(HttpConnection c) { State s = c.getState(); assert s == State.RESPONSE : "State is not RESPONSE ("+s+")"; - rspConnections.remove (c); - c.setState (State.IDLE); + rspConnections.remove(c); + c.setState(State.IDLE); } /** @@ -1059,7 +1059,7 @@ class ServerImpl { * TimerTask run every CLOCK_TICK ms */ class IdleTimeoutTask extends TimerTask { - public void run () { + public void run() { closeConnections(idleConnections, IDLE_INTERVAL); // if any newly accepted connection has been idle (i.e. no byte has been sent on that // connection during the configured idle timeout period) then close it as well @@ -1095,20 +1095,20 @@ class ServerImpl { class ReqRspTimeoutTask extends TimerTask { // runs every TIMER_MILLIS - public void run () { + public void run() { ArrayList toClose = new ArrayList<>(); final long currentTime = System.currentTimeMillis(); synchronized (reqConnections) { if (MAX_REQ_TIME != -1) { for (HttpConnection c : reqConnections) { if (currentTime - c.reqStartedTime >= MAX_REQ_TIME) { - toClose.add (c); + toClose.add(c); } } for (HttpConnection c : toClose) { - logger.log (Level.DEBUG, "closing: no request: " + c); - reqConnections.remove (c); - allConnections.remove (c); + logger.log(Level.DEBUG, "closing: no request: " + c); + reqConnections.remove(c); + allConnections.remove(c); c.close(); } } @@ -1118,13 +1118,13 @@ class ServerImpl { if (MAX_RSP_TIME != -1) { for (HttpConnection c : rspConnections) { if (currentTime - c.rspStartedTime >= MAX_RSP_TIME) { - toClose.add (c); + toClose.add(c); } } for (HttpConnection c : toClose) { - logger.log (Level.DEBUG, "closing: no response: " + c); - rspConnections.remove (c); - allConnections.remove (c); + logger.log(Level.DEBUG, "closing: no response: " + c); + rspConnections.remove(c); + allConnections.remove(c); c.close(); } } diff --git a/src/jdk.httpserver/share/classes/sun/net/httpserver/UndefLengthOutputStream.java b/src/jdk.httpserver/share/classes/sun/net/httpserver/UndefLengthOutputStream.java index 7bfc39c84a1..ecda32ecc31 100644 --- a/src/jdk.httpserver/share/classes/sun/net/httpserver/UndefLengthOutputStream.java +++ b/src/jdk.httpserver/share/classes/sun/net/httpserver/UndefLengthOutputStream.java @@ -40,30 +40,30 @@ class UndefLengthOutputStream extends FilterOutputStream private boolean closed = false; ExchangeImpl t; - UndefLengthOutputStream (ExchangeImpl t, OutputStream src) { - super (src); + UndefLengthOutputStream(ExchangeImpl t, OutputStream src) { + super(src); this.t = t; } - public void write (int b) throws IOException { + public void write(int b) throws IOException { if (closed) { - throw new IOException ("stream closed"); + throw new IOException("stream closed"); } out.write(b); } - public void write (byte[]b, int off, int len) throws IOException { + public void write(byte[] b, int off, int len) throws IOException { Objects.checkFromIndexSize(off, len, b.length); if (len == 0) { return; } if (closed) { - throw new IOException ("stream closed"); + throw new IOException("stream closed"); } out.write(b, off, len); } - public void close () throws IOException { + public void close() throws IOException { if (closed) { return; } @@ -76,7 +76,7 @@ class UndefLengthOutputStream extends FilterOutputStream } catch (IOException e) {} } Event e = new Event.WriteFinished(t); - t.getHttpContext().getServerImpl().addEvent (e); + t.getHttpContext().getServerImpl().addEvent(e); } // flush is a pass-through diff --git a/src/jdk.httpserver/share/classes/sun/net/httpserver/UnmodifiableHeaders.java b/src/jdk.httpserver/share/classes/sun/net/httpserver/UnmodifiableHeaders.java index 91bfc186828..503004b35e0 100644 --- a/src/jdk.httpserver/share/classes/sun/net/httpserver/UnmodifiableHeaders.java +++ b/src/jdk.httpserver/share/classes/sun/net/httpserver/UnmodifiableHeaders.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -62,32 +62,32 @@ public class UnmodifiableHeaders extends Headers { @Override public List put(String key, List value) { - throw new UnsupportedOperationException ("unsupported operation"); + throw new UnsupportedOperationException("unsupported operation"); } @Override public void add(String key, String value) { - throw new UnsupportedOperationException ("unsupported operation"); + throw new UnsupportedOperationException("unsupported operation"); } @Override public void set(String key, String value) { - throw new UnsupportedOperationException ("unsupported operation"); + throw new UnsupportedOperationException("unsupported operation"); } @Override public List remove(Object key) { - throw new UnsupportedOperationException ("unsupported operation"); + throw new UnsupportedOperationException("unsupported operation"); } @Override public void putAll(Map> t) { - throw new UnsupportedOperationException ("unsupported operation"); + throw new UnsupportedOperationException("unsupported operation"); } @Override public void clear() { - throw new UnsupportedOperationException ("unsupported operation"); + throw new UnsupportedOperationException("unsupported operation"); } @Override @@ -106,19 +106,19 @@ public class UnmodifiableHeaders extends Headers { @Override public boolean replace(String key, List oldValue, List newValue) { - throw new UnsupportedOperationException ("unsupported operation"); + throw new UnsupportedOperationException("unsupported operation"); } @Override public void replaceAll(BiFunction, ? extends List> function) { - throw new UnsupportedOperationException ("unsupported operation"); + throw new UnsupportedOperationException("unsupported operation"); } @Override - public boolean equals(Object o) {return headers.equals(o);} + public boolean equals(Object o) { return headers.equals(o); } @Override - public int hashCode() {return headers.hashCode();} + public int hashCode() { return headers.hashCode(); } @Override public String toString() { diff --git a/src/jdk.httpserver/share/classes/sun/net/httpserver/simpleserver/FileServerHandler.java b/src/jdk.httpserver/share/classes/sun/net/httpserver/simpleserver/FileServerHandler.java index 3a3654d4a73..cbf032e8398 100644 --- a/src/jdk.httpserver/share/classes/sun/net/httpserver/simpleserver/FileServerHandler.java +++ b/src/jdk.httpserver/share/classes/sun/net/httpserver/simpleserver/FileServerHandler.java @@ -367,7 +367,7 @@ public final class FileServerHandler implements HttpHandler { // A non-exhaustive map of reserved-HTML and special characters to their // equivalent entity. - private static final Map RESERVED_CHARS = Map.of( + private static final Map RESERVED_CHARS = Map.of( (int) '&' , "&" , (int) '<' , "<" , (int) '>' , ">" , From a05d5d2514c835f2bfeaf7a8c7df0ac241f0177f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Maillard?= Date: Fri, 12 Dec 2025 13:45:28 +0000 Subject: [PATCH 267/706] 8373579: Problem list compiler/runtime/Test7196199.java Reviewed-by: chagedorn, epeter --- test/hotspot/jtreg/ProblemList.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index 177c14da785..4e16e328ab4 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -49,6 +49,7 @@ compiler/cpuflags/TestAESIntrinsicsOnSupportedConfig.java 8190680 generic-all compiler/runtime/Test8168712.java#with-dtrace 8211769,8211771 generic-ppc64,generic-ppc64le,linux-s390x compiler/runtime/Test8168712.java#without-dtrace 8211769,8211771 generic-ppc64,generic-ppc64le,linux-s390x +compiler/runtime/Test7196199.java 8365196 windows-x64 compiler/c2/Test8004741.java 8235801 generic-all compiler/c2/irTests/TestDuplicateBackedge.java 8318904 generic-all From 410014377c210463d654b841bafbcf36947aa960 Mon Sep 17 00:00:00 2001 From: Kelvin Nilsen Date: Fri, 12 Dec 2025 14:02:35 +0000 Subject: [PATCH 268/706] 8373225: GenShen: More adaptive old-generation growth heuristics Reviewed-by: wkemper, ysr --- .../shenandoahGenerationalHeuristics.cpp | 2 +- .../heuristics/shenandoahOldHeuristics.cpp | 49 +++++++++++++++++-- .../heuristics/shenandoahOldHeuristics.hpp | 30 ++++++++++++ .../gc/shenandoah/shenandoahGeneration.cpp | 11 +++-- .../gc/shenandoah/shenandoahGeneration.hpp | 2 +- .../shenandoahGenerationalEvacuationTask.cpp | 5 +- .../shenandoahGenerationalFullGC.cpp | 2 +- .../gc/shenandoah/shenandoahOldGeneration.cpp | 37 +++++++++----- .../gc/shenandoah/shenandoahOldGeneration.hpp | 33 ++++++------- .../gc/shenandoah/shenandoah_globals.hpp | 37 +++++++++----- .../generational/TestOldGrowthTriggers.java | 9 +++- 11 files changed, 158 insertions(+), 59 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.cpp index cab6abc4e6f..b14d72f249b 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.cpp @@ -104,7 +104,7 @@ void ShenandoahGenerationalHeuristics::choose_collection_set(ShenandoahCollectio // Note that for GLOBAL GC, region may be OLD, and OLD regions do not qualify for pre-selection // This region is old enough to be promoted but it was not preselected, either because its garbage is below - // ShenandoahOldGarbageThreshold so it will be promoted in place, or because there is not sufficient room + // old garbage threshold so it will be promoted in place, or because there is not sufficient room // in old gen to hold the evacuated copies of this region's live data. In both cases, we choose not to // place this region into the collection set. if (region->get_top_before_promote() != nullptr) { diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahOldHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahOldHeuristics.cpp index 1e4d40cfa46..1f257560bcb 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahOldHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahOldHeuristics.cpp @@ -71,7 +71,8 @@ ShenandoahOldHeuristics::ShenandoahOldHeuristics(ShenandoahOldGeneration* genera _growth_trigger(false), _fragmentation_density(0.0), _fragmentation_first_old_region(0), - _fragmentation_last_old_region(0) + _fragmentation_last_old_region(0), + _old_garbage_threshold(ShenandoahOldGarbageThreshold) { } @@ -373,7 +374,8 @@ void ShenandoahOldHeuristics::prepare_for_old_collections() { } } - _old_generation->set_live_bytes_after_last_mark(live_data); + // TODO: subtract from live_data bytes promoted during concurrent GC. + _old_generation->set_live_bytes_at_last_mark(live_data); // Unlike young, we are more interested in efficiently packing OLD-gen than in reclaiming garbage first. We sort by live-data. // Some regular regions may have been promoted in place with no garbage but also with very little live data. When we "compact" @@ -385,7 +387,7 @@ void ShenandoahOldHeuristics::prepare_for_old_collections() { const size_t region_size_bytes = ShenandoahHeapRegion::region_size_bytes(); // The convention is to collect regions that have more than this amount of garbage. - const size_t garbage_threshold = region_size_bytes * ShenandoahOldGarbageThreshold / 100; + const size_t garbage_threshold = region_size_bytes * get_old_garbage_threshold() / 100; // Enlightened interpretation: collect regions that have less than this amount of live. const size_t live_threshold = region_size_bytes - garbage_threshold; @@ -655,6 +657,7 @@ bool ShenandoahOldHeuristics::should_start_gc() { const double percent = percent_of(old_gen_capacity, heap_capacity); log_trigger("Expansion failure, current size: %zu%s which is %.1f%% of total heap size", byte_size_in_proper_unit(old_gen_capacity), proper_unit_for_byte_size(old_gen_capacity), percent); + adjust_old_garbage_threshold(); return true; } @@ -677,6 +680,7 @@ bool ShenandoahOldHeuristics::should_start_gc() { "%zu to %zu (%zu), density: %.1f%%", byte_size_in_proper_unit(fragmented_free), proper_unit_for_byte_size(fragmented_free), first_old_region, last_old_region, span_of_old_regions, density * 100); + adjust_old_garbage_threshold(); return true; } @@ -699,12 +703,13 @@ bool ShenandoahOldHeuristics::should_start_gc() { consecutive_young_cycles); _growth_trigger = false; } else if (current_usage > trigger_threshold) { - const size_t live_at_previous_old = _old_generation->get_live_bytes_after_last_mark(); + const size_t live_at_previous_old = _old_generation->get_live_bytes_at_last_mark(); const double percent_growth = percent_of(current_usage - live_at_previous_old, live_at_previous_old); log_trigger("Old has overgrown, live at end of previous OLD marking: " "%zu%s, current usage: %zu%s, percent growth: %.1f%%", byte_size_in_proper_unit(live_at_previous_old), proper_unit_for_byte_size(live_at_previous_old), byte_size_in_proper_unit(current_usage), proper_unit_for_byte_size(current_usage), percent_growth); + adjust_old_garbage_threshold(); return true; } else { // Mixed evacuations have decreased current_usage such that old-growth trigger is no longer relevant. @@ -713,7 +718,41 @@ bool ShenandoahOldHeuristics::should_start_gc() { } // Otherwise, defer to inherited heuristic for gc trigger. - return this->ShenandoahHeuristics::should_start_gc(); + bool result = this->ShenandoahHeuristics::should_start_gc(); + if (result) { + adjust_old_garbage_threshold(); + } + return result; +} + +void ShenandoahOldHeuristics::adjust_old_garbage_threshold() { + const uintx MinimumOldGarbageThreshold = 10; + const uintx InterventionPercentage = 50; + + const ShenandoahHeap* heap = ShenandoahHeap::heap(); + size_t old_regions_size = _old_generation->used_regions_size(); + size_t soft_max_size = heap->soft_max_capacity(); + uintx percent_used = (uintx) ((old_regions_size * 100) / soft_max_size); + _old_garbage_threshold = ShenandoahOldGarbageThreshold; + if (percent_used > InterventionPercentage) { + uintx severity = percent_used - InterventionPercentage; // ranges from 0 to 50 + if (MinimumOldGarbageThreshold < ShenandoahOldGarbageThreshold) { + uintx adjustment_potential = ShenandoahOldGarbageThreshold - MinimumOldGarbageThreshold; + // With default values: + // if percent_used > 80, garbage_threshold is 10 + // else if percent_used > 65, garbage_threshold is 15 + // else if percent_used > 50, garbage_threshold is 20 + if (severity > 30) { + _old_garbage_threshold = ShenandoahOldGarbageThreshold - adjustment_potential; + } else if (severity > 15) { + _old_garbage_threshold = ShenandoahOldGarbageThreshold - 2 * adjustment_potential / 3; + } else { + _old_garbage_threshold = ShenandoahOldGarbageThreshold - adjustment_potential / 3; + } + log_info(gc)("Adjusting old garbage threshold to %lu because Old Generation used regions represents %lu%% of heap", + _old_garbage_threshold, percent_used); + } + } } void ShenandoahOldHeuristics::record_success_concurrent() { diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahOldHeuristics.hpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahOldHeuristics.hpp index 8d3fec746ba..288d3d68e56 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahOldHeuristics.hpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahOldHeuristics.hpp @@ -102,6 +102,17 @@ private: size_t _fragmentation_first_old_region; size_t _fragmentation_last_old_region; + // The value of command-line argument ShenandoahOldGarbageThreshold represents the percent of garbage that must + // be present within an old-generation region before that region is considered a good candidate for inclusion in + // the collection set under normal circumstances. For our purposes, normal circustances are when the memory consumed + // by the old generation is less than 50% of the soft heap capacity. When the old generation grows beyond the 50% + // threshold, we dynamically adjust the old garbage threshold, allowing us to invest in packing the old generation + // more tightly so that more memory can be made available to the more frequent young GC cycles. This variable + // is used in place of ShenandoahOldGarbageThreshold. Under normal circumstances, its value is equal to + // ShenandoahOldGarbageThreshold. When the GC is under duress, this value may be adjusted to a smaller value, + // as scaled according to the severity of duress that we are experiencing. + uintx _old_garbage_threshold; + // Compare by live is used to prioritize compaction of old-gen regions. With old-gen compaction, the goal is // to tightly pack long-lived objects into available regions. In most cases, there has not been an accumulation // of garbage within old-gen regions. The more likely opportunity will be to combine multiple sparsely populated @@ -200,9 +211,28 @@ public: bool is_experimental() override; + // Returns the current value of a dynamically adjusted threshold percentage of garbage above which an old region is + // deemed eligible for evacuation. + inline uintx get_old_garbage_threshold() { return _old_garbage_threshold; } + private: void slide_pinned_regions_to_front(); bool all_candidates_are_pinned(); + + // The normal old_garbage_threshold is specified by ShenandoahOldGarbageThreshold command-line argument, with default + // value 25, denoting that a region that has at least 25% garbage is eligible for evacuation. With default values for + // all command-line arguments, we make the following adjustments: + // 1. If the old generation has grown to consume more than 80% of the soft max capacity, adjust threshold to 10% + // 2. Otherwise, if the old generation has grown to consume more than 65%, adjust threshold to 15% + // 3. Otherwise, if the old generation has grown to consume more than 50%, adjust threshold to 20% + // The effect is to compact the old generation more aggressively as the old generation consumes larger percentages + // of the available heap memory. In these circumstances, we pack the old generation more tightly in order to make + // more memory avaiable to the young generation so that the more frequent young collections can operate more + // efficiently. + // + // If the ShenandoahOldGarbageThreshold is specified on the command line, the effect of adjusting the old garbage + // threshold is scaled linearly. + void adjust_old_garbage_threshold(); }; #endif // SHARE_GC_SHENANDOAH_HEURISTICS_SHENANDOAHOLDHEURISTICS_HPP diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp index 55d6033b3bc..b9295654b6f 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp @@ -505,10 +505,10 @@ inline void assert_no_in_place_promotions() { #endif } -// Preselect for inclusion into the collection set regions whose age is at or above tenure age which contain more than -// ShenandoahOldGarbageThreshold amounts of garbage. We identify these regions by setting the appropriate entry of -// the collection set's preselected regions array to true. All entries are initialized to false before calling this -// function. +// Preselect for inclusion into the collection set all regions whose age is at or above tenure age and for which the +// garbage percentage exceeds a dynamically adjusted threshold (known as the old-garbage threshold percentage). We +// identify these regions by setting the appropriate entry of the collection set's preselected regions array to true. +// All entries are initialized to false before calling this function. // // During the subsequent selection of the collection set, we give priority to these promotion set candidates. // Without this prioritization, we found that the aged regions tend to be ignored because they typically have @@ -531,7 +531,8 @@ size_t ShenandoahGeneration::select_aged_regions(const size_t old_promotion_rese bool* const candidate_regions_for_promotion_by_copy = heap->collection_set()->preselected_regions(); ShenandoahMarkingContext* const ctx = heap->marking_context(); - const size_t old_garbage_threshold = (ShenandoahHeapRegion::region_size_bytes() * ShenandoahOldGarbageThreshold) / 100; + const size_t old_garbage_threshold = + (ShenandoahHeapRegion::region_size_bytes() * heap->old_generation()->heuristics()->get_old_garbage_threshold()) / 100; const size_t pip_used_threshold = (ShenandoahHeapRegion::region_size_bytes() * ShenandoahGenerationalMinPIPUsage) / 100; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.hpp b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.hpp index 424a00f789d..6f393110666 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.hpp @@ -71,7 +71,7 @@ private: // garbage-dense regions, including those that satisfy criteria 1 & 2 below, // and whose live bytes will fit within old_available budget: // Criterion 1. region age >= tenuring threshold - // Criterion 2. region garbage percentage > ShenandoahOldGarbageThreshold + // Criterion 2. region garbage percentage > old garbage threshold // // Identifies regions eligible for promotion in place, // being those of at least tenuring_threshold age that have lower garbage diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalEvacuationTask.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalEvacuationTask.cpp index 4a3faa2c707..de45877994c 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalEvacuationTask.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalEvacuationTask.cpp @@ -145,7 +145,7 @@ void ShenandoahGenerationalEvacuationTask::maybe_promote_region(ShenandoahHeapRe // triggers the load-reference barrier (LRB) to copy on reference fetch. // // Aged humongous continuation regions are handled with their start region. If an aged regular region has - // more garbage than ShenandoahOldGarbageThreshold, we'll promote by evacuation. If there is room for evacuation + // more garbage than the old garbage threshold, we'll promote by evacuation. If there is room for evacuation // in this cycle, the region will be in the collection set. If there is not room, the region will be promoted // by evacuation in some future GC cycle. @@ -177,7 +177,8 @@ void ShenandoahGenerationalEvacuationTask::promote_in_place(ShenandoahHeapRegion size_t region_size_bytes = ShenandoahHeapRegion::region_size_bytes(); { - const size_t old_garbage_threshold = (region_size_bytes * ShenandoahOldGarbageThreshold) / 100; + const size_t old_garbage_threshold = + (region_size_bytes * _heap->old_generation()->heuristics()->get_old_garbage_threshold()) / 100; assert(!_heap->is_concurrent_old_mark_in_progress(), "Cannot promote in place during old marking"); assert(region->garbage_before_padded_for_promote() < old_garbage_threshold, "Region %zu has too much garbage for promotion", region->index()); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalFullGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalFullGC.cpp index ef913362df3..78672ee10a5 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalFullGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalFullGC.cpp @@ -83,7 +83,7 @@ void ShenandoahGenerationalFullGC::handle_completion(ShenandoahHeap* heap) { assert_usage_not_more_than_regions_used(young); // Establish baseline for next old-has-grown trigger. - old->set_live_bytes_after_last_mark(old->used()); + old->set_live_bytes_at_last_mark(old->used()); } void ShenandoahGenerationalFullGC::rebuild_remembered_set(ShenandoahHeap* heap) { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp b/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp index 6a0f986cde5..c7cf013d034 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp @@ -116,11 +116,10 @@ ShenandoahOldGeneration::ShenandoahOldGeneration(uint max_queues) _is_parsable(true), _card_scan(nullptr), _state(WAITING_FOR_BOOTSTRAP), - _growth_before_compaction(INITIAL_GROWTH_BEFORE_COMPACTION), - _min_growth_before_compaction ((ShenandoahMinOldGenGrowthPercent * FRACTIONAL_DENOMINATOR) / 100) + _growth_percent_before_collection(INITIAL_GROWTH_PERCENT_BEFORE_COLLECTION) { assert(type() == ShenandoahGenerationType::OLD, "OO sanity"); - _live_bytes_after_last_mark = ShenandoahHeap::heap()->capacity() * INITIAL_LIVE_FRACTION / FRACTIONAL_DENOMINATOR; + _live_bytes_at_last_mark = (ShenandoahHeap::heap()->soft_max_capacity() * INITIAL_LIVE_PERCENT) / 100; // Always clear references for old generation ref_processor()->set_soft_reference_policy(true); @@ -221,20 +220,20 @@ ShenandoahOldGeneration::configure_plab_for_current_thread(const ShenandoahAlloc } } -size_t ShenandoahOldGeneration::get_live_bytes_after_last_mark() const { - return _live_bytes_after_last_mark; +size_t ShenandoahOldGeneration::get_live_bytes_at_last_mark() const { + return _live_bytes_at_last_mark; } -void ShenandoahOldGeneration::set_live_bytes_after_last_mark(size_t bytes) { +void ShenandoahOldGeneration::set_live_bytes_at_last_mark(size_t bytes) { if (bytes == 0) { // Restart search for best old-gen size to the initial state - _live_bytes_after_last_mark = ShenandoahHeap::heap()->capacity() * INITIAL_LIVE_FRACTION / FRACTIONAL_DENOMINATOR; - _growth_before_compaction = INITIAL_GROWTH_BEFORE_COMPACTION; + _live_bytes_at_last_mark = (ShenandoahHeap::heap()->soft_max_capacity() * INITIAL_LIVE_PERCENT) / 100; + _growth_percent_before_collection = INITIAL_GROWTH_PERCENT_BEFORE_COLLECTION; } else { - _live_bytes_after_last_mark = bytes; - _growth_before_compaction /= 2; - if (_growth_before_compaction < _min_growth_before_compaction) { - _growth_before_compaction = _min_growth_before_compaction; + _live_bytes_at_last_mark = bytes; + _growth_percent_before_collection /= 2; + if (_growth_percent_before_collection < ShenandoahMinOldGenGrowthPercent) { + _growth_percent_before_collection = ShenandoahMinOldGenGrowthPercent; } } } @@ -244,7 +243,19 @@ void ShenandoahOldGeneration::handle_failed_transfer() { } size_t ShenandoahOldGeneration::usage_trigger_threshold() const { - size_t result = _live_bytes_after_last_mark + (_live_bytes_after_last_mark * _growth_before_compaction) / FRACTIONAL_DENOMINATOR; + size_t threshold_by_relative_growth = + _live_bytes_at_last_mark + (_live_bytes_at_last_mark * _growth_percent_before_collection) / 100; + size_t soft_max_capacity = ShenandoahHeap::heap()->soft_max_capacity(); + size_t threshold_by_growth_into_percent_remaining; + if (_live_bytes_at_last_mark < soft_max_capacity) { + threshold_by_growth_into_percent_remaining = (size_t) + (_live_bytes_at_last_mark + ((soft_max_capacity - _live_bytes_at_last_mark) + * ShenandoahMinOldGenGrowthRemainingHeapPercent / 100.0)); + } else { + // we're already consuming more than soft max capacity, so we should start old GC right away. + threshold_by_growth_into_percent_remaining = soft_max_capacity; + } + size_t result = MIN2(threshold_by_relative_growth, threshold_by_growth_into_percent_remaining); return result; } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.hpp b/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.hpp index 614a1596287..90c1458ac97 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.hpp @@ -287,28 +287,23 @@ public: private: State _state; - static const size_t FRACTIONAL_DENOMINATOR = 65536; - // During initialization of the JVM, we search for the correct old-gen size by initially performing old-gen - // collection when old-gen usage is 50% more (INITIAL_GROWTH_BEFORE_COMPACTION) than the initial old-gen size - // estimate (3.125% of heap). The next old-gen trigger occurs when old-gen grows 25% larger than its live - // memory at the end of the first old-gen collection. Then we trigger again when old-gen grows 12.5% - // more than its live memory at the end of the previous old-gen collection. Thereafter, we trigger each time - // old-gen grows more than 12.5% following the end of its previous old-gen collection. - static const size_t INITIAL_GROWTH_BEFORE_COMPACTION = FRACTIONAL_DENOMINATOR / 2; // 50.0% + // collection when old-gen usage is 50% more (INITIAL_GROWTH_PERCENT_BEFORE_COLLECTION) than the initial old-gen size + // estimate (16% of heap). With each successive old-gen collection, we divide the growth trigger by two, but + // never use a growth trigger smaller than ShenandoahMinOldGenGrowthPercent. + static const size_t INITIAL_GROWTH_PERCENT_BEFORE_COLLECTION = 50; - // INITIAL_LIVE_FRACTION represents the initial guess of how large old-gen should be. We estimate that old-gen - // needs to consume 6.25% of the total heap size. And we "pretend" that we start out with this amount of live + // INITIAL_LIVE_PERCENT represents the initial guess of how large old-gen should be. We estimate that old gen + // needs to consume 16% of the total heap size. And we "pretend" that we start out with this amount of live // old-gen memory. The first old-collection trigger will occur when old-gen occupies 50% more than this initial - // approximation of the old-gen memory requirement, in other words when old-gen usage is 150% of 6.25%, which - // is 9.375% of the total heap size. - static const uint16_t INITIAL_LIVE_FRACTION = FRACTIONAL_DENOMINATOR / 16; // 6.25% + // approximation of the old-gen memory requirement, in other words when old-gen usage is 150% of 16%, which + // is 24% of the heap size. + static const size_t INITIAL_LIVE_PERCENT = 16; - size_t _live_bytes_after_last_mark; + size_t _live_bytes_at_last_mark; - // How much growth in usage before we trigger old collection, per FRACTIONAL_DENOMINATOR (65_536) - size_t _growth_before_compaction; - const size_t _min_growth_before_compaction; // Default is 12.5% + // How much growth in usage before we trigger old collection as a percent of soft_max_capacity + size_t _growth_percent_before_collection; void validate_transition(State new_state) NOT_DEBUG_RETURN; @@ -323,8 +318,8 @@ public: void transition_to(State new_state); - size_t get_live_bytes_after_last_mark() const; - void set_live_bytes_after_last_mark(size_t new_live); + size_t get_live_bytes_at_last_mark() const; + void set_live_bytes_at_last_mark(size_t new_live); size_t usage_trigger_threshold() const; diff --git a/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp b/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp index 8bd59beb93b..96ebf23bbb5 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp @@ -59,15 +59,29 @@ "fail, resulting in stop-the-world full GCs.") \ range(0,100) \ \ - product(double, ShenandoahMinOldGenGrowthPercent, 12.5, EXPERIMENTAL, \ + product(double, ShenandoahMinOldGenGrowthPercent, 50, EXPERIMENTAL, \ "(Generational mode only) If the usage within old generation " \ "has grown by at least this percent of its live memory size " \ - "at completion of the most recent old-generation marking " \ - "effort, heuristics may trigger the start of a new old-gen " \ - "collection.") \ + "at the start of the previous old-generation marking effort, " \ + "heuristics may trigger the start of a new old-gen collection.") \ range(0.0,100.0) \ \ - product(uintx, ShenandoahIgnoreOldGrowthBelowPercentage,10, EXPERIMENTAL, \ + product(double, ShenandoahMinOldGenGrowthRemainingHeapPercent, \ + 35, EXPERIMENTAL, \ + "(Generational mode only) If the usage within old generation " \ + "has grown to exceed this percent of the remaining heap that " \ + "was not marked live within the old generation at the time " \ + "of the last old-generation marking effort, heuristics may " \ + "trigger the start of a new old-gen collection. Setting " \ + "this value to a smaller value may cause back-to-back old " \ + "generation marking triggers, since the typical memory used " \ + "by the old generation is about 30% larger than the live " \ + "memory contained within the old generation (because default " \ + "value of ShenandoahOldGarbageThreshold is 25.") \ + range(0.0,100.0) \ + \ + product(uintx, ShenandoahIgnoreOldGrowthBelowPercentage, \ + 40, EXPERIMENTAL, \ "(Generational mode only) If the total usage of the old " \ "generation is smaller than this percent, we do not trigger " \ "old gen collections even if old has grown, except when " \ @@ -77,12 +91,13 @@ range(0,100) \ \ product(uintx, ShenandoahDoNotIgnoreGrowthAfterYoungCycles, \ - 50, EXPERIMENTAL, \ - "(Generational mode only) Even if the usage of old generation " \ - "is below ShenandoahIgnoreOldGrowthBelowPercentage, " \ - "trigger an old-generation mark if old has grown and this " \ - "many consecutive young-gen collections have been " \ - "completed following the preceding old-gen collection.") \ + 100, EXPERIMENTAL, \ + "(Generational mode only) Trigger an old-generation mark " \ + "if old has grown and this many consecutive young-gen " \ + "collections have been completed following the preceding " \ + "old-gen collection. We perform this old-generation mark " \ + "evvort even if the usage of old generation is below " \ + "ShenandoahIgnoreOldGrowthBelowPercentage.") \ \ product(bool, ShenandoahGenerationalAdaptiveTenuring, true, EXPERIMENTAL, \ "(Generational mode only) Dynamically adapt tenuring age.") \ diff --git a/test/hotspot/jtreg/gc/shenandoah/generational/TestOldGrowthTriggers.java b/test/hotspot/jtreg/gc/shenandoah/generational/TestOldGrowthTriggers.java index 5182d4a9ea3..a66b9161c7e 100644 --- a/test/hotspot/jtreg/gc/shenandoah/generational/TestOldGrowthTriggers.java +++ b/test/hotspot/jtreg/gc/shenandoah/generational/TestOldGrowthTriggers.java @@ -99,8 +99,12 @@ public class TestOldGrowthTriggers { "-XX:+UnlockExperimentalVMOptions", "-XX:+UseShenandoahGC", "-XX:ShenandoahGCMode=generational", + "-XX:ShenandoahMinOldGenGrowthPercent=12.5", + "-XX:ShenandoahIgnoreOldGrowthBelowPercentage=10", + "-XX:ShenandoahMinOldGenGrowthRemainingHeapPercent=100", "-XX:ShenandoahGuaranteedYoungGCInterval=0", - "-XX:ShenandoahGuaranteedOldGCInterval=0" + "-XX:ShenandoahGuaranteedOldGCInterval=0", + "-XX:-UseCompactObjectHeaders" ); testOld("-Xlog:gc", @@ -110,6 +114,9 @@ public class TestOldGrowthTriggers { "-XX:+UnlockExperimentalVMOptions", "-XX:+UseShenandoahGC", "-XX:ShenandoahGCMode=generational", + "-XX:ShenandoahMinOldGenGrowthPercent=12.5", + "-XX:ShenandoahIgnoreOldGrowthBelowPercentage=10", + "-XX:ShenandoahMinOldGenGrowthRemainingHeapPercent=100", "-XX:ShenandoahGuaranteedYoungGCInterval=0", "-XX:ShenandoahGuaranteedOldGCInterval=0", "-XX:+UseCompactObjectHeaders" From d854a04231a437a6af36ae65780961f40f336343 Mon Sep 17 00:00:00 2001 From: Stefan Karlsson Date: Fri, 12 Dec 2025 14:02:50 +0000 Subject: [PATCH 269/706] 8373411: Crash when PrintSharedArchiveAndExit is enabled but shared heap is disabled Reviewed-by: shade, iklam --- src/hotspot/share/cds/aotMetaspace.cpp | 2 +- .../cds/PrintSharedArchiveAndExitNoHeap.java | 44 +++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 test/hotspot/jtreg/runtime/cds/PrintSharedArchiveAndExitNoHeap.java diff --git a/src/hotspot/share/cds/aotMetaspace.cpp b/src/hotspot/share/cds/aotMetaspace.cpp index 3c87e3ef797..098d3baed58 100644 --- a/src/hotspot/share/cds/aotMetaspace.cpp +++ b/src/hotspot/share/cds/aotMetaspace.cpp @@ -2205,7 +2205,7 @@ void AOTMetaspace::initialize_shared_spaces() { CountSharedSymbols cl; SymbolTable::shared_symbols_do(&cl); tty->print_cr("Number of shared symbols: %zu", cl.total()); - if (HeapShared::is_loading_mapping_mode()) { + if (HeapShared::is_loading() && HeapShared::is_loading_mapping_mode()) { tty->print_cr("Number of shared strings: %zu", StringTable::shared_entry_count()); } tty->print_cr("VM version: %s\r\n", static_mapinfo->vm_version()); diff --git a/test/hotspot/jtreg/runtime/cds/PrintSharedArchiveAndExitNoHeap.java b/test/hotspot/jtreg/runtime/cds/PrintSharedArchiveAndExitNoHeap.java new file mode 100644 index 00000000000..969218dbc16 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/PrintSharedArchiveAndExitNoHeap.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2025, 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 8373411 + * @summary Testing -XX:+PrintSharedArchiveAndExit option with no shared heap + * @requires vm.cds + * @library /test/lib + */ + +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + +public class PrintSharedArchiveAndExitNoHeap { + public static void main(String[] args) throws Exception { + // This used to crash when trying to figure out if interned string should be printed + OutputAnalyzer oa = ProcessTools.executeTestJava("-XX:AOTCacheOutput=./PrintSharedArchiveAndExitNoHeap.jsa", "-XX:+PrintSharedArchiveAndExit", "-version"); + oa.shouldHaveExitValue(0); + // AOTCacheOutput forks a process, if that crashes then the above check is not enough + // and we have to check the output to figure out if it crashed. + oa.shouldNotContain("Internal Error"); + } +} From a99f340e1b9686431d944ab114918d2b849718fe Mon Sep 17 00:00:00 2001 From: Artur Barashev Date: Fri, 12 Dec 2025 14:39:42 +0000 Subject: [PATCH 270/706] 8371721: Refactor checkTrusted methods in X509TrustManagerImpl Reviewed-by: coffeys, djelinski --- .../security/ssl/X509TrustManagerImpl.java | 153 +++++++----------- 1 file changed, 58 insertions(+), 95 deletions(-) diff --git a/src/java.base/share/classes/sun/security/ssl/X509TrustManagerImpl.java b/src/java.base/share/classes/sun/security/ssl/X509TrustManagerImpl.java index 1bbe0bfb9c7..40ee01d284a 100644 --- a/src/java.base/share/classes/sun/security/ssl/X509TrustManagerImpl.java +++ b/src/java.base/share/classes/sun/security/ssl/X509TrustManagerImpl.java @@ -30,9 +30,7 @@ import java.security.*; import java.security.cert.*; import java.util.*; import java.util.concurrent.locks.ReentrantLock; - import javax.net.ssl.*; - import sun.security.ssl.SSLAlgorithmConstraints.SIGNATURE_CONSTRAINTS_MODE; import sun.security.util.AnchorCertificates; import sun.security.util.HostnameChecker; @@ -40,19 +38,14 @@ import sun.security.validator.*; /** * This class implements the SunJSSE X.509 trust manager using the internal - * validator API in J2SE core. The logic in this class is minimal.

      + * validator API in J2SE core. The logic in this class is minimal. *

      * This class supports both the Simple validation algorithm from previous - * JSSE versions and PKIX validation. Currently, it is not possible for the - * application to specify PKIX parameters other than trust anchors. This will - * be fixed in a future release using new APIs. When that happens, it may also - * make sense to separate the Simple and PKIX trust managers into separate - * classes. + * JSSE versions and PKIX validation. * * @author Andreas Sterbenz */ -final class X509TrustManagerImpl extends X509ExtendedTrustManager - implements X509TrustManager { +final class X509TrustManagerImpl extends X509ExtendedTrustManager { private final String validatorType; @@ -208,120 +201,90 @@ final class X509TrustManagerImpl extends X509ExtendedTrustManager private void checkTrusted(X509Certificate[] chain, String authType, Socket socket, boolean checkClientTrusted) throws CertificateException { - Validator v = checkTrustedInit(chain, authType, checkClientTrusted); - X509Certificate[] trustedChain; + SSLSession session = null; + AlgorithmConstraints constraints = null; + String identityAlg = null; + if (socket instanceof SSLSocket sslSocket && sslSocket.isConnected()) { - - SSLSession session = sslSocket.getHandshakeSession(); - if (session == null) { - throw new CertificateException("No handshake session"); - } - - AlgorithmConstraints constraints = SSLAlgorithmConstraints.forSocket( + session = sslSocket.getHandshakeSession(); + constraints = SSLAlgorithmConstraints.forSocket( sslSocket, SIGNATURE_CONSTRAINTS_MODE.LOCAL, false); - - // Grab any stapled OCSP responses for use in validation - List responseList = Collections.emptyList(); - if (!checkClientTrusted && session instanceof ExtendedSSLSession) { - responseList = - ((ExtendedSSLSession)session).getStatusResponses(); - } - trustedChain = v.validate(chain, null, responseList, - constraints, checkClientTrusted ? null : authType); - - // check endpoint identity - String identityAlg = sslSocket.getSSLParameters(). + identityAlg = sslSocket.getSSLParameters(). getEndpointIdentificationAlgorithm(); - if (identityAlg != null && !identityAlg.isEmpty()) { - checkIdentity(session, - trustedChain, identityAlg, checkClientTrusted); - } - } else { - trustedChain = v.validate(chain, null, Collections.emptyList(), - null, checkClientTrusted ? null : authType); } - if (SSLLogger.isOn() && SSLLogger.isOn("ssl,trustmanager")) { - SSLLogger.fine("Found trusted certificate", - trustedChain[trustedChain.length - 1]); + findTrustedCertificate(chain, authType, + session, constraints, identityAlg, checkClientTrusted); + } + + private void checkTrusted(X509Certificate[] chain, + String authType, SSLEngine engine, + boolean checkClientTrusted) throws CertificateException { + + SSLSession session = null; + AlgorithmConstraints constraints = null; + String identityAlg = null; + + if (engine != null) { + session = engine.getHandshakeSession(); + constraints = SSLAlgorithmConstraints.forEngine( + engine, SIGNATURE_CONSTRAINTS_MODE.LOCAL, false); + identityAlg = engine.getSSLParameters(). + getEndpointIdentificationAlgorithm(); } + + findTrustedCertificate(chain, authType, + session, constraints, identityAlg, checkClientTrusted); } private void checkTrusted(X509Certificate[] chain, String authType, QuicTLSEngineImpl quicTLSEngine, boolean checkClientTrusted) throws CertificateException { - Validator v = checkTrustedInit(chain, authType, checkClientTrusted); + + SSLSession session = null; + AlgorithmConstraints constraints = null; + String identityAlg = null; + + if (quicTLSEngine != null) { + session = quicTLSEngine.getHandshakeSession(); + constraints = SSLAlgorithmConstraints.forQUIC( + quicTLSEngine, SIGNATURE_CONSTRAINTS_MODE.LOCAL, false); + identityAlg = quicTLSEngine.getSSLParameters(). + getEndpointIdentificationAlgorithm(); + } + + findTrustedCertificate(chain, authType, + session, constraints, identityAlg, checkClientTrusted); + } + + private void findTrustedCertificate(X509Certificate[] chain, + String authType, SSLSession session, + AlgorithmConstraints constraints, String identityAlg, + boolean checkClientTrusted) throws CertificateException { final X509Certificate[] trustedChain; - if (quicTLSEngine != null) { + Validator v = checkTrustedInit(chain, authType, checkClientTrusted); - final SSLSession session = quicTLSEngine.getHandshakeSession(); + if (constraints != null) { if (session == null) { throw new CertificateException("No handshake session"); } - // create the algorithm constraints - final AlgorithmConstraints constraints = SSLAlgorithmConstraints.forQUIC( - quicTLSEngine, SIGNATURE_CONSTRAINTS_MODE.LOCAL, false); + // Grab any stapled OCSP responses for use in validation final List responseList; - // grab any stapled OCSP responses for use in validation if (!checkClientTrusted && session instanceof ExtendedSSLSession extSession) { responseList = extSession.getStatusResponses(); } else { responseList = Collections.emptyList(); } - // do the certificate chain validation + + // Certificate chain validation trustedChain = v.validate(chain, null, responseList, constraints, checkClientTrusted ? null : authType); - // check endpoint identity - String identityAlg = quicTLSEngine.getSSLParameters(). - getEndpointIdentificationAlgorithm(); - if (identityAlg != null && !identityAlg.isEmpty()) { - checkIdentity(session, trustedChain, - identityAlg, checkClientTrusted); - } - } else { - trustedChain = v.validate(chain, null, Collections.emptyList(), - null, checkClientTrusted ? null : authType); - } - - if (SSLLogger.isOn() && SSLLogger.isOn("ssl,trustmanager")) { - SSLLogger.fine("Found trusted certificate", - trustedChain[trustedChain.length - 1]); - } - } - - private void checkTrusted(X509Certificate[] chain, - String authType, SSLEngine engine, - boolean checkClientTrusted) throws CertificateException { - Validator v = checkTrustedInit(chain, authType, checkClientTrusted); - - X509Certificate[] trustedChain; - if (engine != null) { - - SSLSession session = engine.getHandshakeSession(); - if (session == null) { - throw new CertificateException("No handshake session"); - } - - AlgorithmConstraints constraints = SSLAlgorithmConstraints.forEngine( - engine, SIGNATURE_CONSTRAINTS_MODE.LOCAL, false); - - // Grab any stapled OCSP responses for use in validation - List responseList = Collections.emptyList(); - if (!checkClientTrusted && session instanceof ExtendedSSLSession) { - responseList = - ((ExtendedSSLSession)session).getStatusResponses(); - } - trustedChain = v.validate(chain, null, responseList, - constraints, checkClientTrusted ? null : authType); - - // check endpoint identity - String identityAlg = engine.getSSLParameters(). - getEndpointIdentificationAlgorithm(); + // Check endpoint identity if (identityAlg != null && !identityAlg.isEmpty()) { checkIdentity(session, trustedChain, identityAlg, checkClientTrusted); From 6ec36d348b1eaeedb993a905e42650242fac0918 Mon Sep 17 00:00:00 2001 From: Ferenc Rakoczi Date: Fri, 12 Dec 2025 16:04:56 +0000 Subject: [PATCH 271/706] 8373059: Test sun/security/provider/acvp/ML_DSA_Intrinsic_Test.java should pass on Aarch64 Reviewed-by: weijun, vpaprotski --- .../classes/sun/security/provider/ML_DSA.java | 2 +- .../{acvp => pqc}/ML_DSA_Intrinsic_Test.java | 90 +++++++++++++------ 2 files changed, 63 insertions(+), 29 deletions(-) rename test/jdk/sun/security/provider/{acvp => pqc}/ML_DSA_Intrinsic_Test.java (90%) diff --git a/src/java.base/share/classes/sun/security/provider/ML_DSA.java b/src/java.base/share/classes/sun/security/provider/ML_DSA.java index af64ef399a8..6a578427e51 100644 --- a/src/java.base/share/classes/sun/security/provider/ML_DSA.java +++ b/src/java.base/share/classes/sun/security/provider/ML_DSA.java @@ -1555,7 +1555,7 @@ public class ML_DSA { return res; } - // precondition: -2^31 * MONT_Q <= a, b < 2^31, -2^31 < a * b < 2^31 * MONT_Q + // precondition: -2^31 <= a, b < 2^31, -2^31 * MONT_Q <= a * b < 2^31 * MONT_Q // computes a * b * 2^-32 mod MONT_Q // the result is greater than -MONT_Q and less than MONT_Q // See e.g. Algorithm 3 in https://eprint.iacr.org/2018/039.pdf diff --git a/test/jdk/sun/security/provider/acvp/ML_DSA_Intrinsic_Test.java b/test/jdk/sun/security/provider/pqc/ML_DSA_Intrinsic_Test.java similarity index 90% rename from test/jdk/sun/security/provider/acvp/ML_DSA_Intrinsic_Test.java rename to test/jdk/sun/security/provider/pqc/ML_DSA_Intrinsic_Test.java index 1e9faf7fb74..d6d9fea789f 100644 --- a/test/jdk/sun/security/provider/acvp/ML_DSA_Intrinsic_Test.java +++ b/test/jdk/sun/security/provider/pqc/ML_DSA_Intrinsic_Test.java @@ -38,16 +38,17 @@ import java.util.HexFormat; */ /* * @test - * @comment This test should be reenabled on aarch64 - * @requires os.simpleArch == "x64" * @library /test/lib * @key randomness * @modules java.base/sun.security.provider:+open * @run main ML_DSA_Intrinsic_Test */ -// To run manually: java --add-opens java.base/sun.security.provider=ALL-UNNAMED --add-exports java.base/sun.security.provider=ALL-UNNAMED -// -XX:+UnlockDiagnosticVMOptions -XX:+UseDilithiumIntrinsics test/jdk/sun/security/provider/acvp/ML_DSA_Intrinsic_Test.java +// To run manually: +// java --add-opens java.base/sun.security.provider=ALL-UNNAMED +// --add-exports java.base/sun.security.provider=ALL-UNNAMED +// -XX:+UnlockDiagnosticVMOptions -XX:+UseDilithiumIntrinsics +// test/jdk/sun/security/provider/pqc/ML_DSA_Intrinsic_Test.java public class ML_DSA_Intrinsic_Test { public static void main(String[] args) throws Throwable { @@ -104,9 +105,10 @@ public class ML_DSA_Intrinsic_Test { m.setAccessible(true); MethodHandle inverseNttJava = lookup.unreflect(m); - // Hint: if test fails, you can hardcode the seed to make the test more reproducible Random rnd = new Random(); long seed = rnd.nextLong(); + // Hint: if a test fails, it prints the seed, so you can hardcode + // it here to reproduce the failure rnd.setSeed(seed); //Note: it might be useful to increase this number during development of new intrinsics final int repeat = 10000; @@ -117,32 +119,49 @@ public class ML_DSA_Intrinsic_Test { int[] prod3 = new int[ML_DSA_N]; int[] prod4 = new int[ML_DSA_N]; for (int i = 0; i < repeat; i++) { - // Hint: if test fails, you can hardcode the seed to make the test more reproducible: - // rnd.setSeed(seed); - testMult(prod1, prod2, coeffs1, coeffs2, mult, multJava, rnd, seed, i); + testMult(prod1, prod2, coeffs1, coeffs2, + mult, multJava, rnd, seed, i); testMultConst(prod1, prod2, multConst, multConstJava, rnd, seed, i); - testDecompose(prod1, prod2, prod3, prod4, coeffs1, coeffs2, decompose, decomposeJava, rnd, seed, i); + testDecompose(prod1, prod2, prod3, prod4, coeffs1, coeffs2, + decompose, decomposeJava, rnd, seed, i); testAlmostNtt(coeffs1, coeffs2, almostNtt, almostNttJava, rnd, seed, i); testInverseNtt(coeffs1, coeffs2, inverseNtt, inverseNttJava, rnd, seed, i); } System.out.println("Fuzz Success"); } - private static final int ML_DSA_N = 256; - public static void testMult(int[] prod1, int[] prod2, int[] coeffs1, int[] coeffs2, + public static void testMult(int[] prod1, int[] prod2, + int[] coeffs1, int[] coeffs2, MethodHandle mult, MethodHandle multJava, Random rnd, long seed, int i) throws Throwable { - for (int j = 0; jcapacity(); - } -} - -PtrQueueSet::PtrQueueSet(BufferNode::Allocator* allocator) : - _allocator(allocator) -{} - -PtrQueueSet::~PtrQueueSet() {} - -void PtrQueueSet::reset_queue(PtrQueue& queue) { - queue.set_index(queue.current_capacity()); -} - -void PtrQueueSet::flush_queue(PtrQueue& queue) { - void** buffer = queue.buffer(); - if (buffer != nullptr) { - size_t index = queue.index(); - queue.set_buffer(nullptr); - queue.set_index(0); - BufferNode* node = BufferNode::make_node_from_buffer(buffer, index); - if (index == node->capacity()) { - deallocate_buffer(node); - } else { - enqueue_completed_buffer(node); - } - } -} - -bool PtrQueueSet::try_enqueue(PtrQueue& queue, void* value) { - size_t index = queue.index(); - if (index == 0) return false; - void** buffer = queue.buffer(); - assert(buffer != nullptr, "no buffer but non-zero index"); - buffer[--index] = value; - queue.set_index(index); - return true; -} - -void PtrQueueSet::retry_enqueue(PtrQueue& queue, void* value) { - assert(queue.index() != 0, "precondition"); - assert(queue.buffer() != nullptr, "precondition"); - size_t index = queue.index(); - queue.buffer()[--index] = value; - queue.set_index(index); -} - -BufferNode* PtrQueueSet::exchange_buffer_with_new(PtrQueue& queue) { - BufferNode* node = nullptr; - void** buffer = queue.buffer(); - if (buffer != nullptr) { - node = BufferNode::make_node_from_buffer(buffer, queue.index()); - } - install_new_buffer(queue); - return node; -} - -void PtrQueueSet::install_new_buffer(PtrQueue& queue) { - BufferNode* node = _allocator->allocate(); - queue.set_buffer(BufferNode::make_buffer_from_node(node)); - queue.set_index(node->capacity()); -} - -void** PtrQueueSet::allocate_buffer() { - BufferNode* node = _allocator->allocate(); - return BufferNode::make_buffer_from_node(node); -} - -void PtrQueueSet::deallocate_buffer(BufferNode* node) { - _allocator->release(node); -} diff --git a/src/hotspot/share/gc/shared/ptrQueue.hpp b/src/hotspot/share/gc/shared/ptrQueue.hpp deleted file mode 100644 index 8aa5e16d40b..00000000000 --- a/src/hotspot/share/gc/shared/ptrQueue.hpp +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Copyright (c) 2001, 2023, 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. - * - */ - -#ifndef SHARE_GC_SHARED_PTRQUEUE_HPP -#define SHARE_GC_SHARED_PTRQUEUE_HPP - -#include "gc/shared/bufferNode.hpp" -#include "utilities/align.hpp" -#include "utilities/debug.hpp" -#include "utilities/globalDefinitions.hpp" -#include "utilities/sizes.hpp" - -// There are various techniques that require threads to be able to log -// addresses. For example, a generational write barrier might log -// the addresses of modified old-generation objects. This type supports -// this operation. - -class PtrQueueSet; -class PtrQueue { - friend class VMStructs; - - NONCOPYABLE(PtrQueue); - - // The (byte) index at which an object was last enqueued. Starts at - // capacity (in bytes) (indicating an empty buffer) and goes towards zero. - // Value is always pointer-size aligned. - size_t _index; - - static const size_t _element_size = sizeof(void*); - - static size_t byte_index_to_index(size_t ind) { - assert(is_aligned(ind, _element_size), "precondition"); - return ind / _element_size; - } - - static size_t index_to_byte_index(size_t ind) { - return ind * _element_size; - } - -protected: - // The buffer. - void** _buf; - - // Initialize this queue to contain a null buffer, and be part of the - // given PtrQueueSet. - PtrQueue(PtrQueueSet* qset); - - // Requires queue flushed. - ~PtrQueue(); - -public: - - void** buffer() const { return _buf; } - void set_buffer(void** buffer) { _buf = buffer; } - - size_t index() const { - return byte_index_to_index(_index); - } - - void set_index(size_t new_index) { - assert(new_index <= current_capacity(), "precondition"); - _index = index_to_byte_index(new_index); - } - - // Returns the capacity of the buffer, or 0 if the queue doesn't currently - // have a buffer. - size_t current_capacity() const; - - bool is_empty() const { return index() == current_capacity(); } - size_t size() const { return current_capacity() - index(); } - -protected: - // To support compiler. - template - static ByteSize byte_offset_of_index() { - return byte_offset_of(Derived, _index); - } - - static constexpr ByteSize byte_width_of_index() { return in_ByteSize(sizeof(size_t)); } - - template - static ByteSize byte_offset_of_buf() { - return byte_offset_of(Derived, _buf); - } - - static ByteSize byte_width_of_buf() { return in_ByteSize(_element_size); } -}; - -// A PtrQueueSet represents resources common to a set of pointer queues. -// In particular, the individual queues allocate buffers from this shared -// set, and return completed buffers to the set. -class PtrQueueSet { - BufferNode::Allocator* _allocator; - - NONCOPYABLE(PtrQueueSet); - -protected: - // Create an empty ptr queue set. - PtrQueueSet(BufferNode::Allocator* allocator); - ~PtrQueueSet(); - - // Discard any buffered enqueued data. - void reset_queue(PtrQueue& queue); - - // If queue has any buffered enqueued data, transfer it to this qset. - // Otherwise, deallocate queue's buffer. - void flush_queue(PtrQueue& queue); - - // Add value to queue's buffer, returning true. If buffer is full - // or if queue doesn't have a buffer, does nothing and returns false. - bool try_enqueue(PtrQueue& queue, void* value); - - // Add value to queue's buffer. The queue must have a non-full buffer. - // Used after an initial try_enqueue has failed and the situation resolved. - void retry_enqueue(PtrQueue& queue, void* value); - - // Installs a new buffer into queue. - // Returns the old buffer, or null if queue didn't have a buffer. - BufferNode* exchange_buffer_with_new(PtrQueue& queue); - - // Installs a new buffer into queue. - void install_new_buffer(PtrQueue& queue); - -public: - - // Return the associated BufferNode allocator. - BufferNode::Allocator* allocator() const { return _allocator; } - - // Return the buffer for a BufferNode of size buffer_capacity(). - void** allocate_buffer(); - - // Return an empty buffer to the free list. The node is required - // to have been allocated with a size of buffer_capacity(). - void deallocate_buffer(BufferNode* node); - - // A completed buffer is a buffer the mutator is finished with, and - // is ready to be processed by the collector. It need not be full. - - // Adds node to the completed buffer list. - virtual void enqueue_completed_buffer(BufferNode* node) = 0; - - size_t buffer_capacity() const { - return _allocator->buffer_capacity(); - } -}; - -#endif // SHARE_GC_SHARED_PTRQUEUE_HPP diff --git a/src/hotspot/share/gc/shared/satbMarkQueue.cpp b/src/hotspot/share/gc/shared/satbMarkQueue.cpp index 93c52b499a0..63496f2eb25 100644 --- a/src/hotspot/share/gc/shared/satbMarkQueue.cpp +++ b/src/hotspot/share/gc/shared/satbMarkQueue.cpp @@ -36,14 +36,19 @@ #include "utilities/globalCounter.inline.hpp" SATBMarkQueue::SATBMarkQueue(SATBMarkQueueSet* qset) : - PtrQueue(qset), + _buf(nullptr), + _index(0), // SATB queues are only active during marking cycles. We create them // with their active field set to false. If a thread is created // during a cycle, it's SATB queue needs to be activated before the // thread starts running. This is handled by the collector-specific // BarrierSet thread attachment protocol. _active(false) -{ } +{} + +SATBMarkQueue::~SATBMarkQueue() { + assert(_buf == nullptr, "queue must be flushed before delete"); +} #ifndef PRODUCT // Helpful for debugging @@ -64,7 +69,7 @@ void SATBMarkQueue::print(const char* name) { #endif // PRODUCT SATBMarkQueueSet::SATBMarkQueueSet(BufferNode::Allocator* allocator) : - PtrQueueSet(allocator), + _allocator(allocator), _list(), _count_and_process_flag(0), _process_completed_buffers_threshold(SIZE_MAX), @@ -214,13 +219,6 @@ bool SATBMarkQueueSet::apply_closure_to_completed_buffer(SATBBufferClosure* cl) } } -void SATBMarkQueueSet::flush_queue(SATBMarkQueue& queue) { - // Filter now to possibly save work later. If filtering empties the - // buffer then flush_queue can deallocate the buffer. - filter(queue); - PtrQueueSet::flush_queue(queue); -} - void SATBMarkQueueSet::enqueue_known_active(SATBMarkQueue& queue, oop obj) { assert(queue.is_active(), "precondition"); void* value = cast_from_oop(obj); @@ -355,3 +353,76 @@ void SATBMarkQueueSet::abandon_partial_marking() { } closure(*this); Threads::threads_do(&closure); } + +size_t SATBMarkQueue::current_capacity() const { + if (_buf == nullptr) { + return 0; + } else { + return BufferNode::make_node_from_buffer(_buf)->capacity(); + } +} + +void SATBMarkQueueSet::reset_queue(SATBMarkQueue& queue) { + queue.set_index(queue.current_capacity()); +} + +void SATBMarkQueueSet::flush_queue(SATBMarkQueue& queue) { + // Filter now to possibly save work later. If filtering empties the + // buffer then flush_queue can deallocate the buffer. + filter(queue); + void** buffer = queue.buffer(); + if (buffer != nullptr) { + size_t index = queue.index(); + queue.set_buffer(nullptr); + queue.set_index(0); + BufferNode* node = BufferNode::make_node_from_buffer(buffer, index); + if (index == node->capacity()) { + deallocate_buffer(node); + } else { + enqueue_completed_buffer(node); + } + } +} + +bool SATBMarkQueueSet::try_enqueue(SATBMarkQueue& queue, void* value) { + size_t index = queue.index(); + if (index == 0) return false; + void** buffer = queue.buffer(); + assert(buffer != nullptr, "no buffer but non-zero index"); + buffer[--index] = value; + queue.set_index(index); + return true; +} + +void SATBMarkQueueSet::retry_enqueue(SATBMarkQueue& queue, void* value) { + assert(queue.index() != 0, "precondition"); + assert(queue.buffer() != nullptr, "precondition"); + size_t index = queue.index(); + queue.buffer()[--index] = value; + queue.set_index(index); +} + +BufferNode* SATBMarkQueueSet::exchange_buffer_with_new(SATBMarkQueue& queue) { + BufferNode* node = nullptr; + void** buffer = queue.buffer(); + if (buffer != nullptr) { + node = BufferNode::make_node_from_buffer(buffer, queue.index()); + } + install_new_buffer(queue); + return node; +} + +void SATBMarkQueueSet::install_new_buffer(SATBMarkQueue& queue) { + BufferNode* node = _allocator->allocate(); + queue.set_buffer(BufferNode::make_buffer_from_node(node)); + queue.set_index(node->capacity()); +} + +void** SATBMarkQueueSet::allocate_buffer() { + BufferNode* node = _allocator->allocate(); + return BufferNode::make_buffer_from_node(node); +} + +void SATBMarkQueueSet::deallocate_buffer(BufferNode* node) { + _allocator->release(node); +} diff --git a/src/hotspot/share/gc/shared/satbMarkQueue.hpp b/src/hotspot/share/gc/shared/satbMarkQueue.hpp index d2b14a3cc92..f1577c004de 100644 --- a/src/hotspot/share/gc/shared/satbMarkQueue.hpp +++ b/src/hotspot/share/gc/shared/satbMarkQueue.hpp @@ -25,11 +25,15 @@ #ifndef SHARE_GC_SHARED_SATBMARKQUEUE_HPP #define SHARE_GC_SHARED_SATBMARKQUEUE_HPP -#include "gc/shared/ptrQueue.hpp" +#include "gc/shared/bufferNode.hpp" #include "memory/allocation.hpp" #include "memory/padded.hpp" #include "oops/oopsHierarchy.hpp" #include "runtime/atomic.hpp" +#include "utilities/align.hpp" +#include "utilities/debug.hpp" +#include "utilities/globalDefinitions.hpp" +#include "utilities/sizes.hpp" class Thread; class Monitor; @@ -45,12 +49,33 @@ public: virtual void do_buffer(void** buffer, size_t size) = 0; }; -// A PtrQueue whose elements are (possibly stale) pointers to object heads. -class SATBMarkQueue: public PtrQueue { +// A queue whose elements are (possibly stale) pointers to object heads. +class SATBMarkQueue { friend class VMStructs; friend class SATBMarkQueueSet; private: + NONCOPYABLE(SATBMarkQueue); + + // The buffer. + void** _buf; + + // The (byte) index at which an object was last enqueued. Starts at + // capacity (in bytes) (indicating an empty buffer) and goes towards zero. + // Value is always pointer-size aligned. + size_t _index; + + static const size_t _element_size = sizeof(void*); + + static size_t byte_index_to_index(size_t ind) { + assert(is_aligned(ind, _element_size), "precondition"); + return ind / _element_size; + } + + static size_t index_to_byte_index(size_t ind) { + return ind * _element_size; + } + // Per-queue (so thread-local) cache of the SATBMarkQueueSet's // active state, to support inline barriers in compiled code. bool _active; @@ -58,6 +83,29 @@ private: public: SATBMarkQueue(SATBMarkQueueSet* qset); + // Queue must be flushed + ~SATBMarkQueue(); + + void** buffer() const { return _buf; } + + void set_buffer(void** buffer) { _buf = buffer; } + + size_t index() const { + return byte_index_to_index(_index); + } + + void set_index(size_t new_index) { + assert(new_index <= current_capacity(), "precondition"); + _index = index_to_byte_index(new_index); + } + + // Returns the capacity of the buffer, or 0 if the queue doesn't currently + // have a buffer. + size_t current_capacity() const; + + bool is_empty() const { return index() == current_capacity(); } + size_t size() const { return current_capacity() - index(); } + bool is_active() const { return _active; } void set_active(bool value) { _active = value; } @@ -68,14 +116,16 @@ public: // Compiler support. static ByteSize byte_offset_of_index() { - return PtrQueue::byte_offset_of_index(); + return byte_offset_of(SATBMarkQueue, _index); } - using PtrQueue::byte_width_of_index; + + static constexpr ByteSize byte_width_of_index() { return in_ByteSize(sizeof(size_t)); } static ByteSize byte_offset_of_buf() { - return PtrQueue::byte_offset_of_buf(); + return byte_offset_of(SATBMarkQueue, _buf); } - using PtrQueue::byte_width_of_buf; + + static ByteSize byte_width_of_buf() { return in_ByteSize(_element_size); } static ByteSize byte_offset_of_active() { return byte_offset_of(SATBMarkQueue, _active); @@ -84,7 +134,18 @@ public: static ByteSize byte_width_of_active() { return in_ByteSize(sizeof(bool)); } }; -class SATBMarkQueueSet: public PtrQueueSet { + +// A SATBMarkQueueSet represents resources common to a set of SATBMarkQueues. +// In particular, the individual queues allocate buffers from this shared +// set, and return completed buffers to the set. +// A completed buffer is a buffer the mutator is finished with, and +// is ready to be processed by the collector. It need not be full. + +class SATBMarkQueueSet { + + BufferNode::Allocator* _allocator; + + NONCOPYABLE(SATBMarkQueueSet); DEFINE_PAD_MINUS_SIZE(1, DEFAULT_PADDING_SIZE, 0); PaddedEnd _list; @@ -99,6 +160,24 @@ class SATBMarkQueueSet: public PtrQueueSet { BufferNode* get_completed_buffer(); void abandon_completed_buffers(); + // Discard any buffered enqueued data. + void reset_queue(SATBMarkQueue& queue); + + // Add value to queue's buffer, returning true. If buffer is full + // or if queue doesn't have a buffer, does nothing and returns false. + bool try_enqueue(SATBMarkQueue& queue, void* value); + + // Add value to queue's buffer. The queue must have a non-full buffer. + // Used after an initial try_enqueue has failed and the situation resolved. + void retry_enqueue(SATBMarkQueue& queue, void* value); + + // Installs a new buffer into queue. + // Returns the old buffer, or null if queue didn't have a buffer. + BufferNode* exchange_buffer_with_new(SATBMarkQueue& queue); + + // Installs a new buffer into queue. + void install_new_buffer(SATBMarkQueue& queue); + #ifdef ASSERT void dump_active_states(bool expected_active); void verify_active_states(bool expected_active); @@ -106,6 +185,7 @@ class SATBMarkQueueSet: public PtrQueueSet { protected: SATBMarkQueueSet(BufferNode::Allocator* allocator); + ~SATBMarkQueueSet(); void handle_zero_index(SATBMarkQueue& queue); @@ -131,6 +211,7 @@ public: void set_process_completed_buffers_threshold(size_t value); size_t buffer_enqueue_threshold() const { return _buffer_enqueue_threshold; } + void set_buffer_enqueue_threshold_percentage(uint value); // If there exists some completed buffer, pop and process it, and @@ -144,7 +225,7 @@ public: // Add obj to queue. This qset and the queue must be active. void enqueue_known_active(SATBMarkQueue& queue, oop obj); virtual void filter(SATBMarkQueue& queue) = 0; - virtual void enqueue_completed_buffer(BufferNode* node); + void enqueue_completed_buffer(BufferNode* node); // The number of buffers in the list. Racy and not updated atomically // with the set of completed buffers. @@ -157,6 +238,20 @@ public: return (_count_and_process_flag.load_relaxed() & 1) != 0; } + // Return the associated BufferNode allocator. + BufferNode::Allocator* allocator() const { return _allocator; } + + // Return the buffer for a BufferNode of size buffer_capacity(). + void** allocate_buffer(); + + // Return an empty buffer to the free list. The node is required + // to have been allocated with a size of buffer_capacity(). + void deallocate_buffer(BufferNode* node); + + size_t buffer_capacity() const { + return _allocator->buffer_capacity(); + } + #ifndef PRODUCT // Helpful for debugging void print_all(const char* msg); From e65e06867e7a841c7edce0625f856b8bc2888893 Mon Sep 17 00:00:00 2001 From: Phil Race Date: Fri, 12 Dec 2025 18:04:14 +0000 Subject: [PATCH 273/706] 8372592: Adjust logger usage in java2d tests Reviewed-by: kizune, serb, rriggs --- test/jdk/sun/java2d/marlin/Bug8341381.java | 4 ++-- test/jdk/sun/java2d/marlin/CrashNaNTest.java | 5 +++-- test/jdk/sun/java2d/marlin/CrashPaintTest.java | 5 +++-- test/jdk/sun/java2d/marlin/TextClipErrorTest.java | 5 +++-- 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/test/jdk/sun/java2d/marlin/Bug8341381.java b/test/jdk/sun/java2d/marlin/Bug8341381.java index b469ac49313..19223e3bdbb 100644 --- a/test/jdk/sun/java2d/marlin/Bug8341381.java +++ b/test/jdk/sun/java2d/marlin/Bug8341381.java @@ -89,13 +89,13 @@ public final class Bug8341381 { static final AtomicBoolean isMarlin = new AtomicBoolean(); static final CountDownLatch latch = new CountDownLatch(1); + // initialize j.u.l Logger: + static final Logger log = Logger.getLogger("sun.java2d.marlin"); public static void main(final String[] args) { Locale.setDefault(Locale.US); // FIRST: Get Marlin runtime state from its log: - // initialize j.u.l Logger: - final Logger log = Logger.getLogger("sun.java2d.marlin"); log.addHandler(new Handler() { @Override public void publish(LogRecord record) { diff --git a/test/jdk/sun/java2d/marlin/CrashNaNTest.java b/test/jdk/sun/java2d/marlin/CrashNaNTest.java index f25be866f85..88ca3ea245f 100644 --- a/test/jdk/sun/java2d/marlin/CrashNaNTest.java +++ b/test/jdk/sun/java2d/marlin/CrashNaNTest.java @@ -54,11 +54,12 @@ public class CrashNaNTest { static final boolean SAVE_IMAGE = false; + // initialize j.u.l Looger: + static final Logger log = Logger.getLogger("sun.java2d.marlin"); + public static void main(String argv[]) { Locale.setDefault(Locale.US); - // initialize j.u.l Looger: - final Logger log = Logger.getLogger("sun.java2d.marlin"); log.addHandler(new Handler() { @Override public void publish(LogRecord record) { diff --git a/test/jdk/sun/java2d/marlin/CrashPaintTest.java b/test/jdk/sun/java2d/marlin/CrashPaintTest.java index cf710bc83a5..81652761acb 100644 --- a/test/jdk/sun/java2d/marlin/CrashPaintTest.java +++ b/test/jdk/sun/java2d/marlin/CrashPaintTest.java @@ -53,11 +53,12 @@ public class CrashPaintTest { static final boolean SAVE_IMAGE = false; + // initialize j.u.l Looger: + static final Logger log = Logger.getLogger("sun.java2d.marlin"); + public static void main(String argv[]) { Locale.setDefault(Locale.US); - // initialize j.u.l Looger: - final Logger log = Logger.getLogger("sun.java2d.marlin"); log.addHandler(new Handler() { @Override public void publish(LogRecord record) { diff --git a/test/jdk/sun/java2d/marlin/TextClipErrorTest.java b/test/jdk/sun/java2d/marlin/TextClipErrorTest.java index 2e63e4689fa..4d1c841a688 100644 --- a/test/jdk/sun/java2d/marlin/TextClipErrorTest.java +++ b/test/jdk/sun/java2d/marlin/TextClipErrorTest.java @@ -61,11 +61,12 @@ public class TextClipErrorTest { static final boolean SAVE_IMAGE = false; static final boolean SERIALIZE = false; + // initialize j.u.l Looger: + static final Logger log = Logger.getLogger("sun.java2d.marlin"); + public static void main(String[] args) { Locale.setDefault(Locale.US); - // initialize j.u.l Looger: - final Logger log = Logger.getLogger("sun.java2d.marlin"); log.addHandler(new Handler() { @Override public void publish(LogRecord record) { From 9b12c0bb190de3f7d06db71411f37f9465992a04 Mon Sep 17 00:00:00 2001 From: Phil Race Date: Fri, 12 Dec 2025 18:06:46 +0000 Subject: [PATCH 274/706] 7067310: 3 tests from closed/javax/sound/sampled caused BSOD on win 7 x86 8307574: ClipIsRunningAfterStop.java failed with "../nptl/pthread_mutex_lock.c:81: __pthread_mutex_lock: Assertion `mutex->__data.__owner == 0' failed." 8308395: javax/sound/sampled/Clip/ClipFlushCrash.java timed out Reviewed-by: serb --- test/jdk/ProblemList.txt | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 757d9c0ba63..789fc93fe7d 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -641,19 +641,9 @@ sun/security/pkcs11/sslecc/ClientJSSEServerJSSE.java 8316183 linux-pp ############################################################################ # jdk_sound -javax/sound/sampled/DirectAudio/bug6372428.java 8055097 generic-all -javax/sound/sampled/Clip/bug5070081.java 8055097 generic-all -javax/sound/sampled/DataLine/LongFramePosition.java 8055097 generic-all javax/sound/sampled/Clip/Drain/ClipDrain.java 7062792 generic-all -javax/sound/sampled/Mixers/DisabledAssertionCrash.java 7067310 generic-all - -javax/sound/midi/Sequencer/Recording.java 8167580,8265485 linux-all,macosx-aarch64 -javax/sound/midi/Sequencer/Looping.java 8136897 generic-all -javax/sound/sampled/Clip/ClipIsRunningAfterStop.java 8307574 linux-x64 -javax/sound/sampled/Clip/ClipFlushCrash.java 8308395 linux-x64 - ############################################################################ # jdk_imageio From 6e2ab84154e7cc11a31026c588a7dc3ceb446cc2 Mon Sep 17 00:00:00 2001 From: Srinivas Mandalika Date: Fri, 12 Dec 2025 18:09:51 +0000 Subject: [PATCH 275/706] 8068378: [TEST_BUG]The java/awt/Modal/PrintDialogsTest/PrintDialogsTest.java instruction need to update Reviewed-by: psadhukhan, prr --- test/jdk/ProblemList.txt | 1 - .../PrintDialogsTest/PrintDialogsTest.java | 63 +++++++++---------- .../java/awt/Modal/PrintDialogsTest/Test.java | 1 + 3 files changed, 30 insertions(+), 35 deletions(-) diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 789fc93fe7d..974e719c1c9 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -772,7 +772,6 @@ java/awt/event/MouseEvent/SpuriousExitEnter/SpuriousExitEnter_1.java 7131438,802 java/awt/event/MouseEvent/SpuriousExitEnter/SpuriousExitEnter_2.java 7131438,8022539 generic-all java/awt/Modal/WsDisabledStyle/CloseBlocker/CloseBlocker.java 7187741 linux-all,macosx-all java/awt/xembed/server/TestXEmbedServerJava.java 8001150,8004031 generic-all -java/awt/Modal/PrintDialogsTest/PrintDialogsTest.java 8068378 generic-all java/awt/image/VolatileImage/VolatileImageConfigurationTest.java 8171069 macosx-all,linux-all java/awt/Modal/InvisibleParentTest/InvisibleParentTest.java 8172245 linux-all java/awt/Frame/FrameStateTest/FrameStateTest.java 8203920 macosx-all,linux-all diff --git a/test/jdk/java/awt/Modal/PrintDialogsTest/PrintDialogsTest.java b/test/jdk/java/awt/Modal/PrintDialogsTest/PrintDialogsTest.java index e2b2d8cac78..3e191fa0c4c 100644 --- a/test/jdk/java/awt/Modal/PrintDialogsTest/PrintDialogsTest.java +++ b/test/jdk/java/awt/Modal/PrintDialogsTest/PrintDialogsTest.java @@ -49,40 +49,35 @@ import java.awt.event.ActionListener; public class PrintDialogsTest extends Panel implements ActionListener { - static final String INSTRUCTIONS = """ - This test is free format, which means there is no enforced or guided sequence. - - Please select each of - (a) The dialog parent type. - (b) The dialog modality type - (c) The print dialog type (Print dialog or Page Setup dialog) - - Once the choices have been made click the "Start test" button. - - Three windows will appear - (1) A Frame or a Dialog - in the case you selected "Dialog" as the parent type - (2) a Window (ie an undecorated top-level) - (3) A dialog with two buttons "Open" and "Finish" - - Now check as follows whether modal blocking works as expected. - Windows (1) and (2) contain a button which you should be able to press - ONLY if you selected "Non-modal", or "Modeless" for modality type. - In other cases window (3) will block input to (1) and (2) - - Then push the "Open" button on the Dialog to show the printing dialog and check - if it blocks the rest of the application - ie all of windows (1), (2) and (3) - should ALWAYS be blocked when the print dialog is showing. - Now cancel the printing dialog and check the correctness of modal blocking - behavior for the Dialog again. - To close all the 3 test windows please push the "Finish" button. - - Repeat all the above for different combinations, which should include - using all of the Dialog parent choices and all of the Dialog Modality types. - - If any behave incorrectly, note the combination of choices and press Fail. - - If all behave correctly, press Pass. - """; + static final String INSTRUCTIONS = + "1. On the Test UI Select:\n" + + "\tThe dialog parent type. (e.g. Frame, Dialog, Hidden, Null)\n" + + "\tThe dialog modality type. (e.g. Modal, Non-Modal, Toolkit modal).\n" + + "\tThe print dialog type. (Print dialog or Page Setup dialog).\n\n" + + "2. Next, click on 'Start test' - Three windows will appear:\n" + + "\tWindow (1) -a Frame or Dialog (depending on selected parent type).\n" + + "\tWindow (2) -an undecorated top-level Window.\n" + + "\tWindow (3) -a Dialog containing two buttons: 'Open' and 'Finish'.\n" + + "\tWindows (1) & (2) have a Dummy button.\n\n" + + "3. Press the button on Window (1) & Window (2) \n" + + "Verification step:\n" + + "\tIf Modality is 'Non-modal' or 'Modeless', Button is pressed \n" + + "\tIf Modality is 'Document' & parent is not Frame/Dialog, Button is pressed \n" + + "\tIn all other cases, button is not pressed & Window (3) should \n" + + "\tblock input to Windows (1) & (2).\n\n" + + "4. Next, press the 'Open' button in Window (3) to open print dialog.\n\n" + + "5. Press the button on Window (1) & Window (2)\n" + + "Verification step:\n" + + "\tThe print dialog should block all three windows (1, 2, and 3).\n\n" + + "6. Cancel the print dialog, Check again if Window (3) " + + "blocks Windows (1) and (2) correctly.\n" + + "Verification step:\n" + + "\tConditions as seen in Verification step 3 " + + "should be seen, as before.\n" + + "To close all test windows, press 'Finish'.\n\n" + + "7. Repeat the steps for different combinations of Dialog Parent, Dialog Modality Type, Print Dialg Type.\n" + + "Try every dialog parent type and every dialog modality type.\n\n" + + "If any of the Verification step fails, note the combination and press 'Fail'.\n"; public static void main(String[] args) throws Exception { diff --git a/test/jdk/java/awt/Modal/PrintDialogsTest/Test.java b/test/jdk/java/awt/Modal/PrintDialogsTest/Test.java index 3c8faceb3a9..0f190971186 100644 --- a/test/jdk/java/awt/Modal/PrintDialogsTest/Test.java +++ b/test/jdk/java/awt/Modal/PrintDialogsTest/Test.java @@ -191,6 +191,7 @@ public class Test { break; case DIALOG: dialog = new CustomDialog(parent); + break; case FRAME: dialog = new CustomDialog(frame); break; From b6319f5b42738cc760711a3b8b5d442d14a0ed74 Mon Sep 17 00:00:00 2001 From: Volkan Yazici Date: Fri, 12 Dec 2025 18:19:35 +0000 Subject: [PATCH 276/706] 8369595: HttpClient: HttpHeaders.firstValueAsLong failures should be converted to ProtocolException Reviewed-by: dfuchs, djelinski --- .../jdk/internal/net/http/Http1Response.java | 57 +- .../internal/net/http/Http3ExchangeImpl.java | 12 +- .../jdk/internal/net/http/Http3Stream.java | 47 +- .../jdk/internal/net/http/MultiExchange.java | 42 +- .../classes/jdk/internal/net/http/Stream.java | 36 +- .../jdk/internal/net/http/common/Utils.java | 42 ++ .../http3/H3MalformedResponseTest.java | 699 ++++++++++-------- 7 files changed, 529 insertions(+), 406 deletions(-) diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/Http1Response.java b/src/java.net.http/share/classes/jdk/internal/net/http/Http1Response.java index f9442df9ac4..35ce4972ed9 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/Http1Response.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/Http1Response.java @@ -30,6 +30,7 @@ import java.lang.System.Logger.Level; import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.net.http.HttpResponse.BodySubscriber; +import java.net.ProtocolException; import java.nio.ByteBuffer; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; @@ -46,6 +47,7 @@ import jdk.internal.net.http.common.MinimalFuture; import jdk.internal.net.http.common.Utils; import static java.net.http.HttpClient.Version.HTTP_1_1; import static java.net.http.HttpResponse.BodySubscribers.discarding; +import static jdk.internal.net.http.common.Utils.readContentLength; import static jdk.internal.net.http.common.Utils.wrapWithExtraDetail; import static jdk.internal.net.http.RedirectFilter.HTTP_NOT_MODIFIED; @@ -272,16 +274,31 @@ class Http1Response { } /** - * Read up to MAX_IGNORE bytes discarding + * Reads the body, if it is present and less than {@value MAX_IGNORE} bytes. + * Otherwise, just the connection is closed. */ public CompletableFuture ignoreBody(Executor executor) { - int clen = (int)headers.firstValueAsLong("Content-Length").orElse(-1); - if (clen == -1 || clen > MAX_IGNORE) { + + // Read the `Content-Length` header + long clen; + try { + clen = readContentLength(headers, "", -1); + } catch (ProtocolException pe) { + return MinimalFuture.failedFuture(pe); + } + + // Read the body, if it is present and less than `MAX_IGNORE` bytes. + // + // We proceed with reading the body even when `Content-Length: 0` to + // ensure that the happy path is taken, and upon success, the connection + // is returned back to the pool. + if (clen != -1 && clen <= MAX_IGNORE) { + return readBody(discarding(), !request.isWebSocket(), executor); + } else { connection.close(); return MinimalFuture.completedFuture(null); // not treating as error - } else { - return readBody(discarding(), !request.isWebSocket(), executor); } + } // Used for those response codes that have no body associated @@ -308,11 +325,28 @@ class Http1Response { this.return2Cache = return2Cache; final BodySubscriber subscriber = p; - final CompletableFuture cf = new MinimalFuture<>(); - long clen0 = headers.firstValueAsLong("Content-Length").orElse(-1L); - final long clen = fixupContentLen(clen0); + Consumer errorNotifier = error -> { + try { + subscriber.onError(error); + cf.completeExceptionally(error); + } finally { + asyncReceiver.setRetryOnError(false); + asyncReceiver.onReadError(error); + } + }; + + // Read the content length + long clen; + try { + long clen0 = readContentLength(headers, "", -1); + clen = fixupContentLen(clen0); + } catch (ProtocolException pe) { + errorNotifier.accept(pe); + connection.close(pe); + return cf; + } // expect-continue reads headers and body twice. // if we reach here, we must reset the headersReader state. @@ -398,12 +432,7 @@ class Http1Response { } }); - ResponseSubscribers.getBodyAsync(executor, p, cf, (t) -> { - subscriber.onError(t); - cf.completeExceptionally(t); - asyncReceiver.setRetryOnError(false); - asyncReceiver.onReadError(t); - }); + ResponseSubscribers.getBodyAsync(executor, p, cf, errorNotifier); return cf.whenComplete((s,t) -> { if (t != null) { diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/Http3ExchangeImpl.java b/src/java.net.http/share/classes/jdk/internal/net/http/Http3ExchangeImpl.java index 81475a47c4a..4625968682f 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/Http3ExchangeImpl.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/Http3ExchangeImpl.java @@ -81,6 +81,8 @@ import jdk.internal.net.http.qpack.writers.HeaderFrameWriter; import jdk.internal.net.http.quic.streams.QuicBidiStream; import jdk.internal.net.http.quic.streams.QuicStreamReader; import jdk.internal.net.http.quic.streams.QuicStreamWriter; + +import static jdk.internal.net.http.common.Utils.readContentLength; import static jdk.internal.net.http.http3.ConnectionSettings.UNLIMITED_MAX_FIELD_SECTION_SIZE; /** @@ -1293,12 +1295,16 @@ final class Http3ExchangeImpl extends Http3Stream { if (Set.of("PUT", "DELETE", "OPTIONS", "TRACE").contains(method)) { throw new ProtocolException("push method not allowed pushId=" + pushId); } - long clen = promiseHeaders.firstValueAsLong("Content-Length").orElse(-1); + + // Read & validate `Content-Length` + long clen = readContentLength( + promiseHeaders, "illegal push headers for pushId=%s: ".formatted(pushId), -1); if (clen > 0) { - throw new ProtocolException("push headers contain non-zero Content-Length for pushId=" + pushId); + throw new ProtocolException("push headers contain non-zero \"Content-Length\" for pushId=" + pushId); } + if (promiseHeaders.firstValue("Transfer-Encoding").isPresent()) { - throw new ProtocolException("push headers contain Transfer-Encoding for pushId=" + pushId); + throw new ProtocolException("push headers contain \"Transfer-Encoding\" for pushId=" + pushId); } diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/Http3Stream.java b/src/java.net.http/share/classes/jdk/internal/net/http/Http3Stream.java index cdac68b47f1..14e440a0e33 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/Http3Stream.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/Http3Stream.java @@ -31,7 +31,6 @@ import java.net.ProtocolException; import java.net.http.HttpHeaders; import java.nio.ByteBuffer; import java.util.List; -import java.util.OptionalLong; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.atomic.AtomicInteger; @@ -58,6 +57,8 @@ import jdk.internal.net.http.quic.streams.QuicStreamReader; import static jdk.internal.net.http.Exchange.MAX_NON_FINAL_RESPONSES; import static jdk.internal.net.http.RedirectFilter.HTTP_NOT_MODIFIED; +import static jdk.internal.net.http.common.Utils.readContentLength; +import static jdk.internal.net.http.common.Utils.readStatusCode; /** * A common super class for the HTTP/3 request/response stream ({@link Http3ExchangeImpl} @@ -606,23 +607,17 @@ sealed abstract class Http3Stream extends ExchangeImpl permits Http3Exchan } int responseCode; - boolean finalResponse = false; try { - responseCode = (int) responseHeaders - .firstValueAsLong(":status") - .orElseThrow(() -> new IOException("no statuscode in response")); - } catch (IOException | NumberFormatException exception) { + responseCode = readStatusCode(responseHeaders, ""); + } catch (ProtocolException pe) { // RFC-9114: 4.1.2. Malformed Requests and Responses: // "Malformed requests or responses that are // detected MUST be treated as a stream error of type H3_MESSAGE_ERROR" - cancelImpl(exception, Http3Error.H3_MESSAGE_ERROR); - return; - } - if (responseCode < 100 || responseCode > 999) { - cancelImpl(new IOException("Unexpected :status header value"), Http3Error.H3_MESSAGE_ERROR); + cancelImpl(pe, Http3Error.H3_MESSAGE_ERROR); return; } + boolean finalResponse = false; if (responseCode >= 200) { responseState = ResponseState.PERMIT_TRAILER; finalResponse = true; @@ -653,23 +648,21 @@ sealed abstract class Http3Stream extends ExchangeImpl permits Http3Exchan responseHeaders); } - try { - OptionalLong cl = responseHeaders.firstValueAsLong("content-length"); - if (finalResponse && cl.isPresent()) { - long cll = cl.getAsLong(); - if (cll < 0) { - cancelImpl(new IOException("Invalid content-length value "+cll), Http3Error.H3_MESSAGE_ERROR); - return; - } - if (!(exchange.request().method().equalsIgnoreCase("HEAD") || responseCode == HTTP_NOT_MODIFIED)) { - // HEAD response and 304 response might have a content-length header, - // but it carries no meaning - contentLength = cll; - } + if (finalResponse) { + long cl; + try { + cl = readContentLength(responseHeaders, "", -1); + } catch (ProtocolException pe) { + cancelImpl(pe, Http3Error.H3_MESSAGE_ERROR); + return; + } + if (cl != -1 && + !(exchange.request().method().equalsIgnoreCase("HEAD") || + responseCode == HTTP_NOT_MODIFIED)) { + // HEAD response and 304 response might have a content-length header, + // but it carries no meaning + contentLength = cl; } - } catch (NumberFormatException nfe) { - cancelImpl(nfe, Http3Error.H3_MESSAGE_ERROR); - return; } if (Log.headers() || debug.on()) { diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/MultiExchange.java b/src/java.net.http/share/classes/jdk/internal/net/http/MultiExchange.java index 60eb55ec0ad..671874b8fb5 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/MultiExchange.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/MultiExchange.java @@ -28,8 +28,11 @@ package jdk.internal.net.http; import java.io.IOException; import java.lang.ref.WeakReference; import java.net.ConnectException; +import java.net.ProtocolException; +import java.net.ProtocolException; import java.net.http.HttpClient.Version; import java.net.http.HttpConnectTimeoutException; +import java.net.http.HttpHeaders; import java.net.http.StreamLimitException; import java.time.Duration; import java.util.List; @@ -47,7 +50,6 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.function.Function; import java.net.http.HttpClient; -import java.net.http.HttpHeaders; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.net.http.HttpResponse.BodySubscriber; @@ -62,6 +64,7 @@ import jdk.internal.net.http.common.Utils; import static jdk.internal.net.http.common.MinimalFuture.completedFuture; import static jdk.internal.net.http.common.MinimalFuture.failedFuture; import static jdk.internal.net.http.AltSvcProcessor.processAltSvcHeader; +import static jdk.internal.net.http.common.Utils.readContentLength; /** @@ -358,13 +361,22 @@ class MultiExchange implements Cancelable { return r.statusCode == 204; } - private boolean bodyIsPresent(Response r) { - HttpHeaders headers = r.headers(); - if (headers.firstValueAsLong("Content-length").orElse(0L) != 0L) - return true; - if (headers.firstValue("Transfer-encoding").isPresent()) - return true; - return false; + private void ensureNoBody(HttpHeaders headers) throws ProtocolException { + + // Check `Content-Length` + var contentLength = readContentLength(headers, "", 0); + if (contentLength > 0) { + throw new ProtocolException( + "Unexpected \"Content-Length\" header in a 204 response: " + contentLength); + } + + // Check `Transfer-Encoding` + var transferEncoding = headers.firstValue("Transfer-Encoding"); + if (transferEncoding.isPresent()) { + throw new ProtocolException( + "Unexpected \"Transfer-Encoding\" header in a 204 response: " + transferEncoding.get()); + } + } // Call the user's body handler to get an empty body object @@ -405,13 +417,13 @@ class MultiExchange implements Cancelable { if (bodyNotPermitted(r)) { // No response body consumption is expected, we can cancel the timer right away cancelTimer(); - if (bodyIsPresent(r)) { - IOException ioe = new IOException( - "unexpected content length header with 204 response"); - exch.cancel(ioe); - return MinimalFuture.failedFuture(ioe); - } else - return handleNoBody(r, exch); + try { + ensureNoBody(r.headers); + } catch (ProtocolException pe) { + exch.cancel(pe); + return MinimalFuture.failedFuture(pe); + } + return handleNoBody(r, exch); } return exch.readBodyAsync(responseHandler) .thenApply((T body) -> setNewResponse(r.request, r, body, exch)); diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/Stream.java b/src/java.net.http/share/classes/jdk/internal/net/http/Stream.java index bf9170f8f51..9826b280438 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/Stream.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/Stream.java @@ -61,6 +61,7 @@ import jdk.internal.net.http.hpack.DecodingCallback; import static jdk.internal.net.http.AltSvcProcessor.processAltSvcFrame; import static jdk.internal.net.http.Exchange.MAX_NON_FINAL_RESPONSES; +import static jdk.internal.net.http.common.Utils.readStatusCode; /** * Http/2 Stream handling. @@ -615,18 +616,14 @@ class Stream extends ExchangeImpl { return null; } - protected void handleResponse(HeaderFrame hf) throws IOException { + protected void handleResponse(HeaderFrame hf) { HttpHeaders responseHeaders = responseHeadersBuilder.build(); if (!finalResponseCodeReceived) { try { - responseCode = (int) responseHeaders - .firstValueAsLong(":status") - .orElseThrow(() -> new ProtocolException(String.format( - "Stream %s PROTOCOL_ERROR: no status code in response", - streamid))); - } catch (ProtocolException cause) { - cancelImpl(cause, ResetFrame.PROTOCOL_ERROR); + responseCode = readStatusCode(responseHeaders, "Stream %s PROTOCOL_ERROR: ".formatted(streamid)); + } catch (ProtocolException pe) { + cancelImpl(pe, ResetFrame.PROTOCOL_ERROR); rspHeadersConsumer.reset(); return; } @@ -1730,21 +1727,18 @@ class Stream extends ExchangeImpl { HttpHeaders responseHeaders = responseHeadersBuilder.build(); if (!finalPushResponseCodeReceived) { - responseCode = (int)responseHeaders - .firstValueAsLong(":status") - .orElse(-1); - - if (responseCode == -1) { - cancelImpl(new ProtocolException("No status code"), ResetFrame.PROTOCOL_ERROR); + try { + responseCode = readStatusCode(responseHeaders, ""); + if (responseCode >= 100 && responseCode < 200) { + String protocolErrorMsg = checkInterimResponseCountExceeded(); + if (protocolErrorMsg != null) { + throw new ProtocolException(protocolErrorMsg); + } + } + } catch (ProtocolException pe) { + cancelImpl(pe, ResetFrame.PROTOCOL_ERROR); rspHeadersConsumer.reset(); return; - } else if (responseCode >= 100 && responseCode < 200) { - String protocolErrorMsg = checkInterimResponseCountExceeded(); - if (protocolErrorMsg != null) { - cancelImpl(new ProtocolException(protocolErrorMsg), ResetFrame.PROTOCOL_ERROR); - rspHeadersConsumer.reset(); - return; - } } this.finalPushResponseCodeReceived = true; diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/common/Utils.java b/src/java.net.http/share/classes/jdk/internal/net/http/common/Utils.java index 20b0338215c..e5ea07c3b97 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/common/Utils.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/common/Utils.java @@ -39,6 +39,7 @@ import java.lang.System.Logger.Level; import java.net.ConnectException; import java.net.Inet6Address; import java.net.InetSocketAddress; +import java.net.ProtocolException; import java.net.SocketAddress; import java.net.StandardSocketOptions; import java.net.Proxy; @@ -1354,6 +1355,47 @@ public final class Utils { } // -- toAsciiString-like support to encode path and query URI segments + public static int readStatusCode(HttpHeaders headers, String errorPrefix) throws ProtocolException { + var s = headers.firstValue(":status").orElse(null); + if (s == null) { + throw new ProtocolException(errorPrefix + "missing status code"); + } + Throwable t = null; + int i = 0; + try { + i = Integer.parseInt(s); + } catch (NumberFormatException nfe) { + t = nfe; + } + if (t != null || i < 100 || i > 999) { + var pe = new ProtocolException(errorPrefix + "invalid status code: " + s); + pe.initCause(t); + throw pe; + } + return i; + } + + public static long readContentLength(HttpHeaders headers, String errorPrefix, long defaultIfMissing) throws ProtocolException { + var k = "Content-Length"; + var s = headers.firstValue(k).orElse(null); + if (s == null) { + return defaultIfMissing; + } + Throwable t = null; + long i = 0; + try { + i = Long.parseLong(s); + } catch (NumberFormatException nfe) { + t = nfe; + } + if (t != null || i < 0) { + var pe = new ProtocolException("%sinvalid \"%s\": %s".formatted(errorPrefix, k, s)); + pe.initCause(t); + throw pe; + } + return i; + } + // Encodes all characters >= \u0080 into escaped, normalized UTF-8 octets, // assuming that s is otherwise legal // diff --git a/test/jdk/java/net/httpclient/http3/H3MalformedResponseTest.java b/test/jdk/java/net/httpclient/http3/H3MalformedResponseTest.java index 881277da1f8..ea1efaf4933 100644 --- a/test/jdk/java/net/httpclient/http3/H3MalformedResponseTest.java +++ b/test/jdk/java/net/httpclient/http3/H3MalformedResponseTest.java @@ -22,410 +22,457 @@ */ import jdk.httpclient.test.lib.common.HttpServerAdapters; -import jdk.httpclient.test.lib.quic.QuicServerConnection; import jdk.httpclient.test.lib.quic.QuicStandaloneServer; -import jdk.internal.net.http.http3.Http3Error; -import jdk.internal.net.http.quic.TerminationCause; +import jdk.internal.net.http.common.Logger; +import jdk.internal.net.http.common.Utils; import jdk.internal.net.quic.QuicVersion; import jdk.test.lib.net.SimpleSSLContext; import jdk.test.lib.net.URIBuilder; -import jdk.test.lib.Utils; -import org.testng.annotations.AfterClass; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; import javax.net.ssl.SSLContext; +import java.io.IOException; import java.io.OutputStream; -import java.net.URI; -import java.net.URISyntaxException; +import java.net.ProtocolException; import java.net.http.HttpClient; import java.net.http.HttpClient.Version; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.net.http.HttpResponse.BodyHandlers; import java.util.HexFormat; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.BooleanSupplier; -import static java.net.http.HttpOption.Http3DiscoveryMode.HTTP_3_URI_ONLY; +import static java.net.http.HttpClient.Builder.NO_PROXY; import static java.net.http.HttpOption.H3_DISCOVERY; -import static org.testng.Assert.*; +import static java.net.http.HttpOption.Http3DiscoveryMode.HTTP_3_URI_ONLY; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; /* * @test - * @summary Verifies that the HTTP client correctly handles malformed responses - * @library /test/lib /test/jdk/java/net/httpclient/lib - * @library ../access - * @build jdk.test.lib.net.SimpleSSLContext - * jdk.httpclient.test.lib.common.HttpServerAdapters - * @build java.net.http/jdk.internal.net.http.Http3ConnectionAccess - * @run testng/othervm - * -Djdk.internal.httpclient.debug=true - * -Djdk.httpclient.HttpClient.log=requests,responses,errors H3MalformedResponseTest + * @bug 8369595 + * @summary Verifies that the HTTP/3 malformed responses are correctly handled + * @library /test/jdk/java/net/httpclient/lib + * /test/lib + * @run junit ${test.main.class} */ -public class H3MalformedResponseTest implements HttpServerAdapters { - private SSLContext sslContext; - private QuicStandaloneServer server; - private String requestURIBase; +/// Verifies that the HTTP/3 malformed responses are correctly handled. +/// +/// ### HTTP/3 `HEADERS` frame & QPACK Field Section encoding crash course +/// +/// Consider an HTTP/3 `HEADERS` frame that carries: +/// +/// ``` +/// :status: 200 +/// content-length: 2 +/// ``` +/// +/// This will be encoded as the following byte sequence: +/// +/// ``` +/// 01 06 00 00 D9 54 01 32 +/// ``` +/// +/// Let's start with decoding the HTTP/3 frame: +/// +/// - `01`: Frame Type (`01` denotes `HEADERS``) +/// +/// - `06`: Payload length (6 bytes) +/// +/// Figured this is a `HEADERS` frame containing 6 bytes: `00 00 D9 54 01 32`. +/// Let's decode the QPACK Field Section +/// +/// - `00`: Required Insert Count (0) +/// +/// - `00`: Base (0) +/// +/// - `D9`: +/// QPACK has a static table (indexed from 0) and `:status: 200` is at the +/// static-table index 25. +/// +/// ``` +/// D9 = <1101 1001> +/// = <1> (Indexed Field Line) +/// + <1> (Static Table) +/// + <01 1001> (entry index = 25) +/// ``` +/// +/// - `54 01 32`: +/// `content-length: 2` can be encoded as a *literal field line with name +/// reference* using the static name `content-length` (static index 4) and +/// the literal value `2`. +/// +/// ``` +/// 54 01 32 = <0101 0100 0000 0001 0011 0010> +/// = <0> (Literal Field Line) +/// + <1> (Name Reference) +/// + <0100> (entry index = 4) +/// + <0000 0001> (value length = 1 byte) +/// + <0011 0010> (value = ASCII "2" = 0x32 = 50) +/// ``` +/// +/// Note that the `value length` field (i.e., `0000 0001`) follows a variable +/// coding scheme: +/// +/// | Prefix | Total size | Payload size | Max value | +/// | --------------------- | ---------- | ------------ | ------------- | +/// | `00xx xxxx` | 1 byte | 6 bits | 63 | +/// | `01xx xxxx xxxx xxxx` | 2 bytes | 14 bits | 16,383 | +/// | `10xx xxx…` | 4 bytes | 30 bits | 1,073,741,823 | +/// | `11xx xxx…` | 8 bytes | 62 bits | 4.61e18 | +class H3MalformedResponseTest { - // These responses are malformed and should not be accepted by the client, - // but they should not cause connection closure - @DataProvider - public static Object[][] malformedResponse() { + private static final String CLASS_NAME = H3MalformedResponseTest.class.getSimpleName(); + + private static final Logger LOGGER = Utils.getDebugLogger(CLASS_NAME::toString, Utils.DEBUG); + + private static SSLContext SSL_CONTEXT; + + private static QuicStandaloneServer SERVER; + + private static HttpRequest REQUEST; + + @BeforeAll + static void setUp() throws Exception { + + // Obtain an `SSLContext` + SSL_CONTEXT = new SimpleSSLContext().get(); + assertNotNull(SSL_CONTEXT); + + // Create and start the server + SERVER = QuicStandaloneServer.newBuilder() + .availableVersions(new QuicVersion[]{QuicVersion.QUIC_V1}) + .sslContext(SSL_CONTEXT) + .alpn("h3") + .build(); + SERVER.start(); + LOGGER.log("Server is started at {}", SERVER.getAddress()); + + // Create the request + var requestURI = URIBuilder.newBuilder() + .scheme("https") + .loopback() + .port(SERVER.getAddress().getPort()) + .path("/" + CLASS_NAME) + .build(); + REQUEST = HttpRequest.newBuilder(requestURI) + .version(Version.HTTP_3) + .setOption(H3_DISCOVERY, HTTP_3_URI_ONLY) + .build(); + + } + + @AfterAll + static void tearDown() { + close("server", SERVER); + } + + private static void close(String name, AutoCloseable closeable) { + if (closeable != null) { + LOGGER.log("Closing {}", name); + try { + closeable.close(); + } catch (Exception e) { + LOGGER.log("Could not close " + name, e); + } + } + } + + /// Malformed responses that should not be accepted by the client, but + /// should neither cause the connection to get closed. + static Object[][] malformedResponsesPreservingConnection() { return new Object[][]{ - new Object[] {"empty", HexFormat.of().parseHex( - "" + {"empty", IOException.class, parseHex("")}, + {"non-final response", IOException.class, parseHex( + "01040000", // headers, length 4, section prefix + "ff00" // :status:100 )}, - new Object[] {"non-final response", HexFormat.of().parseHex( - "01040000"+ // headers, length 4, section prefix - "ff00" // :status:100 + {"uppercase header name", ProtocolException.class, parseHex( + "01090000", // headers, length 9, section prefix + "d9", // :status:200 + "234147450130", // AGE:0 + "000100" // data, 1 byte )}, - new Object[] {"uppercase header name", HexFormat.of().parseHex( - "01090000"+ // headers, length 9, section prefix - "d9"+ // :status:200 - "234147450130"+ // AGE:0 + {"content too long", IOException.class, parseHex( + "01040000", // headers, length 4, section prefix + "d9", // :status:200 + "c4", // content-length:0 + "000100" // data, 1 byte + )}, + {"content too short", IOException.class, parseHex( + "01060000", // headers, length 6, section prefix + "d9", // :status:200 + "540132", // content-length:2 + "000100" // data, 1 byte + )}, + {"text in content-length", ProtocolException.class, parseHex( + "01060000" + // headers, length 6, section prefix + "d9" + // :status:200 + "540161" + // content-length:a "000100" // data, 1 byte )}, - new Object[] {"content too long", HexFormat.of().parseHex( - "01040000"+ // headers, length 4, section prefix - "d9"+ // :status:200 - "c4"+ // content-length:0 - "000100" // data, 1 byte - )}, - new Object[] {"content too short", HexFormat.of().parseHex( - "01060000"+ // headers, length 6, section prefix - "d9"+ // :status:200 - "540132"+ // content-length:2 - "000100" // data, 1 byte - )}, - new Object[] {"text in content-length", HexFormat.of().parseHex( - "01060000"+ // headers, length 6, section prefix - "d9"+ // :status:200 - "540161"+ // content-length:a - "000100" // data, 1 byte - )}, - new Object[] {"connection: close", HexFormat.of().parseHex( - "01150000"+ // headers, length 21, section prefix - "d9"+ // :status:200 - "2703636F6E6E656374696F6E05636C6F7365"+ // connection:close + {"connection: close", ProtocolException.class, parseHex( + "01150000", // headers, length 21, section prefix + "d9", // :status:200 + "2703636F6E6E656374696F6E05636C6F7365" + // connection:close "000100" // data, 1 byte )}, // request pseudo-headers in response - new Object[] {":method in response", HexFormat.of().parseHex( - "01040000"+ // headers, length 4, section prefix - "d9"+ // :status:200 - "d1"+ // :method:get - "000100" // data, 1 byte + {":method in response", ProtocolException.class, parseHex( + "01040000", // headers, length 4, section prefix + "d9", // :status:200 + "d1", // :method:get + "000100" // data, 1 byte )}, - new Object[] {":authority in response", HexFormat.of().parseHex( - "01100000"+ // headers, length 16, section prefix - "d9"+ // :status:200 - "508b089d5c0b8170dc702fbce7"+ // :authority - "000100" // data, 1 byte + {":authority in response", ProtocolException.class, parseHex( + "01100000", // headers, length 16, section prefix + "d9", // :status:200 + "508b089d5c0b8170dc702fbce7", // :authority + "000100" // data, 1 byte )}, - new Object[] {":path in response", HexFormat.of().parseHex( - "010a0000"+ // headers, length 10, section prefix - "d9"+ // :status:200 - "51856272d141ff"+ // :path - "000100" // data, 1 byte + {":path in response", ProtocolException.class, parseHex( + "010a0000", // headers, length 10, section prefix + "d9", // :status:200 + "51856272d141ff", // :path + "000100" // data, 1 byte )}, - new Object[] {":scheme in response", HexFormat.of().parseHex( - "01040000"+ // headers, length 4, section prefix - "d9"+ // :status:200 - "d7"+ // :scheme:https - "000100" // data, 1 byte + {":scheme in response", ProtocolException.class, parseHex( + "01040000", // headers, length 4, section prefix + "d9", // :status:200 + "d7", // :scheme:https + "000100" // data, 1 byte )}, - new Object[] {"undefined pseudo-header", HexFormat.of().parseHex( - "01080000"+ // headers, length 8, section prefix - "d9"+ // :status:200 - "223A6D0130"+ // :m:0 - "000100" // data, 1 byte + {"undefined pseudo-header", ProtocolException.class, parseHex( + "01080000", // headers, length 8, section prefix + "d9", // :status:200 + "223A6D0130", // :m:0 + "000100" // data, 1 byte )}, - new Object[] {"pseudo-header after regular", HexFormat.of().parseHex( - "011a0000"+ // headers, length 26, section prefix - "5f5094ca3ee35a74a6b589418b5258132b1aa496ca8747"+ //user-agent - "d9"+ // :status:200 - "000100" // data, 1 byte + {"pseudo-header after regular", ProtocolException.class, parseHex( + "011a0000", // headers, length 26, section prefix + "5f5094ca3ee35a74a6b589418b5258132b1aa496ca8747", //user-agent + "d9", // :status:200 + "000100" // data, 1 byte )}, - new Object[] {"trailer", HexFormat.of().parseHex( + {"trailer", IOException.class, parseHex( "01020000" // headers, length 2, section prefix )}, - new Object[] {"trailer+data", HexFormat.of().parseHex( - "01020000"+ // headers, length 2, section prefix - "000100" // data, 1 byte + {"trailer+data", IOException.class, parseHex( + "01020000", // headers, length 2, section prefix + "000100" // data, 1 byte )}, // valid characters include \t, 0x20-0x7e, 0x80-0xff (RFC 9110, section 5.5) - new Object[] {"invalid character in field value 00", HexFormat.of().parseHex( - "01060000"+ // headers, length 6, section prefix - "d9"+ // :status:200 - "570100"+ // etag:\0 - "000100" // data, 1 byte + {"invalid character in field value 00", ProtocolException.class, parseHex( + "01060000", // headers, length 6, section prefix + "d9", // :status:200 + "570100", // etag:\0 + "000100" // data, 1 byte )}, - new Object[] {"invalid character in field value 0a", HexFormat.of().parseHex( - "01060000"+ // headers, length 6, section prefix - "d9"+ // :status:200 - "57010a"+ // etag:\n - "000100" // data, 1 byte + {"invalid character in field value 0a", ProtocolException.class, parseHex( + "01060000", // headers, length 6, section prefix + "d9", // :status:200 + "57010a", // etag:\n + "000100" // data, 1 byte )}, - new Object[] {"invalid character in field value 0d", HexFormat.of().parseHex( - "01060000"+ // headers, length 6, section prefix - "d9"+ // :status:200 - "57010d"+ // etag:\r - "000100" // data, 1 byte + {"invalid character in field value 0d", ProtocolException.class, parseHex( + "01060000", // headers, length 6, section prefix + "d9", // :status:200 + "57010d", // etag:\r + "000100" // data, 1 byte )}, - new Object[] {"invalid character in field value 7f", HexFormat.of().parseHex( - "01060000"+ // headers, length 6, section prefix - "d9"+ // :status:200 - "57017f"+ // etag: 0x7f - "000100" // data, 1 byte + {"invalid character in field value 7f", ProtocolException.class, parseHex( + "01060000", // headers, length 6, section prefix + "d9", // :status:200 + "57017f", // etag: 0x7f + "000100" // data, 1 byte )}, }; } - // These responses are malformed and should not be accepted by the client. - // They might or might not cause connection closure (H3_FRAME_UNEXPECTED) - @DataProvider - public static Object[][] malformedResponse2() { + /// Malformed responses that should not be accepted by the client. + /// They might or might not cause the connection to get closed (`H3_FRAME_UNEXPECTED`). + static Object[][] malformedResponses() { // data before headers is covered by H3ErrorHandlingTest return new Object[][]{ - new Object[] {"100+data", HexFormat.of().parseHex( - "01040000"+ // headers, length 4, section prefix - "ff00"+ // :status:100 - "000100" // data, 1 byte + {"100+data", IOException.class, parseHex( + "01040000", // headers, length 4, section prefix + "ff00", // :status:100 + "000100" // data, 1 byte )}, - new Object[] {"100+data+200", HexFormat.of().parseHex( - "01040000"+ // headers, length 4, section prefix - "ff00"+ // :status:100 - "000100"+ // data, 1 byte - "01030000"+ // headers, length 3, section prefix - "d9" // :status:200 + {"100+data+200", IOException.class, parseHex( + "01040000", // headers, length 4, section prefix + "ff00", // :status:100 + "000100", // data, 1 byte + "01030000", // headers, length 3, section prefix + "d9" // :status:200 )}, - new Object[] {"200+data+200", HexFormat.of().parseHex( - "01030000"+ // headers, length 3, section prefix - "d9"+ // :status:200 - "000100"+ // data, 1 byte - "01030000"+ // headers, length 3, section prefix - "d9" // :status:200 + {"200+data+200", IOException.class, parseHex( + "01030000", // headers, length 3, section prefix + "d9", // :status:200 + "000100", // data, 1 byte + "01030000", // headers, length 3, section prefix + "d9" // :status:200 )}, - new Object[] {"200+data+100", HexFormat.of().parseHex( - "01030000"+ // headers, length 3, section prefix - "d9"+ // :status:200 - "000100"+ // data, 1 byte - "01040000"+ // headers, length 4, section prefix - "ff00" // :status:100 + {"200+data+100", IOException.class, parseHex( + "01030000", // headers, length 3, section prefix + "d9", // :status:200 + "000100", // data, 1 byte + "01040000", // headers, length 4, section prefix + "ff00" // :status:100 )}, - new Object[] {"200+data+trailers+data", HexFormat.of().parseHex( - "01030000"+ // headers, length 3, section prefix - "d9"+ // :status:200 - "000100"+ // data, 1 byte - "01020000"+ // trailers, length 2, section prefix - "000100" // data, 1 byte + {"200+data+trailers+data", ProtocolException.class, parseHex( + "01030000", // headers, length 3, section prefix + "d9", // :status:200 + "000100", // data, 1 byte + "01020000", // trailers, length 2, section prefix + "000100" // data, 1 byte )}, - new Object[] {"200+trailers+data", HexFormat.of().parseHex( - "01030000"+ // headers, length 3, section prefix - "d9"+ // :status:200 - "01020000"+ // trailers, length 2, section prefix - "000100" // data, 1 byte + {"200+trailers+data", IOException.class, parseHex( + "01030000", // headers, length 3, section prefix + "d9", // :status:200 + "01020000", // trailers, length 2, section prefix + "000100" // data, 1 byte )}, - new Object[] {"200+200", HexFormat.of().parseHex( - "01030000"+ // headers, length 3, section prefix - "d9"+ // :status:200 - "01030000"+ // headers, length 3, section prefix - "d9" // :status:200 + {"200+200", IOException.class, parseHex( + "01030000", // headers, length 3, section prefix + "d9", // :status:200 + "01030000", // headers, length 3, section prefix + "d9" // :status:200 )}, - new Object[] {"200+100", HexFormat.of().parseHex( - "01030000"+ // headers, length 3, section prefix - "d9"+ // :status:200 - "01040000"+ // headers, length 4, section prefix - "ff00" // :status:100 + {"200+100", IOException.class, parseHex( + "01030000", // headers, length 3, section prefix + "d9", // :status:200 + "01040000", // headers, length 4, section prefix + "ff00" // :status:100 )}, }; } - @DataProvider - public static Object[][] wellformedResponse() { + /// Well-formed responses that should be accepted by the client. + static Object[][] wellFormedResponses() { return new Object[][]{ - new Object[] {"100+200+data+reserved", HexFormat.of().parseHex( - "01040000"+ // headers, length 4, section prefix - "ff00"+ // :status:100 - "01030000"+ // headers, length 3, section prefix - "d9"+ // :status:200 - "000100"+ // data, 1 byte - "210100" // reserved, 1 byte + {"100+200+data+reserved", parseHex( + "01040000", // headers, length 4, section prefix + "ff00", // :status:100 + "01030000", // headers, length 3, section prefix + "d9", // :status:200 + "000100", // data, 1 byte + "210100" // reserved, 1 byte )}, - new Object[] {"200+data+reserved", HexFormat.of().parseHex( - "01030000"+ // headers, length 3, section prefix - "d9"+ // :status:200 - "000100"+ // data, 1 byte - "210100" // reserved, 1 byte + {"200+data+reserved", parseHex( + "01030000", // headers, length 3, section prefix + "d9", // :status:200 + "000100", // data, 1 byte + "210100" // reserved, 1 byte )}, - new Object[] {"200+data", HexFormat.of().parseHex( - "01030000"+ // headers, length 3, section prefix - "d9"+ // :status:200 - "000100" // data, 1 byte + {"200+data", parseHex( + "01030000", // headers, length 3, section prefix + "d9", // :status:200 + "000100" // data, 1 byte )}, - new Object[] {"200+user-agent+data", HexFormat.of().parseHex( - "011a0000"+ // headers, length 26, section prefix - "d9"+ // :status:200 - "5f5094ca3ee35a74a6b589418b5258132b1aa496ca8747"+ //user-agent - "000100" // data, 1 byte + {"200+user-agent+data", parseHex( + "011a0000", // headers, length 26, section prefix + "d9", // :status:200 + "5f5094ca3ee35a74a6b589418b5258132b1aa496ca8747", //user-agent + "000100" // data, 1 byte )}, - new Object[] {"200", HexFormat.of().parseHex( - "01030000"+ // headers, length 3, section prefix - "d9" // :status:200 + {"200", parseHex( + "01030000", // headers, length 3, section prefix + "d9" // :status:200 )}, - new Object[] {"200+data+data", HexFormat.of().parseHex( - "01030000"+ // headers, length 3, section prefix - "d9"+ // :status:200 - "000100"+ // data, 1 byte - "000100" // data, 1 byte + {"200+data+data", parseHex( + "01030000", // headers, length 3, section prefix + "d9", // :status:200 + "000100", // data, 1 byte + "000100" // data, 1 byte )}, - new Object[] {"200+data+trailers", HexFormat.of().parseHex( - "01030000"+ // headers, length 3, section prefix - "d9"+ // :status:200 - "000100"+ // data, 1 byte - "01020000" // trailers, length 2, section prefix + {"200+data+trailers", parseHex( + "01030000", // headers, length 3, section prefix + "d9", // :status:200 + "000100", // data, 1 byte + "01020000" // trailers, length 2, section prefix )}, - new Object[] {"200+trailers", HexFormat.of().parseHex( - "01030000"+ // headers, length 3, section prefix - "d9"+ // :status:200 - "01020000" // trailers, length 2, section prefix + {"200+trailers", parseHex( + "01030000", // headers, length 3, section prefix + "d9", // :status:200 + "01020000" // trailers, length 2, section prefix )}, }; } - @BeforeClass - public void beforeClass() throws Exception { - sslContext = new SimpleSSLContext().get(); - if (sslContext == null) { - throw new AssertionError("Unexpected null sslContext"); + private static byte[] parseHex(String... strings) { + var buffer = new StringBuilder(); + for (String string : strings) { + buffer.append(string); } - server = QuicStandaloneServer.newBuilder() - .availableVersions(new QuicVersion[]{QuicVersion.QUIC_V1}) - .sslContext(sslContext) - .alpn("h3") + return HexFormat.of().parseHex(buffer.toString()); + } + + @ParameterizedTest + @MethodSource("wellFormedResponses") + void testWellFormedResponse(String desc, byte[] serverResponseBytes) throws Exception { + var connectionTerminated = configureServerResponse(serverResponseBytes); + try (var client = createClient()) { + final HttpResponse response = client.send(REQUEST, BodyHandlers.discarding()); + assertEquals(200, response.statusCode()); + assertFalse(connectionTerminated.getAsBoolean(), "Expected the connection to be open"); + } + } + + @ParameterizedTest + @MethodSource("malformedResponsesPreservingConnection") + void testMalformedResponsePreservingConnection( + String desc, + Class exceptionClass, + byte[] serverResponseBytes) { + var connectionTerminated = configureServerResponse(serverResponseBytes); + try (var client = createClient()) { + var exception = assertThrows(exceptionClass, () -> client.send(REQUEST, BodyHandlers.discarding())); + LOGGER.log("Got expected exception for: " + desc, exception); + assertFalse(connectionTerminated.getAsBoolean(), "Expected the connection to be open"); + } + } + + @ParameterizedTest + @MethodSource("malformedResponses") + void testMalformedResponse( + String desc, + Class exceptionClass, + byte[] serverResponseBytes) { + configureServerResponse(serverResponseBytes); + try (var client = createClient()) { + var exception = assertThrows(exceptionClass, () -> client.send(REQUEST, BodyHandlers.discarding())); + LOGGER.log("Got expected exception for: " + desc, exception); + } + } + + private static HttpClient createClient() { + return HttpServerAdapters.createClientBuilderForH3() + .proxy(NO_PROXY) + .version(Version.HTTP_3) + .sslContext(SSL_CONTEXT) .build(); - server.start(); - System.out.println("Server started at " + server.getAddress()); - requestURIBase = URIBuilder.newBuilder().scheme("https").loopback() - .port(server.getAddress().getPort()).build().toString(); } - @AfterClass - public void afterClass() throws Exception { - if (server != null) { - System.out.println("Stopping server " + server.getAddress()); - server.close(); - } - } - - /** - * Server sends a well-formed response - */ - @Test(dataProvider = "wellformedResponse") - public void testWellFormedResponse(String desc, byte[] response) throws Exception { - CompletableFuture errorCF = new CompletableFuture<>(); - server.addHandler((c,s)-> { + private static BooleanSupplier configureServerResponse(byte[] serverResponseBytes) { + var connectionTerminated = new AtomicBoolean(); + SERVER.addHandler((c, s)-> { try (OutputStream outputStream = s.outputStream()) { - outputStream.write(response); + outputStream.write(serverResponseBytes); } - // verify that the connection stays open - completeUponTermination(c, errorCF); + c.futureTerminationCause().handle((_, _) -> { + connectionTerminated.set(true); + return true; + }); }); - HttpClient client = getHttpClient(); - try { - HttpRequest request = getRequest(); - final HttpResponse response1 = client.send( - request, - BodyHandlers.discarding()); - assertEquals(response1.statusCode(), 200); - assertFalse(errorCF.isDone(), "Expected the connection to be open"); - } finally { - client.shutdownNow(); - } + return connectionTerminated::get; } - - /** - * Server sends a malformed response that should not close connection - */ - @Test(dataProvider = "malformedResponse") - public void testMalformedResponse(String desc, byte[] response) throws Exception { - CompletableFuture errorCF = new CompletableFuture<>(); - server.addHandler((c,s)-> { - try (OutputStream outputStream = s.outputStream()) { - outputStream.write(response); - } - // verify that the connection stays open - completeUponTermination(c, errorCF); - }); - HttpClient client = getHttpClient(); - try { - HttpRequest request = getRequest(); - final HttpResponse response1 = client.send( - request, - BodyHandlers.discarding()); - fail("Expected the request to fail, got " + response1); - } catch (Exception e) { - System.out.println("Got expected exception: " +e); - e.printStackTrace(); - assertFalse(errorCF.isDone(), "Expected the connection to be open"); - } finally { - client.shutdownNow(); - } - } - - /** - * Server sends a malformed response that might close connection - */ - @Test(dataProvider = "malformedResponse2") - public void testMalformedResponse2(String desc, byte[] response) throws Exception { - server.addHandler((c,s)-> { - try (OutputStream outputStream = s.outputStream()) { - outputStream.write(response); - } - }); - HttpClient client = getHttpClient(); - try { - HttpRequest request = getRequest(); - final HttpResponse response1 = client.send( - request, - BodyHandlers.discarding()); - fail("Expected the request to fail, got " + response1); - } catch (Exception e) { - System.out.println("Got expected exception: " +e); - e.printStackTrace(); - } finally { - client.shutdownNow(); - } - } - - private HttpRequest getRequest() throws URISyntaxException { - final URI reqURI = new URI(requestURIBase + "/hello"); - final HttpRequest.Builder reqBuilder = HttpRequest.newBuilder(reqURI) - .version(Version.HTTP_3) - .setOption(H3_DISCOVERY, HTTP_3_URI_ONLY); - return reqBuilder.build(); - } - - private HttpClient getHttpClient() { - final HttpClient client = newClientBuilderForH3() - .proxy(HttpClient.Builder.NO_PROXY) - .version(Version.HTTP_3) - .sslContext(sslContext).build(); - return client; - } - - private static String toHexString(final Http3Error error) { - return error.name() + "(0x" + Long.toHexString(error.code()) + ")"; - } - - private static void completeUponTermination(final QuicServerConnection serverConnection, - final CompletableFuture cf) { - serverConnection.futureTerminationCause().handle( - (r,t) -> t != null ? cf.completeExceptionally(t) : cf.complete(r)); - } } From 4e9525ef3619b02e905f16b89261b82c70830f3a Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Fri, 12 Dec 2025 18:57:25 +0000 Subject: [PATCH 277/706] 8373388: Reenable LTO for libsplashscreen Reviewed-by: erikj, dholmes, serb, prr --- make/modules/java.desktop/lib/ClientLibraries.gmk | 1 + 1 file changed, 1 insertion(+) diff --git a/make/modules/java.desktop/lib/ClientLibraries.gmk b/make/modules/java.desktop/lib/ClientLibraries.gmk index 499d5bef841..f273065a6df 100644 --- a/make/modules/java.desktop/lib/ClientLibraries.gmk +++ b/make/modules/java.desktop/lib/ClientLibraries.gmk @@ -226,6 +226,7 @@ ifeq ($(ENABLE_HEADLESS_ONLY), false) EXCLUDE_FILES := imageioJPEG.c jpegdecoder.c pngtest.c, \ EXCLUDES := $(LIBSPLASHSCREEN_EXCLUDES), \ OPTIMIZATION := SIZE, \ + LINK_TIME_OPTIMIZATION := true, \ CFLAGS := $(LIBSPLASHSCREEN_CFLAGS) \ $(GIFLIB_CFLAGS) $(LIBJPEG_CFLAGS) $(PNG_CFLAGS) $(LIBZ_CFLAGS) \ $(ICONV_CFLAGS), \ From f2e56e4c18080616e8ef275a3d9c1da824efda26 Mon Sep 17 00:00:00 2001 From: Vladimir Ivanov Date: Fri, 12 Dec 2025 21:12:09 +0000 Subject: [PATCH 278/706] 8372634: C2: Materialize type information from instanceof checks Reviewed-by: dlong, qamai, roland --- .../share/compiler/compilerDirectives.cpp | 14 + .../share/compiler/compilerDirectives.hpp | 1 + src/hotspot/share/compiler/compilerOracle.cpp | 4 + src/hotspot/share/compiler/compilerOracle.hpp | 4 + src/hotspot/share/compiler/methodMatcher.hpp | 1 + src/hotspot/share/opto/compile.hpp | 3 +- src/hotspot/share/opto/doCall.cpp | 2 +- src/hotspot/share/opto/parse2.cpp | 129 +++-- .../inlining/TestSubtypeCheckTypeInfo.java | 479 ++++++++++++++++++ .../klass/CastNullCheckDroppingsTest.java | 6 +- 10 files changed, 609 insertions(+), 34 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/inlining/TestSubtypeCheckTypeInfo.java diff --git a/src/hotspot/share/compiler/compilerDirectives.cpp b/src/hotspot/share/compiler/compilerDirectives.cpp index 5431b03f6a1..1cd8bd1b510 100644 --- a/src/hotspot/share/compiler/compilerDirectives.cpp +++ b/src/hotspot/share/compiler/compilerDirectives.cpp @@ -561,6 +561,20 @@ bool DirectiveSet::should_not_inline(ciMethod* inlinee) { return false; } +bool DirectiveSet::should_delay_inline(ciMethod* inlinee) { + inlinee->check_is_loaded(); + VM_ENTRY_MARK; + methodHandle mh(THREAD, inlinee->get_Method()); + + if (_inlinematchers != nullptr) { + return matches_inline(mh, InlineMatcher::delay_inline); + } + if (!CompilerDirectivesIgnoreCompileCommandsOption) { + return CompilerOracle::should_delay_inline(mh); + } + return false; +} + bool DirectiveSet::parse_and_add_inline(char* str, const char*& error_msg) { InlineMatcher* m = InlineMatcher::parse_inline_pattern(str, error_msg); if (m != nullptr) { diff --git a/src/hotspot/share/compiler/compilerDirectives.hpp b/src/hotspot/share/compiler/compilerDirectives.hpp index 27aafe06919..e4826b3056c 100644 --- a/src/hotspot/share/compiler/compilerDirectives.hpp +++ b/src/hotspot/share/compiler/compilerDirectives.hpp @@ -142,6 +142,7 @@ public: void append_inline(InlineMatcher* m); bool should_inline(ciMethod* inlinee); bool should_not_inline(ciMethod* inlinee); + bool should_delay_inline(ciMethod* inlinee); void print_inline(outputStream* st); DirectiveSet* compilecommand_compatibility_init(const methodHandle& method); bool is_exclusive_copy() { return _directive == nullptr; } diff --git a/src/hotspot/share/compiler/compilerOracle.cpp b/src/hotspot/share/compiler/compilerOracle.cpp index 23bb754f432..5bcd01a4d09 100644 --- a/src/hotspot/share/compiler/compilerOracle.cpp +++ b/src/hotspot/share/compiler/compilerOracle.cpp @@ -480,6 +480,10 @@ bool CompilerOracle::should_not_inline(const methodHandle& method) { return check_predicate(CompileCommandEnum::DontInline, method) || check_predicate(CompileCommandEnum::Exclude, method); } +bool CompilerOracle::should_delay_inline(const methodHandle& method) { + return (check_predicate(CompileCommandEnum::DelayInline, method)); +} + bool CompilerOracle::should_print(const methodHandle& method) { return check_predicate(CompileCommandEnum::Print, method); } diff --git a/src/hotspot/share/compiler/compilerOracle.hpp b/src/hotspot/share/compiler/compilerOracle.hpp index 09984705792..665f3b2fbfd 100644 --- a/src/hotspot/share/compiler/compilerOracle.hpp +++ b/src/hotspot/share/compiler/compilerOracle.hpp @@ -51,6 +51,7 @@ class methodHandle; option(Log, "log", Bool) \ option(Print, "print", Bool) \ option(Inline, "inline", Bool) \ + option(DelayInline, "delayinline", Bool) \ option(DontInline, "dontinline", Bool) \ option(Blackhole, "blackhole", Bool) \ option(CompileOnly, "compileonly", Bool)\ @@ -150,6 +151,9 @@ class CompilerOracle : AllStatic { // Tells whether we want to disallow inlining of this method static bool should_not_inline(const methodHandle& method); + // Tells whether we want to delay inlining of this method + static bool should_delay_inline(const methodHandle& method); + // Tells whether this method changes Thread.currentThread() static bool changes_current_thread(const methodHandle& method); diff --git a/src/hotspot/share/compiler/methodMatcher.hpp b/src/hotspot/share/compiler/methodMatcher.hpp index ba70747ad26..62945129e90 100644 --- a/src/hotspot/share/compiler/methodMatcher.hpp +++ b/src/hotspot/share/compiler/methodMatcher.hpp @@ -100,6 +100,7 @@ public: enum InlineType { unknown_inline, dont_inline, + delay_inline, force_inline }; diff --git a/src/hotspot/share/opto/compile.hpp b/src/hotspot/share/opto/compile.hpp index f5611062f2c..45a3a4f548f 100644 --- a/src/hotspot/share/opto/compile.hpp +++ b/src/hotspot/share/opto/compile.hpp @@ -984,7 +984,8 @@ public: JVMState* jvms, bool allow_inline, float profile_factor, ciKlass* speculative_receiver_type = nullptr, bool allow_intrinsics = true); bool should_delay_inlining(ciMethod* call_method, JVMState* jvms) { - return should_delay_string_inlining(call_method, jvms) || + return C->directive()->should_delay_inline(call_method) || + should_delay_string_inlining(call_method, jvms) || should_delay_boxing_inlining(call_method, jvms) || should_delay_vector_inlining(call_method, jvms); } diff --git a/src/hotspot/share/opto/doCall.cpp b/src/hotspot/share/opto/doCall.cpp index 5533b19897b..e4418631d17 100644 --- a/src/hotspot/share/opto/doCall.cpp +++ b/src/hotspot/share/opto/doCall.cpp @@ -192,7 +192,7 @@ CallGenerator* Compile::call_generator(ciMethod* callee, int vtable_index, bool // Try inlining a bytecoded method: if (!call_does_dispatch) { InlineTree* ilt = InlineTree::find_subtree_from_root(this->ilt(), jvms->caller(), jvms->method()); - bool should_delay = C->should_delay_inlining(); + bool should_delay = C->should_delay_inlining() || C->directive()->should_delay_inline(callee); if (ilt->ok_to_inline(callee, jvms, profile, should_delay)) { CallGenerator* cg = CallGenerator::for_inline(callee, expected_uses); // For optimized virtual calls assert at runtime that receiver object diff --git a/src/hotspot/share/opto/parse2.cpp b/src/hotspot/share/opto/parse2.cpp index cb8073144a5..eac2b3e863a 100644 --- a/src/hotspot/share/opto/parse2.cpp +++ b/src/hotspot/share/opto/parse2.cpp @@ -41,6 +41,7 @@ #include "opto/opaquenode.hpp" #include "opto/parse.hpp" #include "opto/runtime.hpp" +#include "opto/subtypenode.hpp" #include "runtime/deoptimization.hpp" #include "runtime/sharedRuntime.hpp" @@ -1719,38 +1720,108 @@ static Node* extract_obj_from_klass_load(PhaseGVN* gvn, Node* n) { return obj; } +// Matches exact and inexact type check IR shapes during parsing. +// On successful match, returns type checked object node and its type after successful check +// as out parameters. +static bool match_type_check(PhaseGVN& gvn, + BoolTest::mask btest, + Node* con, const Type* tcon, + Node* val, const Type* tval, + Node** obj, const TypeOopPtr** cast_type) { // out-parameters + // Look for opportunities to sharpen the type of a node whose klass is compared with a constant klass. + // The constant klass being tested against can come from many bytecode instructions (implicitly or explicitly), + // and also from profile data used by speculative casts. + if (btest == BoolTest::eq && tcon->isa_klassptr()) { + // Found: + // Bool(CmpP(LoadKlass(obj._klass), ConP(Foo.klass)), [eq]) + // or the narrowOop equivalent. + (*obj) = extract_obj_from_klass_load(&gvn, val); + (*cast_type) = tcon->isa_klassptr()->as_instance_type(); + return true; // found + } + + // Match an instanceof check. + // During parsing its IR shape is not canonicalized yet. + // + // obj superklass + // | | + // SubTypeCheck + // | + // Bool [eq] / [ne] + // | + // If + // / \ + // T F + // \ / + // Region + // \ ConI ConI + // \ | / + // val -> Phi ConI <- con + // \ / + // CmpI + // | + // Bool [btest] + // | + // + if (tval->isa_int() && val->is_Phi() && val->in(0)->as_Region()->is_diamond()) { + RegionNode* diamond = val->in(0)->as_Region(); + IfNode* if1 = diamond->in(1)->in(0)->as_If(); + BoolNode* b1 = if1->in(1)->isa_Bool(); + if (b1 != nullptr && b1->in(1)->isa_SubTypeCheck()) { + assert(b1->_test._test == BoolTest::eq || + b1->_test._test == BoolTest::ne, "%d", b1->_test._test); + + ProjNode* success_proj = if1->proj_out(b1->_test._test == BoolTest::eq ? 1 : 0); + int idx = diamond->find_edge(success_proj); + assert(idx == 1 || idx == 2, ""); + Node* vcon = val->in(idx); + + assert(val->find_edge(con) > 0, ""); + if ((btest == BoolTest::eq && vcon == con) || (btest == BoolTest::ne && vcon != con)) { + SubTypeCheckNode* sub = b1->in(1)->as_SubTypeCheck(); + Node* obj_or_subklass = sub->in(SubTypeCheckNode::ObjOrSubKlass); + Node* superklass = sub->in(SubTypeCheckNode::SuperKlass); + + if (gvn.type(obj_or_subklass)->isa_oopptr()) { + const TypeKlassPtr* klass_ptr_type = gvn.type(superklass)->is_klassptr(); + const TypeKlassPtr* improved_klass_ptr_type = klass_ptr_type->try_improve(); + + (*obj) = obj_or_subklass; + (*cast_type) = improved_klass_ptr_type->cast_to_exactness(false)->as_instance_type(); + return true; // found + } + } + } + } + return false; // not found +} + void Parse::sharpen_type_after_if(BoolTest::mask btest, Node* con, const Type* tcon, Node* val, const Type* tval) { - // Look for opportunities to sharpen the type of a node - // whose klass is compared with a constant klass. - if (btest == BoolTest::eq && tcon->isa_klassptr()) { - Node* obj = extract_obj_from_klass_load(&_gvn, val); - const TypeOopPtr* con_type = tcon->isa_klassptr()->as_instance_type(); - if (obj != nullptr && (con_type->isa_instptr() || con_type->isa_aryptr())) { - // Found: - // Bool(CmpP(LoadKlass(obj._klass), ConP(Foo.klass)), [eq]) - // or the narrowOop equivalent. - const Type* obj_type = _gvn.type(obj); - const TypeOopPtr* tboth = obj_type->join_speculative(con_type)->isa_oopptr(); - if (tboth != nullptr && tboth->klass_is_exact() && tboth != obj_type && - tboth->higher_equal(obj_type)) { - // obj has to be of the exact type Foo if the CmpP succeeds. - int obj_in_map = map()->find_edge(obj); - JVMState* jvms = this->jvms(); - if (obj_in_map >= 0 && - (jvms->is_loc(obj_in_map) || jvms->is_stk(obj_in_map))) { - TypeNode* ccast = new CheckCastPPNode(control(), obj, tboth); - const Type* tcc = ccast->as_Type()->type(); - assert(tcc != obj_type && tcc->higher_equal(obj_type), "must improve"); - // Delay transform() call to allow recovery of pre-cast value - // at the control merge. - _gvn.set_type_bottom(ccast); - record_for_igvn(ccast); - // Here's the payoff. - replace_in_map(obj, ccast); - } - } + Node* obj = nullptr; + const TypeOopPtr* cast_type = nullptr; + // Insert a cast node with a narrowed type after a successful type check. + if (match_type_check(_gvn, btest, con, tcon, val, tval, + &obj, &cast_type)) { + assert(obj != nullptr && cast_type != nullptr, "missing type check info"); + const Type* obj_type = _gvn.type(obj); + const TypeOopPtr* tboth = obj_type->join_speculative(cast_type)->isa_oopptr(); + if (tboth != nullptr && tboth != obj_type && tboth->higher_equal(obj_type)) { + int obj_in_map = map()->find_edge(obj); + JVMState* jvms = this->jvms(); + if (obj_in_map >= 0 && + (jvms->is_loc(obj_in_map) || jvms->is_stk(obj_in_map))) { + TypeNode* ccast = new CheckCastPPNode(control(), obj, tboth); + const Type* tcc = ccast->as_Type()->type(); + assert(tcc != obj_type && tcc->higher_equal(obj_type), "must improve"); + // Delay transform() call to allow recovery of pre-cast value + // at the control merge. + _gvn.set_type_bottom(ccast); + record_for_igvn(ccast); + // Here's the payoff. + replace_in_map(obj, ccast); + } } } diff --git a/test/hotspot/jtreg/compiler/inlining/TestSubtypeCheckTypeInfo.java b/test/hotspot/jtreg/compiler/inlining/TestSubtypeCheckTypeInfo.java new file mode 100644 index 00000000000..93767ca8416 --- /dev/null +++ b/test/hotspot/jtreg/compiler/inlining/TestSubtypeCheckTypeInfo.java @@ -0,0 +1,479 @@ +/* + * Copyright (c) 2025, 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 + * @summary 8372634 + * + * @requires vm.flagless + * @library /test/lib / + * + * @run driver compiler.inlining.TestSubtypeCheckTypeInfo + */ +package compiler.inlining; + +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.lang.reflect.Method; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class TestSubtypeCheckTypeInfo { + static final Class THIS_CLASS = TestSubtypeCheckTypeInfo.class; + static final String TEST_CLASS_NAME = THIS_CLASS.getName(); + + public static void main(String[] args) throws Exception { + ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( + "-XX:+IgnoreUnrecognizedVMOptions", "-showversion", + "-XX:-TieredCompilation", "-Xbatch", "-XX:CICompilerCount=1", + "-XX:+PrintCompilation", "-XX:+UnlockDiagnosticVMOptions", "-XX:+PrintInlining", + "-XX:CompileCommand=quiet", + "-XX:CompileCommand=compileonly," + TEST_CLASS_NAME + "::test*", + "-XX:CompileCommand=delayinline," + TEST_CLASS_NAME + "::lateInline*", + TestSubtypeCheckTypeInfo.Launcher.class.getName()); + + OutputAnalyzer analyzer = new OutputAnalyzer(pb.start()); + + analyzer.shouldHaveExitValue(0); + + // The test is applicable only to C2 (present in Server VM). + if (analyzer.getStderr().contains("Server VM")) { + List output = analyzer.asLinesWithoutVMWarnings(); + + parseOutput(output); + System.out.println("TEST PASSED"); + } + } + + static class Launcher { + public static void main(String[] args) { + runTestCase(TestSubtypeCheckTypeInfo::testInstanceOf); + runTestCase(TestSubtypeCheckTypeInfo::testInstanceOfCondPre); + runTestCase(TestSubtypeCheckTypeInfo::testInstanceOfCondPost); + + runTestCase(TestSubtypeCheckTypeInfo::testIsInstance); + runTestCase(TestSubtypeCheckTypeInfo::testIsInstanceCondPre); + runTestCase(TestSubtypeCheckTypeInfo::testIsInstanceCondPost); + + runTestCase(TestSubtypeCheckTypeInfo::testInstanceOfLate); + runTestCase(TestSubtypeCheckTypeInfo::testInstanceOfLateCondPre); + runTestCase(TestSubtypeCheckTypeInfo::testInstanceOfLateCondPost); + + runTestCase(TestSubtypeCheckTypeInfo::testIsInstanceLate); + runTestCase(TestSubtypeCheckTypeInfo::testIsInstanceLateCondPre); + runTestCase(TestSubtypeCheckTypeInfo::testIsInstanceLateCondPost); + + runTestCase(TestSubtypeCheckTypeInfo::testInstanceOfCondLate); + runTestCase(TestSubtypeCheckTypeInfo::testInstanceOfCondLatePre); + runTestCase(TestSubtypeCheckTypeInfo::testInstanceOfCondLatePost); + + runTestCase(TestSubtypeCheckTypeInfo::testIsInstanceCondLate); + runTestCase(TestSubtypeCheckTypeInfo::testIsInstanceCondLatePre); + runTestCase(TestSubtypeCheckTypeInfo::testIsInstanceCondLatePost); + + runTestCase(TestSubtypeCheckTypeInfo::testInstanceOfNulls); + runTestCase(TestSubtypeCheckTypeInfo::testIsInstanceNulls); + } + } + + /* =========================================================== */ + + @InlineSuccess + // @ 8 compiler.inlining.TestSubtypeCheckTypeInfo$B::m (1 bytes) inline (hot) + static void testInstanceOf(A o, boolean cond) { + if (o instanceof B) { + o.m(); + } + } + + @InlineSuccess + // @ 12 compiler.inlining.TestSubtypeCheckTypeInfo$B::m (1 bytes) inline (hot) + static void testInstanceOfCondPre(A o, boolean cond) { + if (cond && (o instanceof B)) { + o.m(); + } + } + + @InlineSuccess + // @ 12 compiler.inlining.TestSubtypeCheckTypeInfo$B::m (1 bytes) inline (hot) + static void testInstanceOfCondPost(A o, boolean cond) { + if ((o instanceof B) && cond) { + o.m(); + } + } + + /* =========================================================== */ + + @InlineSuccess + // Inlining _isInstance on constant Class compiler/inlining/TestSubtypeCheckTypeInfo$B + // @ 3 java.lang.Class::isInstance (0 bytes) (intrinsic) + // @ 10 compiler.inlining.TestSubtypeCheckTypeInfo$B::m (1 bytes) inline (hot) + static void testIsInstance(A o, boolean cond) { + if (B.class.isInstance(o)) { + o.m(); + } + } + + @InlineSuccess + // Inlining _isInstance on constant Class compiler/inlining/TestSubtypeCheckTypeInfo$B + // @ 7 java.lang.Class::isInstance (0 bytes) (intrinsic) + // @ 14 compiler.inlining.TestSubtypeCheckTypeInfo$B::m (1 bytes) inline (hot) + static void testIsInstanceCondPre(A o, boolean cond) { + if (cond && B.class.isInstance(o)) { + o.m(); + } + } + + @InlineSuccess + // @ 3 java.lang.Class::isInstance (0 bytes) (intrinsic) + // @ 14 compiler.inlining.TestSubtypeCheckTypeInfo$B::m (1 bytes) inline (hot) + static void testIsInstanceCondPost(A o, boolean cond) { + if (B.class.isInstance(o) && cond) { + o.m(); + } + } + + /* =========================================================== */ + + @InlineSuccess + // @ 5 compiler.inlining.TestSubtypeCheckTypeInfo::lateInline (9 bytes) inline (hot) late inline succeeded + // @ 5 compiler.inlining.TestSubtypeCheckTypeInfo$B::m (1 bytes) inline (hot) + static void testInstanceOfLate(A o, boolean cond) { + // if (o instanceof B) { o.m(); } + lateInline(o, o instanceof B); + } + + @InlineFailure + // @ 17 compiler.inlining.TestSubtypeCheckTypeInfo::lateInline (9 bytes) inline (hot) late inline succeeded + // @ 5 compiler.inlining.TestSubtypeCheckTypeInfo$A::m (0 bytes) failed to inline: virtual call + static void testInstanceOfLateCondPre(A o, boolean cond) { + // if (cond && o instanceof B) { o.m(); } + lateInline(o, cond && (o instanceof B)); + } + + @InlineFailure + // @ 17 compiler.inlining.TestSubtypeCheckTypeInfo::lateInline (9 bytes) inline (hot) late inline succeeded + // @ 5 compiler.inlining.TestSubtypeCheckTypeInfo$A::m (0 bytes) failed to inline: virtual call + static void testInstanceOfLateCondPost(A o, boolean cond) { + // if ((o instanceof B) && cond) { o.m(); } + lateInline(o, (o instanceof B) && cond); + } + + /* =========================================================== */ + + @InlineSuccess + // Inlining _isInstance on constant Class compiler/inlining/TestSubtypeCheckTypeInfo$B + // @ 4 java.lang.Class::isInstance (0 bytes) (intrinsic) + // @ 7 compiler.inlining.TestSubtypeCheckTypeInfo::lateInline (9 bytes) inline (hot) late inline succeeded + // @ 5 compiler.inlining.TestSubtypeCheckTypeInfo$B::m (1 bytes) inline (hot) + static void testIsInstanceLate(A o, boolean cond) { + // if (B.class.isInstance(o)) { o.m(); } + lateInline(o, B.class.isInstance(o)); + } + + @InlineFailure + // Inlining _isInstance on constant Class compiler/inlining/TestSubtypeCheckTypeInfo$B + // @ 8 java.lang.Class::isInstance (0 bytes) (intrinsic) + // @ 19 compiler.inlining.TestSubtypeCheckTypeInfo::lateInline (9 bytes) inline (hot) late inline succeeded + // @ 5 compiler.inlining.TestSubtypeCheckTypeInfo$A::m (0 bytes) failed to inline: virtual call + static void testIsInstanceLateCondPre(A o, boolean cond) { + // if (cond && B.class.isInstance(o)) { o.m(); } + lateInline(o, cond && (B.class.isInstance(o))); + } + + @InlineFailure + // Inlining _isInstance on constant Class compiler/inlining/TestSubtypeCheckTypeInfo$B + // @ 4 java.lang.Class::isInstance (0 bytes) (intrinsic) + // @ 19 compiler.inlining.TestSubtypeCheckTypeInfo::lateInline (9 bytes) inline (hot) late inline succeeded + // @ 5 compiler.inlining.TestSubtypeCheckTypeInfo$A::m (0 bytes) failed to inline: virtual call + static void testIsInstanceLateCondPost(A o, boolean cond) { + // if (B.class.isInstance(o) && cond) { o.m(); } + lateInline(o, (B.class.isInstance(o) && cond)); + } + + /* =========================================================== */ + + @InlineFailure + // @ 2 compiler.inlining.TestSubtypeCheckTypeInfo::lateInlineInstanceOfCondPre (17 bytes) inline (hot) late inline succeeded + // @ 9 compiler.inlining.TestSubtypeCheckTypeInfo$A::m (0 bytes) failed to inline: virtual call + static void testInstanceOfCondLate(A a, boolean cond) { + if (lateInlineInstanceOfCondPre(a, true)) { + a.m(); + } + } + + @InlineFailure + // @ 2 compiler.inlining.TestSubtypeCheckTypeInfo::lateInlineInstanceOfCondPre (17 bytes) inline (hot) late inline succeeded + // @ 9 compiler.inlining.TestSubtypeCheckTypeInfo$A::m (0 bytes) failed to inline: virtual call + static void testInstanceOfCondLatePre(A a, boolean cond) { + if (lateInlineInstanceOfCondPre(a, cond)) { + a.m(); + } + } + + @InlineFailure + // @ 2 compiler.inlining.TestSubtypeCheckTypeInfo::lateInlineInstanceOfCondPost (17 bytes) inline (hot) late inline succeeded + // @ 9 compiler.inlining.TestSubtypeCheckTypeInfo$A::m (0 bytes) failed to inline: virtual call + static void testInstanceOfCondLatePost(A a, boolean cond) { + if (lateInlineInstanceOfCondPost(a, cond)) { + a.m(); + } + } + + /* =========================================================== */ + + @InlineFailure + // Inlining _isInstance on constant Class compiler/inlining/TestSubtypeCheckTypeInfo$B + // @ 2 compiler.inlining.TestSubtypeCheckTypeInfo::lateInlineIsInstanceCondPre (19 bytes) inline (hot) late inline succeeded + // @ 7 java.lang.Class::isInstance (0 bytes) (intrinsic) + // @ 9 compiler.inlining.TestSubtypeCheckTypeInfo$A::m (0 bytes) failed to inline: virtual call + static void testIsInstanceCondLate(A a, boolean cond) { + if (lateInlineIsInstanceCondPre(a, true)) { + a.m(); + } + } + + @InlineFailure + // Inlining _isInstance on constant Class compiler/inlining/TestSubtypeCheckTypeInfo$B + // @ 2 compiler.inlining.TestSubtypeCheckTypeInfo::lateInlineIsInstanceCondPre (19 bytes) inline (hot) late inline succeeded + // @ 7 java.lang.Class::isInstance (0 bytes) (intrinsic) + // @ 9 compiler.inlining.TestSubtypeCheckTypeInfo$A::m (0 bytes) failed to inline: virtual call + static void testIsInstanceCondLatePre(A a, boolean cond) { + if (lateInlineIsInstanceCondPre(a, cond)) { + a.m(); + } + } + + @InlineFailure + // Inlining _isInstance on constant Class compiler/inlining/TestSubtypeCheckTypeInfo$B + // @ 2 compiler.inlining.TestSubtypeCheckTypeInfo::lateInlineIsInstanceCondPost (19 bytes) inline (hot) late inline succeeded + // @ 3 java.lang.Class::isInstance (0 bytes) (intrinsic) + // @ 9 compiler.inlining.TestSubtypeCheckTypeInfo$A::m (0 bytes) failed to inline: virtual call + static void testIsInstanceCondLatePost(A a, boolean cond) { + if (lateInlineIsInstanceCondPost(a, cond)) { + a.m(); + } + } + + /* =========================================================== */ + + @InlineFailure + // @ 20 compiler.inlining.TestSubtypeCheckTypeInfo$A::m (0 bytes) failed to inline: virtual call + static void testInstanceOfNulls(A o, boolean cond) { + A recv = (cond ? o : null); + if (recv instanceof B) { + o.m(); + } + } + + @InlineFailure + //Inlining _isInstance on constant Class compiler/inlining/TestSubtypeCheckTypeInfo$B + // @ 13 java.lang.Class::isInstance (0 bytes) (intrinsic) + // @ 20 compiler.inlining.TestSubtypeCheckTypeInfo$A::m (0 bytes) failed to inline: virtual call + static void testIsInstanceNulls(A o, boolean cond) { + A recv = (cond ? o : null); + if (B.class.isInstance(recv)) { + o.m(); + } + } + + /* =========================================================== */ + + static abstract class A { + public abstract void m(); + } + static abstract class B extends A { + public void m() {} + } + + static class C extends A { + public void m() {} + } + + static void lateInline(A o, boolean cond) { + if (cond) { + o.m(); + } + } + + static boolean lateInlineInstanceOfCondPre(A o, boolean cond) { + return cond && (o instanceof B); + } + + static boolean lateInlineInstanceOfCondPost(A o, boolean cond) { + return (o instanceof B) && cond; + } + + static boolean lateInlineIsInstanceCondPre(A o, boolean cond) { + return cond && B.class.isInstance(o); + } + static boolean lateInlineIsInstanceCondPost(A o, boolean cond) { + return B.class.isInstance(o) && cond; + } + + /* =========================================================== */ + + static final String INLINE_SUCCESS_MESSAGE = "B::m (1 bytes) inline (hot)"; + static final String INLINE_FAILURE_MESSAGE = "A::m (0 bytes) failed to inline: virtual call"; + + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.METHOD) + public @interface InlineSuccess { + String[] shouldContain() default INLINE_SUCCESS_MESSAGE; + String[] shouldNotContain() default INLINE_FAILURE_MESSAGE; + } + + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.METHOD) + public @interface InlineFailure { + String[] shouldContain() default INLINE_FAILURE_MESSAGE; + String[] shouldNotContain() default INLINE_SUCCESS_MESSAGE; + } + + /* =========================================================== */ + + // Parse compilation log (-XX:+PrintCompilation -XX:+PrintInlining output). + static void parseOutput(List output) { + Pattern compilation = Pattern.compile("^\\d+\\s+\\d+.*"); + StringBuilder inlineTree = new StringBuilder(); + Set passedTests = new HashSet(); + Set failedTests = new HashSet(); + for (String line : output) { + // Detect start of next compilation. + if (compilation.matcher(line).matches()) { + // Parse output for previous compilation. + validateInliningOutput(inlineTree.toString(), passedTests, failedTests); + inlineTree = new StringBuilder(); // reset + } + inlineTree.append(line); + } + // Process last compilation + validateInliningOutput(inlineTree.toString(), passedTests, failedTests); + + if (!failedTests.isEmpty()) { + String msg = String.format("TEST FAILED: %d test cases failed", failedTests.size()); + throw new AssertionError(msg); + } else if (passedTests.size() != totalTestCount()) { + String msg = String.format("TEST FAILED: %d out of %d test cases passed", passedTests.size(), totalTestCount()); + throw new AssertionError(msg); + } + } + + // Sample: + // 213 42 b compiler.inlining.TestSubtypeCheckTypeInfo::testIsInstanceCondLatePost (13 bytes) + static final Pattern TEST_CASE = Pattern.compile("^\\d+\\s+\\d+\\s+b\\s+" + TEST_CLASS_NAME + "::(\\w+) .*"); + + static boolean validateInliningOutput(String inlineTree, Set passedTests, Set failedTests) { + Matcher m = TEST_CASE.matcher(inlineTree); + if (m.matches()) { + String testName = m.group(1); + System.out.print(testName); + try { + Method testMethod = TestSubtypeCheckTypeInfo.class.getDeclaredMethod(testName, A.class, boolean.class); + if (validate(inlineTree, testMethod.getAnnotation(InlineSuccess.class)) && + validate(inlineTree, testMethod.getAnnotation(InlineFailure.class))) { + System.out.println(": SUCCESS"); + passedTests.add(testName); + return true; + } else { + failedTests.add(testName); + return false; + } + } catch (NoSuchMethodException e) { + System.out.println(": FAILURE: Missing test info for " + testName + ": " + inlineTree); + throw new InternalError(e); + } + } else { + return false; // not a test method; ignored + } + } + + static boolean validate(String message, InlineSuccess ann) { + if (ann != null) { + return validatePatterns(message, ann.shouldContain(), ann.shouldNotContain()); + } + return true; // no patterns to validate + } + + static boolean validate(String message, InlineFailure ann) { + if (ann != null) { + return validatePatterns(message, ann.shouldContain(), ann.shouldNotContain()); + } + return true; // no patterns to validate + } + + static boolean validatePatterns(String message, String[] shouldContain, String[] shouldNotContain) { + for (String pattern : shouldContain) { + if (!message.contains(pattern)) { + System.out.printf(": FAILURE: '%s' not found in '%s'\n", pattern, message); + return false; + } + } + for (String pattern : shouldNotContain) { + if (message.contains(pattern)) { + System.out.printf(": FAILURE: '%s' found in '%s'\n", pattern, message); + return false; + } + } + return true; + } + + static int totalTestCount() { + int count = 0; + for (Method m : THIS_CLASS.getDeclaredMethods()) { + if (m.isAnnotationPresent(InlineSuccess.class) || m.isAnnotationPresent(InlineFailure.class)) { + String testName = m.getName(); + if (testName.startsWith("test")) { + count++; + } else { + throw new InternalError("wrong test name: " + testName); + } + } + } + return count; + } + + /* =========================================================== */ + + interface TestCase { + void run(A o, boolean cond); + } + + static void runTestCase(TestCase t) { + A[] receivers = new A[] { new B() {}, new B() {}, new B() {}, new C() {}, new C() {}}; + for (int i = 0; i < 20_000; i++) { + // Pollute type profile and branch frequencies. + A recv = receivers[i % receivers.length]; + boolean cond = (i % 2 == 0); + t.run(recv, cond); + } + } +} diff --git a/test/hotspot/jtreg/compiler/intrinsics/klass/CastNullCheckDroppingsTest.java b/test/hotspot/jtreg/compiler/intrinsics/klass/CastNullCheckDroppingsTest.java index 2d2bf14d76f..17a4034350f 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/klass/CastNullCheckDroppingsTest.java +++ b/test/hotspot/jtreg/compiler/intrinsics/klass/CastNullCheckDroppingsTest.java @@ -132,13 +132,13 @@ public class CastNullCheckDroppingsTest { t.runTest(methodClassCastNull, false, svalue); t.runTest(methodNullClassCast, false, svalue); t.runTest(methodClassCastObj, false, svalue); - t.runTest(methodObjClassCast, false, svalue); + t.runTest(methodObjClassCast, false, svalue); t.runTest(methodClassCastInt, false, svalue); - t.runTest(methodIntClassCast, true, svalue); + t.runTest(methodIntClassCast, false, svalue); t.runTest(methodClassCastint, false, svalue); t.runTest(methodintClassCast, false, svalue); t.runTest(methodClassCastPrim, false, svalue); - t.runTest(methodPrimClassCast, true, svalue); + t.runTest(methodPrimClassCast, false, svalue); t.runTest(methodVarClassCast, true, objClass); } From 23c39757ecdc834c631f98f4487cfea21c9b948b Mon Sep 17 00:00:00 2001 From: Man Cao Date: Fri, 12 Dec 2025 21:19:09 +0000 Subject: [PATCH 279/706] 8373403: [TESTBUG] TestG1ClassUnloadingHWM.java could fail with large G1HeapRegionSize and small InitialHeapSize Reviewed-by: tschatzl, iwalulya --- .../class_unloading/TestG1ClassUnloadingHWM.java | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/test/hotspot/jtreg/gc/class_unloading/TestG1ClassUnloadingHWM.java b/test/hotspot/jtreg/gc/class_unloading/TestG1ClassUnloadingHWM.java index 59289f10c37..7faae885f70 100644 --- a/test/hotspot/jtreg/gc/class_unloading/TestG1ClassUnloadingHWM.java +++ b/test/hotspot/jtreg/gc/class_unloading/TestG1ClassUnloadingHWM.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, 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 @@ -68,19 +68,21 @@ public class TestG1ClassUnloadingHWM { } public static void testWithoutG1ClassUnloading() throws Exception { - // -XX:-ClassUnloadingWithConcurrentMark is used, so we expect a full GC instead of a concurrent cycle. + // -XX:-ClassUnloadingWithConcurrentMark is used, so we expect a full GC due to Metadata GC Threshold + // instead of a concurrent cycle. OutputAnalyzer out = runWithoutG1ClassUnloading(); - out.shouldMatch(".*Pause Full.*"); - out.shouldNotMatch(".*Pause Young \\(Concurrent Start\\).*"); + out.shouldMatch(".*Pause Full \\(Metadata GC Threshold\\).*"); + out.shouldNotMatch(".*Pause Young \\(Concurrent Start\\) \\(Metadata GC Threshold\\).*"); } public static void testWithG1ClassUnloading() throws Exception { - // -XX:+ClassUnloadingWithConcurrentMark is used, so we expect a concurrent cycle instead of a full GC. + // -XX:+ClassUnloadingWithConcurrentMark is used, so we expect a concurrent cycle due to Metadata GC Threshold + // instead of a full GC. OutputAnalyzer out = runWithG1ClassUnloading(); - out.shouldMatch(".*Pause Young \\(Concurrent Start\\).*"); - out.shouldNotMatch(".*Pause Full.*"); + out.shouldMatch(".*Pause Young \\(Concurrent Start\\) \\(Metadata GC Threshold\\).*"); + out.shouldNotMatch(".*Pause Full \\(Metadata GC Threshold\\).*"); } public static void main(String args[]) throws Exception { From d05486520036a4a6b3e3eee46a18f5b0e1ef493e Mon Sep 17 00:00:00 2001 From: Sergey Bylokhov Date: Sat, 13 Dec 2025 01:35:24 +0000 Subject: [PATCH 280/706] 8371975: Apply java.io.Serial annotations in java.security.sasl Reviewed-by: mullan --- .../share/classes/com/sun/security/sasl/Provider.java | 4 +++- .../classes/javax/security/sasl/AuthenticationException.java | 5 ++++- .../share/classes/javax/security/sasl/AuthorizeCallback.java | 5 ++++- .../share/classes/javax/security/sasl/RealmCallback.java | 5 ++++- .../classes/javax/security/sasl/RealmChoiceCallback.java | 5 ++++- .../share/classes/javax/security/sasl/SaslException.java | 4 +++- 6 files changed, 22 insertions(+), 6 deletions(-) diff --git a/src/java.security.sasl/share/classes/com/sun/security/sasl/Provider.java b/src/java.security.sasl/share/classes/com/sun/security/sasl/Provider.java index c3d4cdcc54b..6a6c1bb3ce3 100644 --- a/src/java.security.sasl/share/classes/com/sun/security/sasl/Provider.java +++ b/src/java.security.sasl/share/classes/com/sun/security/sasl/Provider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, 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,7 @@ */ package com.sun.security.sasl; +import java.io.Serial; import java.security.NoSuchAlgorithmException; import java.security.InvalidParameterException; import java.security.ProviderException; @@ -45,6 +46,7 @@ import static sun.security.util.SecurityConstants.PROVIDER_VER; public final class Provider extends java.security.Provider { + @Serial private static final long serialVersionUID = 8622598936488630849L; private static final String info = "Sun SASL provider" + diff --git a/src/java.security.sasl/share/classes/javax/security/sasl/AuthenticationException.java b/src/java.security.sasl/share/classes/javax/security/sasl/AuthenticationException.java index b61981bc16f..c9c3a274c44 100644 --- a/src/java.security.sasl/share/classes/javax/security/sasl/AuthenticationException.java +++ b/src/java.security.sasl/share/classes/javax/security/sasl/AuthenticationException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, 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 javax.security.sasl; +import java.io.Serial; + /** * This exception is thrown by a SASL mechanism implementation * to indicate that the SASL @@ -79,5 +81,6 @@ public class AuthenticationException extends SaslException { } /** Use serialVersionUID from JSR 28 RI for interoperability */ + @Serial private static final long serialVersionUID = -3579708765071815007L; } diff --git a/src/java.security.sasl/share/classes/javax/security/sasl/AuthorizeCallback.java b/src/java.security.sasl/share/classes/javax/security/sasl/AuthorizeCallback.java index e0f323d36c9..a254159229b 100644 --- a/src/java.security.sasl/share/classes/javax/security/sasl/AuthorizeCallback.java +++ b/src/java.security.sasl/share/classes/javax/security/sasl/AuthorizeCallback.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, 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 javax.security.sasl; +import java.io.Serial; + import javax.security.auth.callback.Callback; /** @@ -141,5 +143,6 @@ public class AuthorizeCallback implements Callback, java.io.Serializable { authorizedID = id; } + @Serial private static final long serialVersionUID = -2353344186490470805L; } diff --git a/src/java.security.sasl/share/classes/javax/security/sasl/RealmCallback.java b/src/java.security.sasl/share/classes/javax/security/sasl/RealmCallback.java index af14158aa77..4d87b4da9d9 100644 --- a/src/java.security.sasl/share/classes/javax/security/sasl/RealmCallback.java +++ b/src/java.security.sasl/share/classes/javax/security/sasl/RealmCallback.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, 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 javax.security.sasl; +import java.io.Serial; + import javax.security.auth.callback.TextInputCallback; /** @@ -63,5 +65,6 @@ public class RealmCallback extends TextInputCallback { super(prompt, defaultRealmInfo); } + @Serial private static final long serialVersionUID = -4342673378785456908L; } diff --git a/src/java.security.sasl/share/classes/javax/security/sasl/RealmChoiceCallback.java b/src/java.security.sasl/share/classes/javax/security/sasl/RealmChoiceCallback.java index 61d9c0edd35..6a782268fb6 100644 --- a/src/java.security.sasl/share/classes/javax/security/sasl/RealmChoiceCallback.java +++ b/src/java.security.sasl/share/classes/javax/security/sasl/RealmChoiceCallback.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, 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 javax.security.sasl; +import java.io.Serial; + import javax.security.auth.callback.ChoiceCallback; /** @@ -58,5 +60,6 @@ public class RealmChoiceCallback extends ChoiceCallback { super(prompt, choices, defaultChoice, multiple); } + @Serial private static final long serialVersionUID = -8588141348846281332L; } diff --git a/src/java.security.sasl/share/classes/javax/security/sasl/SaslException.java b/src/java.security.sasl/share/classes/javax/security/sasl/SaslException.java index 0398d8d7277..4d07eb18d36 100644 --- a/src/java.security.sasl/share/classes/javax/security/sasl/SaslException.java +++ b/src/java.security.sasl/share/classes/javax/security/sasl/SaslException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2025, 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 @@ package javax.security.sasl; import java.io.IOException; +import java.io.Serial; /** * This class represents an error that has occurred when using SASL. @@ -125,5 +126,6 @@ public class SaslException extends IOException { } /** Use serialVersionUID from JSR 28 RI for interoperability */ + @Serial private static final long serialVersionUID = 4579784287983423626L; } From 17744fbfc004dfed5a3e959cd9ac7e7081b5be7a Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sat, 13 Dec 2025 02:53:57 +0000 Subject: [PATCH 281/706] 8373628: jpackage doesn't print to console until completetion Reviewed-by: almatvee --- .../jdk/jpackage/internal/cli/Main.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/Main.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/Main.java index f377b22374d..af51bc9fd98 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/Main.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/Main.java @@ -31,6 +31,7 @@ import static jdk.jpackage.internal.cli.StandardOption.VERSION; import java.io.FileNotFoundException; import java.io.IOException; +import java.io.PrintStream; import java.io.PrintWriter; import java.io.UncheckedIOException; import java.nio.file.NoSuchFileException; @@ -65,6 +66,21 @@ public final class Main { public int run(PrintWriter out, PrintWriter err, String... args) { return Main.run(out, err, args); } + + @Override + public int run(PrintStream out, PrintStream err, String... args) { + PrintWriter outWriter = new PrintWriter(out, true); + PrintWriter errWriter = new PrintWriter(err, true); + try { + try { + return run(outWriter, errWriter, args); + } finally { + outWriter.flush(); + } + } finally { + errWriter.flush(); + } + } } @@ -78,6 +94,10 @@ public final class Main { } public static int run(PrintWriter out, PrintWriter err, String... args) { + Objects.requireNonNull(args); + for (String arg : args) { + Objects.requireNonNull(arg); + } Objects.requireNonNull(out); Objects.requireNonNull(err); From 4f1dcf89b841e9a37d342bdf8c66bbbab9edb0d4 Mon Sep 17 00:00:00 2001 From: Mohamed Issa Date: Sat, 13 Dec 2025 03:16:46 +0000 Subject: [PATCH 282/706] 8368977: Provide clear naming for AVX10 identifiers Reviewed-by: jbhateja, mhaessig, vlivanov --- src/hotspot/cpu/x86/assembler_x86.hpp | 4 +- src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp | 12 +-- src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp | 8 +- src/hotspot/cpu/x86/macroAssembler_x86.cpp | 16 ++-- src/hotspot/cpu/x86/x86.ad | 86 +++++++++---------- .../floatingpoint/ScalarFPtoIntCastTest.java | 16 ++-- .../compiler/lib/ir_framework/IRNode.java | 24 +++--- .../vectorapi/VectorFPtoIntCastTest.java | 16 ++-- .../runner/ArrayTypeConvertTest.java | 16 ++-- 9 files changed, 99 insertions(+), 99 deletions(-) diff --git a/src/hotspot/cpu/x86/assembler_x86.hpp b/src/hotspot/cpu/x86/assembler_x86.hpp index 43471a88391..26c57fc2d80 100644 --- a/src/hotspot/cpu/x86/assembler_x86.hpp +++ b/src/hotspot/cpu/x86/assembler_x86.hpp @@ -449,8 +449,8 @@ const int FPUStateSizeInWords = 2688 / wordSize; // imm8[1:0] = 00 (min) / 01 (max) // // [1] https://www.intel.com/content/www/us/en/content-details/856721/intel-advanced-vector-extensions-10-2-intel-avx10-2-architecture-specification.html?wapkw=AVX10 -const int AVX10_MINMAX_MAX_COMPARE_SIGN = 0x5; -const int AVX10_MINMAX_MIN_COMPARE_SIGN = 0x4; +const int AVX10_2_MINMAX_MAX_COMPARE_SIGN = 0x5; +const int AVX10_2_MINMAX_MIN_COMPARE_SIGN = 0x4; // The Intel x86/Amd64 Assembler: Pure assembler doing NO optimizations on the instruction // level (e.g. mov rax, 0 is not translated into xor rax, rax!); i.e., what you write diff --git a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp index 3de7f473fea..e1a64cb5c2e 100644 --- a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp @@ -1033,8 +1033,8 @@ void C2_MacroAssembler::vminmax_fp(int opc, BasicType elem_bt, XMMRegister dst, assert(opc == Op_MinV || opc == Op_MinReductionV || opc == Op_MaxV || opc == Op_MaxReductionV, "sanity"); - int imm8 = (opc == Op_MinV || opc == Op_MinReductionV) ? AVX10_MINMAX_MIN_COMPARE_SIGN - : AVX10_MINMAX_MAX_COMPARE_SIGN; + int imm8 = (opc == Op_MinV || opc == Op_MinReductionV) ? AVX10_2_MINMAX_MIN_COMPARE_SIGN + : AVX10_2_MINMAX_MAX_COMPARE_SIGN; if (elem_bt == T_FLOAT) { evminmaxps(dst, mask, src1, src2, true, imm8, vlen_enc); } else { @@ -5163,7 +5163,7 @@ void C2_MacroAssembler::vector_castD2X_evex(BasicType to_elem_bt, XMMRegister ds } } -void C2_MacroAssembler::vector_castF2X_avx10(BasicType to_elem_bt, XMMRegister dst, XMMRegister src, int vec_enc) { +void C2_MacroAssembler::vector_castF2X_avx10_2(BasicType to_elem_bt, XMMRegister dst, XMMRegister src, int vec_enc) { switch(to_elem_bt) { case T_LONG: evcvttps2qqs(dst, src, vec_enc); @@ -5183,7 +5183,7 @@ void C2_MacroAssembler::vector_castF2X_avx10(BasicType to_elem_bt, XMMRegister d } } -void C2_MacroAssembler::vector_castF2X_avx10(BasicType to_elem_bt, XMMRegister dst, Address src, int vec_enc) { +void C2_MacroAssembler::vector_castF2X_avx10_2(BasicType to_elem_bt, XMMRegister dst, Address src, int vec_enc) { switch(to_elem_bt) { case T_LONG: evcvttps2qqs(dst, src, vec_enc); @@ -5203,7 +5203,7 @@ void C2_MacroAssembler::vector_castF2X_avx10(BasicType to_elem_bt, XMMRegister d } } -void C2_MacroAssembler::vector_castD2X_avx10(BasicType to_elem_bt, XMMRegister dst, XMMRegister src, int vec_enc) { +void C2_MacroAssembler::vector_castD2X_avx10_2(BasicType to_elem_bt, XMMRegister dst, XMMRegister src, int vec_enc) { switch(to_elem_bt) { case T_LONG: evcvttpd2qqs(dst, src, vec_enc); @@ -5223,7 +5223,7 @@ void C2_MacroAssembler::vector_castD2X_avx10(BasicType to_elem_bt, XMMRegister d } } -void C2_MacroAssembler::vector_castD2X_avx10(BasicType to_elem_bt, XMMRegister dst, Address src, int vec_enc) { +void C2_MacroAssembler::vector_castD2X_avx10_2(BasicType to_elem_bt, XMMRegister dst, Address src, int vec_enc) { switch(to_elem_bt) { case T_LONG: evcvttpd2qqs(dst, src, vec_enc); diff --git a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp index cd5f0ceb900..6d8b0ceaebe 100644 --- a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp @@ -347,13 +347,13 @@ public: XMMRegister xtmp2, XMMRegister xtmp3, XMMRegister xtmp4, XMMRegister xtmp5, AddressLiteral float_sign_flip, Register rscratch, int vec_enc); - void vector_castF2X_avx10(BasicType to_elem_bt, XMMRegister dst, XMMRegister src, int vec_enc); + void vector_castF2X_avx10_2(BasicType to_elem_bt, XMMRegister dst, XMMRegister src, int vec_enc); - void vector_castF2X_avx10(BasicType to_elem_bt, XMMRegister dst, Address src, int vec_enc); + void vector_castF2X_avx10_2(BasicType to_elem_bt, XMMRegister dst, Address src, int vec_enc); - void vector_castD2X_avx10(BasicType to_elem_bt, XMMRegister dst, XMMRegister src, int vec_enc); + void vector_castD2X_avx10_2(BasicType to_elem_bt, XMMRegister dst, XMMRegister src, int vec_enc); - void vector_castD2X_avx10(BasicType to_elem_bt, XMMRegister dst, Address src, int vec_enc); + void vector_castD2X_avx10_2(BasicType to_elem_bt, XMMRegister dst, Address src, int vec_enc); void vector_cast_double_to_int_special_cases_avx(XMMRegister dst, XMMRegister src, XMMRegister xtmp1, XMMRegister xtmp2, XMMRegister xtmp3, XMMRegister xtmp4, XMMRegister xtmp5, Register rscratch, diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.cpp b/src/hotspot/cpu/x86/macroAssembler_x86.cpp index 44f1a35d443..48928b0db3f 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp @@ -8899,9 +8899,9 @@ void MacroAssembler::evpmins(BasicType type, XMMRegister dst, KRegister mask, XM case T_LONG: evpminsq(dst, mask, nds, src, merge, vector_len); break; case T_FLOAT: - evminmaxps(dst, mask, nds, src, merge, AVX10_MINMAX_MIN_COMPARE_SIGN, vector_len); break; + evminmaxps(dst, mask, nds, src, merge, AVX10_2_MINMAX_MIN_COMPARE_SIGN, vector_len); break; case T_DOUBLE: - evminmaxpd(dst, mask, nds, src, merge, AVX10_MINMAX_MIN_COMPARE_SIGN, vector_len); break; + evminmaxpd(dst, mask, nds, src, merge, AVX10_2_MINMAX_MIN_COMPARE_SIGN, vector_len); break; default: fatal("Unexpected type argument %s", type2name(type)); break; } @@ -8918,9 +8918,9 @@ void MacroAssembler::evpmaxs(BasicType type, XMMRegister dst, KRegister mask, XM case T_LONG: evpmaxsq(dst, mask, nds, src, merge, vector_len); break; case T_FLOAT: - evminmaxps(dst, mask, nds, src, merge, AVX10_MINMAX_MAX_COMPARE_SIGN, vector_len); break; + evminmaxps(dst, mask, nds, src, merge, AVX10_2_MINMAX_MAX_COMPARE_SIGN, vector_len); break; case T_DOUBLE: - evminmaxpd(dst, mask, nds, src, merge, AVX10_MINMAX_MAX_COMPARE_SIGN, vector_len); break; + evminmaxpd(dst, mask, nds, src, merge, AVX10_2_MINMAX_MAX_COMPARE_SIGN, vector_len); break; default: fatal("Unexpected type argument %s", type2name(type)); break; } @@ -8937,9 +8937,9 @@ void MacroAssembler::evpmins(BasicType type, XMMRegister dst, KRegister mask, XM case T_LONG: evpminsq(dst, mask, nds, src, merge, vector_len); break; case T_FLOAT: - evminmaxps(dst, mask, nds, src, merge, AVX10_MINMAX_MIN_COMPARE_SIGN, vector_len); break; + evminmaxps(dst, mask, nds, src, merge, AVX10_2_MINMAX_MIN_COMPARE_SIGN, vector_len); break; case T_DOUBLE: - evminmaxpd(dst, mask, nds, src, merge, AVX10_MINMAX_MIN_COMPARE_SIGN, vector_len); break; + evminmaxpd(dst, mask, nds, src, merge, AVX10_2_MINMAX_MIN_COMPARE_SIGN, vector_len); break; default: fatal("Unexpected type argument %s", type2name(type)); break; } @@ -8956,9 +8956,9 @@ void MacroAssembler::evpmaxs(BasicType type, XMMRegister dst, KRegister mask, XM case T_LONG: evpmaxsq(dst, mask, nds, src, merge, vector_len); break; case T_FLOAT: - evminmaxps(dst, mask, nds, src, merge, AVX10_MINMAX_MAX_COMPARE_SIGN, vector_len); break; + evminmaxps(dst, mask, nds, src, merge, AVX10_2_MINMAX_MAX_COMPARE_SIGN, vector_len); break; case T_DOUBLE: - evminmaxps(dst, mask, nds, src, merge, AVX10_MINMAX_MAX_COMPARE_SIGN, vector_len); break; + evminmaxps(dst, mask, nds, src, merge, AVX10_2_MINMAX_MAX_COMPARE_SIGN, vector_len); break; default: fatal("Unexpected type argument %s", type2name(type)); break; } diff --git a/src/hotspot/cpu/x86/x86.ad b/src/hotspot/cpu/x86/x86.ad index 42d2e815e45..5958db5d1eb 100644 --- a/src/hotspot/cpu/x86/x86.ad +++ b/src/hotspot/cpu/x86/x86.ad @@ -7289,12 +7289,12 @@ instruct loadD(regD dst, memory mem) %} // max = java.lang.Math.max(float a, float b) -instruct maxF_avx10_reg(regF dst, regF a, regF b) %{ +instruct maxF_reg_avx10_2(regF dst, regF a, regF b) %{ predicate(VM_Version::supports_avx10_2()); match(Set dst (MaxF a b)); format %{ "maxF $dst, $a, $b" %} ins_encode %{ - __ eminmaxss($dst$$XMMRegister, $a$$XMMRegister, $b$$XMMRegister, AVX10_MINMAX_MAX_COMPARE_SIGN); + __ eminmaxss($dst$$XMMRegister, $a$$XMMRegister, $b$$XMMRegister, AVX10_2_MINMAX_MAX_COMPARE_SIGN); %} ins_pipe( pipe_slow ); %} @@ -7325,12 +7325,12 @@ instruct maxF_reduction_reg(legRegF dst, legRegF a, legRegF b, legRegF xtmp, rRe %} // max = java.lang.Math.max(double a, double b) -instruct maxD_avx10_reg(regD dst, regD a, regD b) %{ +instruct maxD_reg_avx10_2(regD dst, regD a, regD b) %{ predicate(VM_Version::supports_avx10_2()); match(Set dst (MaxD a b)); format %{ "maxD $dst, $a, $b" %} ins_encode %{ - __ eminmaxsd($dst$$XMMRegister, $a$$XMMRegister, $b$$XMMRegister, AVX10_MINMAX_MAX_COMPARE_SIGN); + __ eminmaxsd($dst$$XMMRegister, $a$$XMMRegister, $b$$XMMRegister, AVX10_2_MINMAX_MAX_COMPARE_SIGN); %} ins_pipe( pipe_slow ); %} @@ -7361,12 +7361,12 @@ instruct maxD_reduction_reg(legRegD dst, legRegD a, legRegD b, legRegD xtmp, rRe %} // max = java.lang.Math.min(float a, float b) -instruct minF_avx10_reg(regF dst, regF a, regF b) %{ +instruct minF_reg_avx10_2(regF dst, regF a, regF b) %{ predicate(VM_Version::supports_avx10_2()); match(Set dst (MinF a b)); format %{ "minF $dst, $a, $b" %} ins_encode %{ - __ eminmaxss($dst$$XMMRegister, $a$$XMMRegister, $b$$XMMRegister, AVX10_MINMAX_MIN_COMPARE_SIGN); + __ eminmaxss($dst$$XMMRegister, $a$$XMMRegister, $b$$XMMRegister, AVX10_2_MINMAX_MIN_COMPARE_SIGN); %} ins_pipe( pipe_slow ); %} @@ -7397,12 +7397,12 @@ instruct minF_reduction_reg(legRegF dst, legRegF a, legRegF b, legRegF xtmp, rRe %} // max = java.lang.Math.min(double a, double b) -instruct minD_avx10_reg(regD dst, regD a, regD b) %{ +instruct minD_reg_avx10_2(regD dst, regD a, regD b) %{ predicate(VM_Version::supports_avx10_2()); match(Set dst (MinD a b)); format %{ "minD $dst, $a, $b" %} ins_encode %{ - __ eminmaxsd($dst$$XMMRegister, $a$$XMMRegister, $b$$XMMRegister, AVX10_MINMAX_MIN_COMPARE_SIGN); + __ eminmaxsd($dst$$XMMRegister, $a$$XMMRegister, $b$$XMMRegister, AVX10_2_MINMAX_MIN_COMPARE_SIGN); %} ins_pipe( pipe_slow ); %} @@ -14586,7 +14586,7 @@ instruct convF2I_reg_reg(rRegI dst, regF src, rFlagsReg cr) ins_pipe(pipe_slow); %} -instruct convF2I_reg_reg_avx10(rRegI dst, regF src) +instruct convF2I_reg_reg_avx10_2(rRegI dst, regF src) %{ predicate(VM_Version::supports_avx10_2()); match(Set dst (ConvF2I src)); @@ -14597,7 +14597,7 @@ instruct convF2I_reg_reg_avx10(rRegI dst, regF src) ins_pipe(pipe_slow); %} -instruct convF2I_reg_mem_avx10(rRegI dst, memory src) +instruct convF2I_reg_mem_avx10_2(rRegI dst, memory src) %{ predicate(VM_Version::supports_avx10_2()); match(Set dst (ConvF2I (LoadF src))); @@ -14620,7 +14620,7 @@ instruct convF2L_reg_reg(rRegL dst, regF src, rFlagsReg cr) ins_pipe(pipe_slow); %} -instruct convF2L_reg_reg_avx10(rRegL dst, regF src) +instruct convF2L_reg_reg_avx10_2(rRegL dst, regF src) %{ predicate(VM_Version::supports_avx10_2()); match(Set dst (ConvF2L src)); @@ -14631,7 +14631,7 @@ instruct convF2L_reg_reg_avx10(rRegL dst, regF src) ins_pipe(pipe_slow); %} -instruct convF2L_reg_mem_avx10(rRegL dst, memory src) +instruct convF2L_reg_mem_avx10_2(rRegL dst, memory src) %{ predicate(VM_Version::supports_avx10_2()); match(Set dst (ConvF2L (LoadF src))); @@ -14654,7 +14654,7 @@ instruct convD2I_reg_reg(rRegI dst, regD src, rFlagsReg cr) ins_pipe(pipe_slow); %} -instruct convD2I_reg_reg_avx10(rRegI dst, regD src) +instruct convD2I_reg_reg_avx10_2(rRegI dst, regD src) %{ predicate(VM_Version::supports_avx10_2()); match(Set dst (ConvD2I src)); @@ -14665,7 +14665,7 @@ instruct convD2I_reg_reg_avx10(rRegI dst, regD src) ins_pipe(pipe_slow); %} -instruct convD2I_reg_mem_avx10(rRegI dst, memory src) +instruct convD2I_reg_mem_avx10_2(rRegI dst, memory src) %{ predicate(VM_Version::supports_avx10_2()); match(Set dst (ConvD2I (LoadD src))); @@ -14688,7 +14688,7 @@ instruct convD2L_reg_reg(rRegL dst, regD src, rFlagsReg cr) ins_pipe(pipe_slow); %} -instruct convD2L_reg_reg_avx10(rRegL dst, regD src) +instruct convD2L_reg_reg_avx10_2(rRegL dst, regD src) %{ predicate(VM_Version::supports_avx10_2()); match(Set dst (ConvD2L src)); @@ -14699,7 +14699,7 @@ instruct convD2L_reg_reg_avx10(rRegL dst, regD src) ins_pipe(pipe_slow); %} -instruct convD2L_reg_mem_avx10(rRegL dst, memory src) +instruct convD2L_reg_mem_avx10_2(rRegL dst, memory src) %{ predicate(VM_Version::supports_avx10_2()); match(Set dst (ConvD2L (LoadD src))); @@ -19660,7 +19660,7 @@ instruct minmax_reductionF_av(legRegF dst, legVec src, legVec tmp, legVec atmp, ins_pipe( pipe_slow ); %} -instruct minmax_reduction2F_avx10(regF dst, immF src1, vec src2, vec xtmp1) %{ +instruct minmax_reduction2F_avx10_2(regF dst, immF src1, vec src2, vec xtmp1) %{ predicate(VM_Version::supports_avx10_2() && Matcher::vector_element_basic_type(n->in(2)) == T_FLOAT && ((n->Opcode() == Op_MinReductionV && n->in(1)->bottom_type() == TypeF::POS_INF) || (n->Opcode() == Op_MaxReductionV && n->in(1)->bottom_type() == TypeF::NEG_INF)) && @@ -19678,7 +19678,7 @@ instruct minmax_reduction2F_avx10(regF dst, immF src1, vec src2, vec xtmp1) %{ ins_pipe( pipe_slow ); %} -instruct minmax_reductionF_avx10(regF dst, immF src1, vec src2, vec xtmp1, vec xtmp2) %{ +instruct minmax_reductionF_avx10_2(regF dst, immF src1, vec src2, vec xtmp1, vec xtmp2) %{ predicate(VM_Version::supports_avx10_2() && Matcher::vector_element_basic_type(n->in(2)) == T_FLOAT && ((n->Opcode() == Op_MinReductionV && n->in(1)->bottom_type() == TypeF::POS_INF) || (n->Opcode() == Op_MaxReductionV && n->in(1)->bottom_type() == TypeF::NEG_INF)) && @@ -19696,7 +19696,7 @@ instruct minmax_reductionF_avx10(regF dst, immF src1, vec src2, vec xtmp1, vec x ins_pipe( pipe_slow ); %} -instruct minmax_reduction2F_avx10_av(regF dst, vec src, vec xtmp1) %{ +instruct minmax_reduction2F_av_avx10_2(regF dst, vec src, vec xtmp1) %{ predicate(VM_Version::supports_avx10_2() && Matcher::vector_element_basic_type(n->in(2)) == T_FLOAT && Matcher::vector_length(n->in(2)) == 2); match(Set dst (MinReductionV dst src)); @@ -19712,7 +19712,7 @@ instruct minmax_reduction2F_avx10_av(regF dst, vec src, vec xtmp1) %{ ins_pipe( pipe_slow ); %} -instruct minmax_reductionF_avx10_av(regF dst, vec src, vec xtmp1, vec xtmp2) %{ +instruct minmax_reductionF_av_avx10_2(regF dst, vec src, vec xtmp1, vec xtmp2) %{ predicate(VM_Version::supports_avx10_2() && Matcher::vector_element_basic_type(n->in(2)) == T_FLOAT && Matcher::vector_length(n->in(2)) >= 4); match(Set dst (MinReductionV dst src)); @@ -19810,7 +19810,7 @@ instruct minmax_reductionD_av(legRegD dst, legVec src, legVec tmp1, legVec tmp2, ins_pipe( pipe_slow ); %} -instruct minmax_reduction2D_avx10(regD dst, immD src1, vec src2, vec xtmp1) %{ +instruct minmax_reduction2D_avx10_2(regD dst, immD src1, vec src2, vec xtmp1) %{ predicate(VM_Version::supports_avx10_2() && Matcher::vector_element_basic_type(n->in(2)) == T_DOUBLE && ((n->Opcode() == Op_MinReductionV && n->in(1)->bottom_type() == TypeD::POS_INF) || (n->Opcode() == Op_MaxReductionV && n->in(1)->bottom_type() == TypeD::NEG_INF)) && @@ -19828,7 +19828,7 @@ instruct minmax_reduction2D_avx10(regD dst, immD src1, vec src2, vec xtmp1) %{ ins_pipe( pipe_slow ); %} -instruct minmax_reductionD_avx10(regD dst, immD src1, vec src2, vec xtmp1, vec xtmp2) %{ +instruct minmax_reductionD_avx10_2(regD dst, immD src1, vec src2, vec xtmp1, vec xtmp2) %{ predicate(VM_Version::supports_avx10_2() && Matcher::vector_element_basic_type(n->in(2)) == T_DOUBLE && ((n->Opcode() == Op_MinReductionV && n->in(1)->bottom_type() == TypeD::POS_INF) || (n->Opcode() == Op_MaxReductionV && n->in(1)->bottom_type() == TypeD::NEG_INF)) && @@ -19847,7 +19847,7 @@ instruct minmax_reductionD_avx10(regD dst, immD src1, vec src2, vec xtmp1, vec x %} -instruct minmax_reduction2D_av_avx10(regD dst, vec src, vec xtmp1) %{ +instruct minmax_reduction2D_av_avx10_2(regD dst, vec src, vec xtmp1) %{ predicate(VM_Version::supports_avx10_2() && Matcher::vector_element_basic_type(n->in(2)) == T_DOUBLE && Matcher::vector_length(n->in(2)) == 2); match(Set dst (MinReductionV dst src)); @@ -19863,7 +19863,7 @@ instruct minmax_reduction2D_av_avx10(regD dst, vec src, vec xtmp1) %{ ins_pipe( pipe_slow ); %} -instruct minmax_reductionD_av_avx10(regD dst, vec src, vec xtmp1, vec xtmp2) %{ +instruct minmax_reductionD_av_avx10_2(regD dst, vec src, vec xtmp1, vec xtmp2) %{ predicate(VM_Version::supports_avx10_2() && Matcher::vector_element_basic_type(n->in(2)) == T_DOUBLE && Matcher::vector_length(n->in(2)) >= 4); match(Set dst (MinReductionV dst src)); @@ -20766,7 +20766,7 @@ instruct vminmaxL_reg_evex(vec dst, vec src1, vec src2) %{ %} // Float/Double vector Min/Max -instruct minmaxFP_avx10_reg(vec dst, vec a, vec b) %{ +instruct minmaxFP_reg_avx10_2(vec dst, vec a, vec b) %{ predicate(VM_Version::supports_avx10_2() && is_floating_point_type(Matcher::vector_element_basic_type(n))); // T_FLOAT, T_DOUBLE match(Set dst (MinV a b)); @@ -22113,29 +22113,29 @@ instruct castFtoX_reg_evex(vec dst, vec src, vec xtmp1, vec xtmp2, kReg ktmp1, k ins_pipe( pipe_slow ); %} -instruct castFtoX_reg_avx10(vec dst, vec src) %{ +instruct castFtoX_reg_avx10_2(vec dst, vec src) %{ predicate(VM_Version::supports_avx10_2() && is_integral_type(Matcher::vector_element_basic_type(n))); match(Set dst (VectorCastF2X src)); - format %{ "vector_cast_f2x_avx10 $dst, $src\t!" %} + format %{ "vector_cast_f2x_avx10_2 $dst, $src\t!" %} ins_encode %{ BasicType to_elem_bt = Matcher::vector_element_basic_type(this); int vlen_enc = (to_elem_bt == T_LONG) ? vector_length_encoding(this) : vector_length_encoding(this, $src); - __ vector_castF2X_avx10(to_elem_bt, $dst$$XMMRegister, $src$$XMMRegister, vlen_enc); + __ vector_castF2X_avx10_2(to_elem_bt, $dst$$XMMRegister, $src$$XMMRegister, vlen_enc); %} ins_pipe( pipe_slow ); %} -instruct castFtoX_mem_avx10(vec dst, memory src) %{ +instruct castFtoX_mem_avx10_2(vec dst, memory src) %{ predicate(VM_Version::supports_avx10_2() && is_integral_type(Matcher::vector_element_basic_type(n))); match(Set dst (VectorCastF2X (LoadVector src))); - format %{ "vector_cast_f2x_avx10 $dst, $src\t!" %} + format %{ "vector_cast_f2x_avx10_2 $dst, $src\t!" %} ins_encode %{ int vlen = Matcher::vector_length(this); BasicType to_elem_bt = Matcher::vector_element_basic_type(this); int vlen_enc = (to_elem_bt == T_LONG) ? vector_length_encoding(this) : vector_length_encoding(vlen * sizeof(jfloat)); - __ vector_castF2X_avx10(to_elem_bt, $dst$$XMMRegister, $src$$Address, vlen_enc); + __ vector_castF2X_avx10_2(to_elem_bt, $dst$$XMMRegister, $src$$Address, vlen_enc); %} ins_pipe( pipe_slow ); %} @@ -22187,29 +22187,29 @@ instruct castDtoX_reg_evex(vec dst, vec src, vec xtmp1, vec xtmp2, kReg ktmp1, k ins_pipe( pipe_slow ); %} -instruct castDtoX_reg_avx10(vec dst, vec src) %{ +instruct castDtoX_reg_avx10_2(vec dst, vec src) %{ predicate(VM_Version::supports_avx10_2() && is_integral_type(Matcher::vector_element_basic_type(n))); match(Set dst (VectorCastD2X src)); - format %{ "vector_cast_d2x_avx10 $dst, $src\t!" %} + format %{ "vector_cast_d2x_avx10_2 $dst, $src\t!" %} ins_encode %{ int vlen_enc = vector_length_encoding(this, $src); BasicType to_elem_bt = Matcher::vector_element_basic_type(this); - __ vector_castD2X_avx10(to_elem_bt, $dst$$XMMRegister, $src$$XMMRegister, vlen_enc); + __ vector_castD2X_avx10_2(to_elem_bt, $dst$$XMMRegister, $src$$XMMRegister, vlen_enc); %} ins_pipe( pipe_slow ); %} -instruct castDtoX_mem_avx10(vec dst, memory src) %{ +instruct castDtoX_mem_avx10_2(vec dst, memory src) %{ predicate(VM_Version::supports_avx10_2() && is_integral_type(Matcher::vector_element_basic_type(n))); match(Set dst (VectorCastD2X (LoadVector src))); - format %{ "vector_cast_d2x_avx10 $dst, $src\t!" %} + format %{ "vector_cast_d2x_avx10_2 $dst, $src\t!" %} ins_encode %{ int vlen = Matcher::vector_length(this); int vlen_enc = vector_length_encoding(vlen * sizeof(jdouble)); BasicType to_elem_bt = Matcher::vector_element_basic_type(this); - __ vector_castD2X_avx10(to_elem_bt, $dst$$XMMRegister, $src$$Address, vlen_enc); + __ vector_castD2X_avx10_2(to_elem_bt, $dst$$XMMRegister, $src$$Address, vlen_enc); %} ins_pipe( pipe_slow ); %} @@ -25181,14 +25181,14 @@ instruct scalar_binOps_HF_reg(regF dst, regF src1, regF src2) ins_pipe(pipe_slow); %} -instruct scalar_minmax_HF_avx10_reg(regF dst, regF src1, regF src2) +instruct scalar_minmax_HF_reg_avx10_2(regF dst, regF src1, regF src2) %{ predicate(VM_Version::supports_avx10_2()); match(Set dst (MaxHF src1 src2)); match(Set dst (MinHF src1 src2)); format %{ "scalar_min_max_fp16 $dst, $src1, $src2" %} ins_encode %{ - int function = this->ideal_Opcode() == Op_MinHF ? AVX10_MINMAX_MIN_COMPARE_SIGN : AVX10_MINMAX_MAX_COMPARE_SIGN; + int function = this->ideal_Opcode() == Op_MinHF ? AVX10_2_MINMAX_MIN_COMPARE_SIGN : AVX10_2_MINMAX_MAX_COMPARE_SIGN; __ eminmaxsh($dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, function); %} ins_pipe( pipe_slow ); @@ -25296,7 +25296,7 @@ instruct vector_fma_HF_mem(vec dst, memory src1, vec src2) ins_pipe( pipe_slow ); %} -instruct vector_minmax_HF_avx10_mem(vec dst, vec src1, memory src2) +instruct vector_minmax_HF_mem_avx10_2(vec dst, vec src1, memory src2) %{ predicate(VM_Version::supports_avx10_2()); match(Set dst (MinVHF src1 (VectorReinterpret (LoadVector src2)))); @@ -25304,13 +25304,13 @@ instruct vector_minmax_HF_avx10_mem(vec dst, vec src1, memory src2) format %{ "vector_min_max_fp16_mem $dst, $src1, $src2" %} ins_encode %{ int vlen_enc = vector_length_encoding(this); - int function = this->ideal_Opcode() == Op_MinVHF ? AVX10_MINMAX_MIN_COMPARE_SIGN : AVX10_MINMAX_MAX_COMPARE_SIGN; + int function = this->ideal_Opcode() == Op_MinVHF ? AVX10_2_MINMAX_MIN_COMPARE_SIGN : AVX10_2_MINMAX_MAX_COMPARE_SIGN; __ evminmaxph($dst$$XMMRegister, k0, $src1$$XMMRegister, $src2$$Address, true, function, vlen_enc); %} ins_pipe( pipe_slow ); %} -instruct vector_minmax_HF_avx10_reg(vec dst, vec src1, vec src2) +instruct vector_minmax_HF_reg_avx10_2(vec dst, vec src1, vec src2) %{ predicate(VM_Version::supports_avx10_2()); match(Set dst (MinVHF src1 src2)); @@ -25318,7 +25318,7 @@ instruct vector_minmax_HF_avx10_reg(vec dst, vec src1, vec src2) format %{ "vector_min_max_fp16 $dst, $src1, $src2" %} ins_encode %{ int vlen_enc = vector_length_encoding(this); - int function = this->ideal_Opcode() == Op_MinVHF ? AVX10_MINMAX_MIN_COMPARE_SIGN : AVX10_MINMAX_MAX_COMPARE_SIGN; + int function = this->ideal_Opcode() == Op_MinVHF ? AVX10_2_MINMAX_MIN_COMPARE_SIGN : AVX10_2_MINMAX_MAX_COMPARE_SIGN; __ evminmaxph($dst$$XMMRegister, k0, $src1$$XMMRegister, $src2$$XMMRegister, true, function, vlen_enc); %} ins_pipe( pipe_slow ); diff --git a/test/hotspot/jtreg/compiler/floatingpoint/ScalarFPtoIntCastTest.java b/test/hotspot/jtreg/compiler/floatingpoint/ScalarFPtoIntCastTest.java index e8575cfe6b6..80a9aca9ae2 100644 --- a/test/hotspot/jtreg/compiler/floatingpoint/ScalarFPtoIntCastTest.java +++ b/test/hotspot/jtreg/compiler/floatingpoint/ScalarFPtoIntCastTest.java @@ -90,7 +90,7 @@ public class ScalarFPtoIntCastTest { @IR(counts = {IRNode.X86_SCONV_F2I, "> 0"}, applyIfPlatform = {"x64", "true"}, applyIfCPUFeature = {"avx10_2", "false"}) - @IR(counts = {IRNode.X86_SCONV_F2I_AVX10, "> 0"}, + @IR(counts = {IRNode.X86_SCONV_F2I_AVX10_2, "> 0"}, applyIfCPUFeature = {"avx10_2", "true"}) public void float2int() { for (int i = 0; i < COUNT; i++) { @@ -106,7 +106,7 @@ public class ScalarFPtoIntCastTest { @IR(counts = {IRNode.X86_SCONV_F2L, "> 0"}, applyIfPlatform = {"x64", "true"}, applyIfCPUFeature = {"avx10_2", "false"}) - @IR(counts = {IRNode.X86_SCONV_F2L_AVX10, "> 0"}, + @IR(counts = {IRNode.X86_SCONV_F2L_AVX10_2, "> 0"}, applyIfCPUFeature = {"avx10_2", "true"}) public void float2long() { for (int i = 0; i < COUNT; i++) { @@ -122,7 +122,7 @@ public class ScalarFPtoIntCastTest { @IR(counts = {IRNode.X86_SCONV_F2I, "> 0"}, applyIfPlatform = {"x64", "true"}, applyIfCPUFeature = {"avx10_2", "false"}) - @IR(counts = {IRNode.X86_SCONV_F2I_AVX10, "> 0"}, + @IR(counts = {IRNode.X86_SCONV_F2I_AVX10_2, "> 0"}, applyIfCPUFeature = {"avx10_2", "true"}) public void float2short() { for (int i = 0; i < COUNT; i++) { @@ -138,7 +138,7 @@ public class ScalarFPtoIntCastTest { @IR(counts = {IRNode.X86_SCONV_F2I, "> 0"}, applyIfPlatform = {"x64", "true"}, applyIfCPUFeature = {"avx10_2", "false"}) - @IR(counts = {IRNode.X86_SCONV_F2I_AVX10, "> 0"}, + @IR(counts = {IRNode.X86_SCONV_F2I_AVX10_2, "> 0"}, applyIfCPUFeature = {"avx10_2", "true"}) public void float2byte() { for (int i = 0; i < COUNT; i++) { @@ -154,7 +154,7 @@ public class ScalarFPtoIntCastTest { @IR(counts = {IRNode.X86_SCONV_D2I, "> 0"}, applyIfPlatform = {"x64", "true"}, applyIfCPUFeature = {"avx10_2", "false"}) - @IR(counts = {IRNode.X86_SCONV_D2I_AVX10, "> 0"}, + @IR(counts = {IRNode.X86_SCONV_D2I_AVX10_2, "> 0"}, applyIfCPUFeature = {"avx10_2", "true"}) public void double2int() { for (int i = 0; i < COUNT; i++) { @@ -170,7 +170,7 @@ public class ScalarFPtoIntCastTest { @IR(counts = {IRNode.X86_SCONV_D2L, "> 0"}, applyIfPlatform = {"x64", "true"}, applyIfCPUFeature = {"avx10_2", "false"}) - @IR(counts = {IRNode.X86_SCONV_D2L_AVX10, "> 0"}, + @IR(counts = {IRNode.X86_SCONV_D2L_AVX10_2, "> 0"}, applyIfCPUFeature = {"avx10_2", "true"}) public void double2long() { for (int i = 0; i < COUNT; i++) { @@ -186,7 +186,7 @@ public class ScalarFPtoIntCastTest { @IR(counts = {IRNode.X86_SCONV_D2I, "> 0"}, applyIfPlatform = {"x64", "true"}, applyIfCPUFeature = {"avx10_2", "false"}) - @IR(counts = {IRNode.X86_SCONV_D2I_AVX10, "> 0"}, + @IR(counts = {IRNode.X86_SCONV_D2I_AVX10_2, "> 0"}, applyIfCPUFeature = {"avx10_2", "true"}) public void double2short() { for (int i = 0; i < COUNT; i++) { @@ -202,7 +202,7 @@ public class ScalarFPtoIntCastTest { @IR(counts = {IRNode.X86_SCONV_D2I, "> 0"}, applyIfPlatform = {"x64", "true"}, applyIfCPUFeature = {"avx10_2", "false"}) - @IR(counts = {IRNode.X86_SCONV_D2I_AVX10, "> 0"}, + @IR(counts = {IRNode.X86_SCONV_D2I_AVX10_2, "> 0"}, applyIfCPUFeature = {"avx10_2", "true"}) public void double2byte() { for (int i = 0; i < COUNT; i++) { diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java index 608027e7ee1..d5799e5aa05 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java @@ -2801,24 +2801,24 @@ public class IRNode { machOnlyNameRegex(X86_SCONV_F2L, "convF2L_reg_reg"); } - public static final String X86_SCONV_D2I_AVX10 = PREFIX + "X86_SCONV2_D2I_AVX10" + POSTFIX; + public static final String X86_SCONV_D2I_AVX10_2 = PREFIX + "X86_SCONV_D2I_AVX10_2" + POSTFIX; static { - machOnlyNameRegex(X86_SCONV_D2I_AVX10, "convD2I_(reg_reg|reg_mem)_avx10"); + machOnlyNameRegex(X86_SCONV_D2I_AVX10_2, "convD2I_(reg_reg|reg_mem)_avx10_2"); } - public static final String X86_SCONV_D2L_AVX10 = PREFIX + "X86_SCONV_D2L_AVX10" + POSTFIX; + public static final String X86_SCONV_D2L_AVX10_2 = PREFIX + "X86_SCONV_D2L_AVX10_2" + POSTFIX; static { - machOnlyNameRegex(X86_SCONV_D2L_AVX10, "convD2L_(reg_reg|reg_mem)_avx10"); + machOnlyNameRegex(X86_SCONV_D2L_AVX10_2, "convD2L_(reg_reg|reg_mem)_avx10_2"); } - public static final String X86_SCONV_F2I_AVX10 = PREFIX + "X86_SCONV_F2I_AVX10" + POSTFIX; + public static final String X86_SCONV_F2I_AVX10_2 = PREFIX + "X86_SCONV_F2I_AVX10_2" + POSTFIX; static { - machOnlyNameRegex(X86_SCONV_F2I_AVX10, "convF2I_(reg_reg|reg_mem)_avx10"); + machOnlyNameRegex(X86_SCONV_F2I_AVX10_2, "convF2I_(reg_reg|reg_mem)_avx10_2"); } - public static final String X86_SCONV_F2L_AVX10 = PREFIX + "X86_SCONV_F2L_AVX10" + POSTFIX; + public static final String X86_SCONV_F2L_AVX10_2 = PREFIX + "X86_SCONV_F2L_AVX10_2" + POSTFIX; static { - machOnlyNameRegex(X86_SCONV_F2L_AVX10, "convF2L_(reg_reg|reg_mem)_avx10"); + machOnlyNameRegex(X86_SCONV_F2L_AVX10_2, "convF2L_(reg_reg|reg_mem)_avx10_2"); } public static final String X86_VCAST_F2X = PREFIX + "X86_VCAST_F2X" + POSTFIX; @@ -2831,14 +2831,14 @@ public class IRNode { machOnlyNameRegex(X86_VCAST_D2X, "castDtoX_reg_(av|eve)x"); } - public static final String X86_VCAST_F2X_AVX10 = PREFIX + "X86_VCAST_F2X_AVX10" + POSTFIX; + public static final String X86_VCAST_F2X_AVX10_2 = PREFIX + "X86_VCAST_F2X_AVX10_2" + POSTFIX; static { - machOnlyNameRegex(X86_VCAST_F2X_AVX10, "castFtoX_(reg|mem)_avx10"); + machOnlyNameRegex(X86_VCAST_F2X_AVX10_2, "castFtoX_(reg|mem)_avx10_2"); } - public static final String X86_VCAST_D2X_AVX10 = PREFIX + "X86_VCAST_D2X_AVX10" + POSTFIX; + public static final String X86_VCAST_D2X_AVX10_2 = PREFIX + "X86_VCAST_D2X_AVX10_2" + POSTFIX; static { - machOnlyNameRegex(X86_VCAST_D2X_AVX10, "castDtoX_(reg|mem)_avx10"); + machOnlyNameRegex(X86_VCAST_D2X_AVX10_2, "castDtoX_(reg|mem)_avx10_2"); } public static final String XOR = PREFIX + "XOR" + POSTFIX; diff --git a/test/hotspot/jtreg/compiler/vectorapi/VectorFPtoIntCastTest.java b/test/hotspot/jtreg/compiler/vectorapi/VectorFPtoIntCastTest.java index 1037a2989f9..888750ec226 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/VectorFPtoIntCastTest.java +++ b/test/hotspot/jtreg/compiler/vectorapi/VectorFPtoIntCastTest.java @@ -90,7 +90,7 @@ public class VectorFPtoIntCastTest { applyIfCPUFeatureOr = {"avx512f", "true", "avx10_2", "true"}) @IR(counts = {IRNode.X86_VCAST_F2X, "> 0"}, applyIfCPUFeatureAnd = {"avx512f", "true", "avx10_2", "false"}) - @IR(counts = {IRNode.X86_VCAST_F2X_AVX10, "> 0"}, + @IR(counts = {IRNode.X86_VCAST_F2X_AVX10_2, "> 0"}, applyIfCPUFeature = {"avx10_2", "true"}) public void float2int() { var cvec = (IntVector)fvec512.convertShape(VectorOperators.F2I, ispec512, 0); @@ -112,7 +112,7 @@ public class VectorFPtoIntCastTest { applyIfCPUFeatureOr = {"avx512dq", "true", "avx10_2", "true"}) @IR(counts = {IRNode.X86_VCAST_F2X, "> 0"}, applyIfCPUFeatureAnd = {"avx512dq", "true", "avx10_2", "false"}) - @IR(counts = {IRNode.X86_VCAST_F2X_AVX10, "> 0"}, + @IR(counts = {IRNode.X86_VCAST_F2X_AVX10_2, "> 0"}, applyIfCPUFeature = {"avx10_2", "true"}) public void float2long() { var cvec = (LongVector)fvec512.convertShape(VectorOperators.F2L, lspec512, 0); @@ -134,7 +134,7 @@ public class VectorFPtoIntCastTest { applyIfCPUFeatureOr = {"avx512f", "true", "avx10_2", "true"}) @IR(counts = {IRNode.X86_VCAST_F2X, "> 0"}, applyIfCPUFeatureAnd = {"avx512f", "true", "avx10_2", "false"}) - @IR(counts = {IRNode.X86_VCAST_F2X_AVX10, "> 0"}, + @IR(counts = {IRNode.X86_VCAST_F2X_AVX10_2, "> 0"}, applyIfCPUFeature = {"avx10_2", "true"}) public void float2short() { var cvec = (ShortVector)fvec512.convertShape(VectorOperators.F2S, sspec256, 0); @@ -156,7 +156,7 @@ public class VectorFPtoIntCastTest { applyIfCPUFeatureOr = {"avx512f", "true", "avx10_2", "true"}) @IR(counts = {IRNode.X86_VCAST_F2X, "> 0"}, applyIfCPUFeatureAnd = {"avx512f", "true", "avx10_2", "false"}) - @IR(counts = {IRNode.X86_VCAST_F2X_AVX10, "> 0"}, + @IR(counts = {IRNode.X86_VCAST_F2X_AVX10_2, "> 0"}, applyIfCPUFeature = {"avx10_2", "true"}) public void float2byte() { var cvec = (ByteVector)fvec512.convertShape(VectorOperators.F2B, bspec128, 0); @@ -178,7 +178,7 @@ public class VectorFPtoIntCastTest { applyIfCPUFeatureOr = {"avx512f", "true", "avx10_2", "true"}) @IR(counts = {IRNode.X86_VCAST_D2X, "> 0"}, applyIfCPUFeatureAnd = {"avx512f", "true", "avx10_2", "false"}) - @IR(counts = {IRNode.X86_VCAST_D2X_AVX10, "> 0"}, + @IR(counts = {IRNode.X86_VCAST_D2X_AVX10_2, "> 0"}, applyIfCPUFeature = {"avx10_2", "true"}) public void double2int() { var cvec = (IntVector)dvec512.convertShape(VectorOperators.D2I, ispec256, 0); @@ -200,7 +200,7 @@ public class VectorFPtoIntCastTest { applyIfCPUFeatureOr = {"avx512dq", "true", "avx10_2", "true"}) @IR(counts = {IRNode.X86_VCAST_D2X, "> 0"}, applyIfCPUFeatureAnd = {"avx512dq", "true", "avx10_2", "false"}) - @IR(counts = {IRNode.X86_VCAST_D2X_AVX10, "> 0"}, + @IR(counts = {IRNode.X86_VCAST_D2X_AVX10_2, "> 0"}, applyIfCPUFeature = {"avx10_2", "true"}) public void double2long() { var cvec = (LongVector)dvec512.convertShape(VectorOperators.D2L, lspec512, 0); @@ -222,7 +222,7 @@ public class VectorFPtoIntCastTest { applyIfCPUFeatureOr = {"avx512f", "true", "avx10_2", "true"}) @IR(counts = {IRNode.X86_VCAST_D2X, "> 0"}, applyIfCPUFeatureAnd = {"avx512f", "true", "avx10_2", "false"}) - @IR(counts = {IRNode.X86_VCAST_D2X_AVX10, "> 0"}, + @IR(counts = {IRNode.X86_VCAST_D2X_AVX10_2, "> 0"}, applyIfCPUFeature = {"avx10_2", "true"}) public void double2short() { var cvec = (ShortVector)dvec512.convertShape(VectorOperators.D2S, sspec128, 0); @@ -244,7 +244,7 @@ public class VectorFPtoIntCastTest { applyIfCPUFeatureOr = {"avx512f", "true", "avx10_2", "true"}) @IR(counts = {IRNode.X86_VCAST_D2X, "> 0"}, applyIfCPUFeatureAnd = {"avx512f", "true", "avx10_2", "false"}) - @IR(counts = {IRNode.X86_VCAST_D2X_AVX10, "> 0"}, + @IR(counts = {IRNode.X86_VCAST_D2X_AVX10_2, "> 0"}, applyIfCPUFeature = {"avx10_2", "true"}) public void double2byte() { var cvec = (ByteVector)dvec512.convertShape(VectorOperators.D2B, bspec64, 0); diff --git a/test/hotspot/jtreg/compiler/vectorization/runner/ArrayTypeConvertTest.java b/test/hotspot/jtreg/compiler/vectorization/runner/ArrayTypeConvertTest.java index 4db973ff728..d3119a00c37 100644 --- a/test/hotspot/jtreg/compiler/vectorization/runner/ArrayTypeConvertTest.java +++ b/test/hotspot/jtreg/compiler/vectorization/runner/ArrayTypeConvertTest.java @@ -298,7 +298,7 @@ public class ArrayTypeConvertTest extends VectorizationTestRunner { counts = {IRNode.VECTOR_CAST_F2I, IRNode.VECTOR_SIZE + "min(max_float, max_int)", "> 0"}) @IR(counts = {IRNode.X86_VCAST_F2X, "> 0"}, applyIfCPUFeatureAnd = {"avx", "true", "avx10_2", "false"}) - @IR(counts = {IRNode.X86_VCAST_F2X_AVX10, "> 0"}, + @IR(counts = {IRNode.X86_VCAST_F2X_AVX10_2, "> 0"}, applyIfCPUFeature = {"avx10_2", "true"}) public int[] convertFloatToInt() { int[] res = new int[SIZE]; @@ -313,7 +313,7 @@ public class ArrayTypeConvertTest extends VectorizationTestRunner { counts = {IRNode.VECTOR_CAST_F2L, IRNode.VECTOR_SIZE + "min(max_float, max_long)", "> 0"}) @IR(counts = {IRNode.X86_VCAST_F2X, "> 0"}, applyIfCPUFeatureAnd = {"avx512dq", "true", "avx10_2", "false"}) - @IR(counts = {IRNode.X86_VCAST_F2X_AVX10, "> 0"}, + @IR(counts = {IRNode.X86_VCAST_F2X_AVX10_2, "> 0"}, applyIfCPUFeature = {"avx10_2", "true"}) public long[] convertFloatToLong() { long[] res = new long[SIZE]; @@ -328,7 +328,7 @@ public class ArrayTypeConvertTest extends VectorizationTestRunner { counts = {IRNode.VECTOR_CAST_D2I, IRNode.VECTOR_SIZE + "min(max_double, max_int)", "> 0"}) @IR(counts = {IRNode.X86_VCAST_D2X, "> 0"}, applyIfCPUFeatureAnd = {"avx", "true", "avx10_2", "false"}) - @IR(counts = {IRNode.X86_VCAST_D2X_AVX10, "> 0"}, + @IR(counts = {IRNode.X86_VCAST_D2X_AVX10_2, "> 0"}, applyIfCPUFeature = {"avx10_2", "true"}) public int[] convertDoubleToInt() { int[] res = new int[SIZE]; @@ -343,7 +343,7 @@ public class ArrayTypeConvertTest extends VectorizationTestRunner { counts = {IRNode.VECTOR_CAST_D2L, IRNode.VECTOR_SIZE + "min(max_double, max_long)", "> 0"}) @IR(counts = {IRNode.X86_VCAST_D2X, "> 0"}, applyIfCPUFeatureAnd = {"avx512dq", "true", "avx10_2", "false"}) - @IR(counts = {IRNode.X86_VCAST_D2X_AVX10, "> 0"}, + @IR(counts = {IRNode.X86_VCAST_D2X_AVX10_2, "> 0"}, applyIfCPUFeature = {"avx10_2", "true"}) public long[] convertDoubleToLong() { long[] res = new long[SIZE]; @@ -361,7 +361,7 @@ public class ArrayTypeConvertTest extends VectorizationTestRunner { @IR(counts = {IRNode.X86_VCAST_F2X, "> 0"}, applyIfOr = {"AlignVector", "false", "UseCompactObjectHeaders", "false"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx10_2", "false"}) - @IR(counts = {IRNode.X86_VCAST_F2X_AVX10, "> 0"}, + @IR(counts = {IRNode.X86_VCAST_F2X_AVX10_2, "> 0"}, applyIfOr = {"AlignVector", "false", "UseCompactObjectHeaders", "false"}, applyIfCPUFeature = {"avx10_2", "true"}) public short[] convertFloatToShort() { @@ -386,7 +386,7 @@ public class ArrayTypeConvertTest extends VectorizationTestRunner { @IR(counts = {IRNode.X86_VCAST_F2X, "> 0"}, applyIfOr = {"AlignVector", "false", "UseCompactObjectHeaders", "false"}, applyIfCPUFeatureAnd = {"avx2", "true", "avx10_2", "false"}) - @IR(counts = {IRNode.X86_VCAST_F2X_AVX10, "> 0"}, + @IR(counts = {IRNode.X86_VCAST_F2X_AVX10_2, "> 0"}, applyIfOr = {"AlignVector", "false", "UseCompactObjectHeaders", "false"}, applyIfCPUFeature = {"avx10_2", "true"}) public char[] convertFloatToChar() { @@ -414,7 +414,7 @@ public class ArrayTypeConvertTest extends VectorizationTestRunner { @IR(counts = {IRNode.X86_VCAST_D2X, "> 0"}, applyIf = {"MaxVectorSize", ">=16"}, applyIfCPUFeatureAnd = {"avx", "true", "avx10_2", "false"}) - @IR(counts = {IRNode.X86_VCAST_D2X_AVX10, "> 0"}, + @IR(counts = {IRNode.X86_VCAST_D2X_AVX10_2, "> 0"}, applyIf = {"MaxVectorSize", ">=16"}, applyIfCPUFeature = {"avx10_2", "true"}) public short[] convertDoubleToShort() { @@ -435,7 +435,7 @@ public class ArrayTypeConvertTest extends VectorizationTestRunner { @IR(counts = {IRNode.X86_VCAST_D2X, "> 0"}, applyIf = {"MaxVectorSize", ">=16"}, applyIfCPUFeatureAnd = {"avx", "true", "avx10_2", "false"}) - @IR(counts = {IRNode.X86_VCAST_D2X_AVX10, "> 0"}, + @IR(counts = {IRNode.X86_VCAST_D2X_AVX10_2, "> 0"}, applyIf = {"MaxVectorSize", ">=16"}, applyIfCPUFeature = {"avx10_2", "true"}) public char[] convertDoubleToChar() { From 104d0cb542d12f133ac8a0a34f2b21ca3aa4a5cc Mon Sep 17 00:00:00 2001 From: Quan Anh Mai Date: Sat, 13 Dec 2025 14:07:24 +0000 Subject: [PATCH 283/706] 8373577: C2: Cleanup adr_type of CallLeafPureNode Reviewed-by: roland, vlivanov --- src/hotspot/share/opto/callnode.hpp | 5 ++--- src/hotspot/share/opto/divnode.cpp | 2 +- src/hotspot/share/opto/graphKit.cpp | 3 ++- src/hotspot/share/opto/macro.cpp | 3 +-- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/hotspot/share/opto/callnode.hpp b/src/hotspot/share/opto/callnode.hpp index 90a86d76679..de4b8941359 100644 --- a/src/hotspot/share/opto/callnode.hpp +++ b/src/hotspot/share/opto/callnode.hpp @@ -943,9 +943,8 @@ protected: TupleNode* make_tuple_of_input_state_and_top_return_values(const Compile* C) const; public: - CallLeafPureNode(const TypeFunc* tf, address addr, const char* name, - const TypePtr* adr_type) - : CallLeafNode(tf, addr, name, adr_type) { + CallLeafPureNode(const TypeFunc* tf, address addr, const char* name) + : CallLeafNode(tf, addr, name, nullptr) { init_class_id(Class_CallLeafPure); } int Opcode() const override; diff --git a/src/hotspot/share/opto/divnode.cpp b/src/hotspot/share/opto/divnode.cpp index cf5bc8ce643..f3039b12508 100644 --- a/src/hotspot/share/opto/divnode.cpp +++ b/src/hotspot/share/opto/divnode.cpp @@ -42,7 +42,7 @@ #include -ModFloatingNode::ModFloatingNode(Compile* C, const TypeFunc* tf, address addr, const char* name) : CallLeafPureNode(tf, addr, name, TypeRawPtr::BOTTOM) { +ModFloatingNode::ModFloatingNode(Compile* C, const TypeFunc* tf, address addr, const char* name) : CallLeafPureNode(tf, addr, name) { add_flag(Flag_is_macro); C->add_macro_node(this); } diff --git a/src/hotspot/share/opto/graphKit.cpp b/src/hotspot/share/opto/graphKit.cpp index 49c411843d5..f5c15a81cb6 100644 --- a/src/hotspot/share/opto/graphKit.cpp +++ b/src/hotspot/share/opto/graphKit.cpp @@ -2505,7 +2505,8 @@ Node* GraphKit::make_runtime_call(int flags, uint num_bits = call_type->range()->field_at(TypeFunc::Parms)->is_vect()->length_in_bytes() * BitsPerByte; call = new CallLeafVectorNode(call_type, call_addr, call_name, adr_type, num_bits); } else if (flags & RC_PURE) { - call = new CallLeafPureNode(call_type, call_addr, call_name, adr_type); + assert(adr_type == nullptr, "pure call does not touch memory"); + call = new CallLeafPureNode(call_type, call_addr, call_name); } else { call = new CallLeafNode(call_type, call_addr, call_name, adr_type); } diff --git a/src/hotspot/share/opto/macro.cpp b/src/hotspot/share/opto/macro.cpp index 90602bc2b35..bc07f937f1e 100644 --- a/src/hotspot/share/opto/macro.cpp +++ b/src/hotspot/share/opto/macro.cpp @@ -2658,8 +2658,7 @@ bool PhaseMacroExpand::expand_macro_nodes() { case Op_ModD: case Op_ModF: { CallNode* mod_macro = n->as_Call(); - CallNode* call = new CallLeafPureNode(mod_macro->tf(), mod_macro->entry_point(), - mod_macro->_name, TypeRawPtr::BOTTOM); + CallNode* call = new CallLeafPureNode(mod_macro->tf(), mod_macro->entry_point(), mod_macro->_name); call->init_req(TypeFunc::Control, mod_macro->in(TypeFunc::Control)); call->init_req(TypeFunc::I_O, C->top()); call->init_req(TypeFunc::Memory, C->top()); From fb531cdaf3b30034e0efa86b9b20558478ce94d0 Mon Sep 17 00:00:00 2001 From: Phil Race Date: Sat, 13 Dec 2025 22:43:30 +0000 Subject: [PATCH 284/706] 8373632: Some sound tests failing in CI due to lack of sound key Reviewed-by: iris --- test/jdk/javax/sound/midi/Sequencer/Looping.java | 2 +- test/jdk/javax/sound/sampled/Clip/IsRunningHang.java | 1 + test/jdk/javax/sound/sampled/DataLine/LongFramePosition.java | 1 + test/jdk/javax/sound/sampled/DirectAudio/bug6372428.java | 1 + 4 files changed, 4 insertions(+), 1 deletion(-) diff --git a/test/jdk/javax/sound/midi/Sequencer/Looping.java b/test/jdk/javax/sound/midi/Sequencer/Looping.java index 9bcc9254653..9a5a89c6472 100644 --- a/test/jdk/javax/sound/midi/Sequencer/Looping.java +++ b/test/jdk/javax/sound/midi/Sequencer/Looping.java @@ -36,7 +36,7 @@ import javax.sound.midi.Track; * @test * @bug 4204105 * @summary RFE: add loop() method(s) to Sequencer - * @key intermittent + * @key sound */ public class Looping { diff --git a/test/jdk/javax/sound/sampled/Clip/IsRunningHang.java b/test/jdk/javax/sound/sampled/Clip/IsRunningHang.java index c417c5ad8d0..8ffd760b08a 100644 --- a/test/jdk/javax/sound/sampled/Clip/IsRunningHang.java +++ b/test/jdk/javax/sound/sampled/Clip/IsRunningHang.java @@ -36,6 +36,7 @@ import javax.sound.sampled.LineUnavailableException; /** * @test * @bug 8156169 + * @key sound * @run main/othervm/timeout=300 IsRunningHang */ public final class IsRunningHang { diff --git a/test/jdk/javax/sound/sampled/DataLine/LongFramePosition.java b/test/jdk/javax/sound/sampled/DataLine/LongFramePosition.java index 079a785de8b..42e70521b2b 100644 --- a/test/jdk/javax/sound/sampled/DataLine/LongFramePosition.java +++ b/test/jdk/javax/sound/sampled/DataLine/LongFramePosition.java @@ -29,6 +29,7 @@ import javax.sound.sampled.SourceDataLine; /** * @test * @bug 5049129 + * @key sound * @summary DataLine.getLongFramePosition */ public class LongFramePosition { diff --git a/test/jdk/javax/sound/sampled/DirectAudio/bug6372428.java b/test/jdk/javax/sound/sampled/DirectAudio/bug6372428.java index 177ebce85a0..a99caeea055 100644 --- a/test/jdk/javax/sound/sampled/DirectAudio/bug6372428.java +++ b/test/jdk/javax/sound/sampled/DirectAudio/bug6372428.java @@ -31,6 +31,7 @@ import javax.sound.sampled.TargetDataLine; /* * @test * @bug 6372428 + * @key sound * @summary playback and capture doesn't interrupt after terminating thread that * calls start() * @run main bug6372428 From 99f90befafe9476de17e416d45a9875569171935 Mon Sep 17 00:00:00 2001 From: Thomas Stuefe Date: Sun, 14 Dec 2025 11:57:00 +0000 Subject: [PATCH 285/706] 8373490: JFR Leak Profiler: path-to-gc-root very slow for large object arrays Reviewed-by: egahlin --- .../jfr/leakprofiler/chains/bfsClosure.cpp | 13 +- .../jcmd/TestJcmdDumpPathToGCRootsBFSDFS.java | 195 ++++++++++++++++++ 2 files changed, 202 insertions(+), 6 deletions(-) create mode 100644 test/jdk/jdk/jfr/jcmd/TestJcmdDumpPathToGCRootsBFSDFS.java diff --git a/src/hotspot/share/jfr/leakprofiler/chains/bfsClosure.cpp b/src/hotspot/share/jfr/leakprofiler/chains/bfsClosure.cpp index 4f96680fa6c..701f75ff87c 100644 --- a/src/hotspot/share/jfr/leakprofiler/chains/bfsClosure.cpp +++ b/src/hotspot/share/jfr/leakprofiler/chains/bfsClosure.cpp @@ -121,13 +121,14 @@ void BFSClosure::closure_impl(UnifiedOopRef reference, const oop pointee) { return; } - if (_use_dfs) { - assert(_current_parent != nullptr, "invariant"); - DFSClosure::find_leaks_from_edge(_edge_store, _mark_bits, _current_parent); - return; - } - if (!_mark_bits->is_marked(pointee)) { + + if (_use_dfs) { + assert(_current_parent != nullptr, "invariant"); + DFSClosure::find_leaks_from_edge(_edge_store, _mark_bits, _current_parent); + return; + } + _mark_bits->mark_obj(pointee); // is the pointee a sample object? if (pointee->mark().is_marked()) { diff --git a/test/jdk/jdk/jfr/jcmd/TestJcmdDumpPathToGCRootsBFSDFS.java b/test/jdk/jdk/jfr/jcmd/TestJcmdDumpPathToGCRootsBFSDFS.java new file mode 100644 index 00000000000..6815d354309 --- /dev/null +++ b/test/jdk/jdk/jfr/jcmd/TestJcmdDumpPathToGCRootsBFSDFS.java @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2025, 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.jfr.jcmd; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import jdk.jfr.Enabled; +import jdk.jfr.Recording; +import jdk.jfr.consumer.RecordedEvent; +import jdk.jfr.consumer.RecordedObject; +import jdk.jfr.consumer.RecordingFile; +import jdk.jfr.internal.test.WhiteBox; +import jdk.test.lib.jfr.EventNames; + +/** + * @test id=dfs-only + * @summary Test dumping with path-to-gc-roots and DFS only + * @bug 8373490 + * @requires vm.hasJFR & vm.flagless + * @modules jdk.jfr/jdk.jfr.internal.test + * @library /test/lib /test/jdk + * + * @run main/othervm -XX:TLABSize=2k -Xmx256m jdk.jfr.jcmd.TestJcmdDumpPathToGCRootsBFSDFS dfs-only + */ + +/** + * @test id=bfs-only + * @summary Test dumping with path-to-gc-roots and BFS only + * @bug 8373490 + * @requires vm.hasJFR & vm.flagless + * @modules jdk.jfr/jdk.jfr.internal.test + * @library /test/lib /test/jdk + * + * @run main/othervm -XX:TLABSize=2k -Xmx256m jdk.jfr.jcmd.TestJcmdDumpPathToGCRootsBFSDFS bfs-only + */ + +/** + * @test id=bfsdfs + * @summary Test dumping with path-to-gc-roots and mixed BFS+DFS + * @bug 8373490 + * @requires vm.hasJFR & vm.flagless + * @modules jdk.jfr/jdk.jfr.internal.test + * @library /test/lib /test/jdk + * + * @run main/othervm -XX:TLABSize=2k -Xmx256m jdk.jfr.jcmd.TestJcmdDumpPathToGCRootsBFSDFS bfsdfs + */ +public class TestJcmdDumpPathToGCRootsBFSDFS { + + // Note: + // - We start with a small heap of 256M in order to get the minimum Edge Queue size in BFS (lower cap is 32MB, enough to hold ~2mio edges) + // - We build a leak with an array containing more than 2mio entries + // That will hit BFS first, then fall back to DFS, showing the performance problem JDK-8373490 describes. + // DFS-only mode should work well, and so should BFS-only mode. + + // The minimum size of the edge queue in BFS (keep in sync with hotspot) + private final static int minimumEdgeQueueSizeCap = 32 * 1024 * 1024; + // The size of the Edge structure (keep in sync with hotspot) + private final static int edgeSizeBytes = 16; + + public static List leak; + + public static void main(String[] args) throws Exception { + WhiteBox.setWriteAllObjectSamples(true); + String settingName = EventNames.OldObjectSample + "#" + "cutoff"; + + int edgesPerMinSizedQueue = minimumEdgeQueueSizeCap / 16; + int lower = 1_000_000; + int upper = 3_000_000; + int fudge = 250_000; + if (edgesPerMinSizedQueue < (lower + fudge)) { + throw new RuntimeException("edgesPerMinSizedQueue lower bound wrong?"); + } + if (edgesPerMinSizedQueue > (upper - fudge)) { + throw new RuntimeException("edgesPerMinSizedQueue upper bound wrong?"); + } + + int leakedObjectCount; + boolean skipBFS; + switch (args[0]) { + case "bfsdfs" -> { + // Mixed mode: enough objects to saturate BFS queue + leakedObjectCount = upper; + skipBFS = false; + } + case "dfs-only" -> { + // DFS-only mode: object count does not matter, we enter DFS right away + leakedObjectCount = upper; + skipBFS = true; + } + case "bfs-only" -> { + // BFS-only mode: not enough objects to saturate BFS queue + leakedObjectCount = lower; + skipBFS = false; + } + default -> { + throw new RuntimeException("Invalid argument"); + } + }; + + WhiteBox.setSkipBFS(skipBFS); + + testDump("path-to-gc-roots=true", Collections.singletonMap(settingName, "infinity"), leakedObjectCount, true); + } + + private static void testDump(String pathToGcRoots, Map settings, int leakedObjectCount, boolean expectedChains) throws Exception { + while (true) { + try (Recording r = new Recording()) { + Map p = new HashMap<>(settings); + p.put(EventNames.OldObjectSample + "#" + Enabled.NAME, "true"); + r.setName("dodo"); + r.setSettings(p); + r.setToDisk(true); + r.start(); + clearLeak(); + System.out.println("Recording id: " + r.getId()); + System.out.println("Settings: " + settings.toString()); + System.out.println("Command: JFR.dump " + pathToGcRoots); + System.out.println("Chains expected: " + expectedChains); + buildLeak(leakedObjectCount); + System.gc(); + System.gc(); + File recording = new File("TestJcmdDumpPathToGCRoots" + r.getId() + ".jfr"); + recording.delete(); + JcmdHelper.jcmd("JFR.dump", "name=dodo", pathToGcRoots, "filename=" + recording.getAbsolutePath()); + r.setSettings(Collections.emptyMap()); + List events = RecordingFile.readAllEvents(recording.toPath()); + if (events.isEmpty()) { + System.out.println("No events found in recording. Retrying."); + continue; + } + boolean chains = hasChains(events); + if (expectedChains && !chains) { + System.out.println(events); + System.out.println("Expected chains but found none. Retrying."); + continue; + } + if (!expectedChains && chains) { + System.out.println(events); + System.out.println("Didn't expect chains but found some. Retrying."); + continue; + } + return; // Success + } + } + } + + private static void clearLeak() { + leak = null; + System.gc(); + } + + private static boolean hasChains(List events) throws IOException { + for (RecordedEvent e : events) { + RecordedObject ro = e.getValue("object"); + if (ro.getValue("referrer") != null) { + return true; + } + } + return false; + } + + private static void buildLeak(int objectCount) { + leak = new ArrayList(objectCount); + for (int i = 0; i < objectCount;i ++) { + leak.add(new Object[0]); + } + } +} From d03e7cb87ae04c1d32559b4a49d71d32f9d616a8 Mon Sep 17 00:00:00 2001 From: David Holmes Date: Sun, 14 Dec 2025 20:45:18 +0000 Subject: [PATCH 286/706] 8373522: Remove expired flags in JDK 27 Reviewed-by: kvn, ayang --- src/hotspot/share/runtime/arguments.cpp | 26 ------------------------- src/java.base/share/man/java.md | 2 ++ 2 files changed, 2 insertions(+), 26 deletions(-) diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index dab3a60c650..dbf10c8a7b3 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -534,7 +534,6 @@ static SpecialFlag const special_jvm_flags[] = { { "DynamicDumpSharedSpaces", JDK_Version::jdk(18), JDK_Version::jdk(19), JDK_Version::undefined() }, { "RequireSharedSpaces", JDK_Version::jdk(18), JDK_Version::jdk(19), JDK_Version::undefined() }, { "UseSharedSpaces", JDK_Version::jdk(18), JDK_Version::jdk(19), JDK_Version::undefined() }, - { "LockingMode", JDK_Version::jdk(24), JDK_Version::jdk(26), JDK_Version::jdk(27) }, #ifdef _LP64 { "UseCompressedClassPointers", JDK_Version::jdk(25), JDK_Version::jdk(27), JDK_Version::undefined() }, #endif @@ -550,36 +549,11 @@ static SpecialFlag const special_jvm_flags[] = { // -------------- Obsolete Flags - sorted by expired_in -------------- -#ifdef LINUX - { "UseOprofile", JDK_Version::jdk(25), JDK_Version::jdk(26), JDK_Version::jdk(27) }, -#endif { "MetaspaceReclaimPolicy", JDK_Version::undefined(), JDK_Version::jdk(21), JDK_Version::undefined() }, - { "G1UpdateBufferSize", JDK_Version::undefined(), JDK_Version::jdk(26), JDK_Version::jdk(27) }, - { "ShenandoahPacing", JDK_Version::jdk(25), JDK_Version::jdk(26), JDK_Version::jdk(27) }, #if defined(AARCH64) { "NearCpool", JDK_Version::undefined(), JDK_Version::jdk(25), JDK_Version::undefined() }, #endif - { "AdaptiveSizeMajorGCDecayTimeScale", JDK_Version::undefined(), JDK_Version::jdk(26), JDK_Version::jdk(27) }, - { "AdaptiveSizePolicyInitializingSteps", JDK_Version::undefined(), JDK_Version::jdk(26), JDK_Version::jdk(27) }, - { "AdaptiveSizePolicyOutputInterval", JDK_Version::undefined(), JDK_Version::jdk(26), JDK_Version::jdk(27) }, - { "AdaptiveSizeThroughPutPolicy", JDK_Version::undefined(), JDK_Version::jdk(26), JDK_Version::jdk(27) }, - { "AdaptiveTimeWeight", JDK_Version::undefined(), JDK_Version::jdk(26), JDK_Version::jdk(27) }, - { "PausePadding", JDK_Version::undefined(), JDK_Version::jdk(26), JDK_Version::jdk(27) }, - { "SurvivorPadding", JDK_Version::undefined(), JDK_Version::jdk(26), JDK_Version::jdk(27) }, - { "TenuredGenerationSizeIncrement", JDK_Version::undefined(), JDK_Version::jdk(26), JDK_Version::jdk(27) }, - { "TenuredGenerationSizeSupplement", JDK_Version::undefined(), JDK_Version::jdk(26), JDK_Version::jdk(27) }, - { "TenuredGenerationSizeSupplementDecay", JDK_Version::undefined(), JDK_Version::jdk(26), JDK_Version::jdk(27) }, - { "UseAdaptiveGenerationSizePolicyAtMajorCollection", JDK_Version::undefined(), JDK_Version::jdk(26), JDK_Version::jdk(27) }, - { "UseAdaptiveGenerationSizePolicyAtMinorCollection", JDK_Version::undefined(), JDK_Version::jdk(26), JDK_Version::jdk(27) }, - { "UseAdaptiveSizeDecayMajorGCCost", JDK_Version::undefined(), JDK_Version::jdk(26), JDK_Version::jdk(27) }, - { "UseAdaptiveSizePolicyFootprintGoal", JDK_Version::undefined(), JDK_Version::jdk(26), JDK_Version::jdk(27) }, - { "UseAdaptiveSizePolicyWithSystemGC", JDK_Version::undefined(), JDK_Version::jdk(26), JDK_Version::jdk(27) }, - { "UsePSAdaptiveSurvivorSizePolicy", JDK_Version::undefined(), JDK_Version::jdk(26), JDK_Version::jdk(27) }, - - { "PretenureSizeThreshold", JDK_Version::undefined(), JDK_Version::jdk(26), JDK_Version::jdk(27) }, - { "HeapMaximumCompactionInterval",JDK_Version::undefined(), JDK_Version::jdk(26), JDK_Version::jdk(27) }, - #ifdef ASSERT { "DummyObsoleteTestFlag", JDK_Version::undefined(), JDK_Version::jdk(18), JDK_Version::undefined() }, #endif diff --git a/src/java.base/share/man/java.md b/src/java.base/share/man/java.md index 8517e161e3f..30661a3f387 100644 --- a/src/java.base/share/man/java.md +++ b/src/java.base/share/man/java.md @@ -3002,6 +3002,8 @@ No documented java options have been removed in JDK @@VERSION_SPECIFICATION@@. For the lists and descriptions of options removed in previous releases see the *Removed Java Options* section in: +- [The `java` Command, Release 26](https://docs.oracle.com/en/java/javase/26/docs/specs/man/java.html) + - [The `java` Command, Release 25](https://docs.oracle.com/en/java/javase/25/docs/specs/man/java.html) - [The `java` Command, Release 24](https://docs.oracle.com/en/java/javase/24/docs/specs/man/java.html) From eda1ab2143f8bb25fce2e5c086aeb4ecb4141f55 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Mon, 15 Dec 2025 01:50:25 +0000 Subject: [PATCH 287/706] 8373449: Parallel: Obsolete deprecated PSChunkLargeArrays Reviewed-by: kbarrett, dholmes, tschatzl --- src/hotspot/share/gc/parallel/parallel_globals.hpp | 5 +---- src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp | 4 +--- src/hotspot/share/runtime/arguments.cpp | 3 ++- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/hotspot/share/gc/parallel/parallel_globals.hpp b/src/hotspot/share/gc/parallel/parallel_globals.hpp index 84d884f128c..22e495e7db4 100644 --- a/src/hotspot/share/gc/parallel/parallel_globals.hpp +++ b/src/hotspot/share/gc/parallel/parallel_globals.hpp @@ -33,10 +33,7 @@ constraint) \ product(bool, UseMaximumCompactionOnSystemGC, true, \ "Use maximum compaction in the Parallel Old garbage collector " \ - "for a system GC") \ - \ - product(bool, PSChunkLargeArrays, true, \ - "(Deprecated) Process large arrays in chunks") + "for a system GC") // end of GC_PARALLEL_FLAGS diff --git a/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp b/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp index fb58c22cf29..f1fd49c7dfe 100644 --- a/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp +++ b/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp @@ -299,8 +299,7 @@ inline oop PSPromotionManager::copy_unmarked_to_survivor_space(oop o, // _min_array_size_for_chunking, and most of them will be arrays. // So, the objArray test would be very infrequent. if (new_obj_size > _min_array_size_for_chunking && - klass->is_objArray_klass() && - PSChunkLargeArrays) { + klass->is_objArray_klass()) { push_objArray(o, new_obj); } else { // we'll just push its contents @@ -344,7 +343,6 @@ inline void PSPromotionManager::copy_and_push_safe_barrier(T* p) { inline void PSPromotionManager::process_popped_location_depth(ScannerTask task, bool stolen) { if (task.is_partial_array_state()) { - assert(PSChunkLargeArrays, "invariant"); process_array_chunk(task.to_partial_array_state(), stolen); } else { if (task.is_narrow_oop_ptr()) { diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index dbf10c8a7b3..d4ba599fa9b 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -539,7 +539,6 @@ static SpecialFlag const special_jvm_flags[] = { #endif { "ParallelRefProcEnabled", JDK_Version::jdk(26), JDK_Version::jdk(27), JDK_Version::jdk(28) }, { "ParallelRefProcBalancingEnabled", JDK_Version::jdk(26), JDK_Version::jdk(27), JDK_Version::jdk(28) }, - { "PSChunkLargeArrays", JDK_Version::jdk(26), JDK_Version::jdk(27), JDK_Version::jdk(28) }, { "MaxRAM", JDK_Version::jdk(26), JDK_Version::jdk(27), JDK_Version::jdk(28) }, { "AggressiveHeap", JDK_Version::jdk(26), JDK_Version::jdk(27), JDK_Version::jdk(28) }, { "NeverActAsServerClassMachine", JDK_Version::jdk(26), JDK_Version::jdk(27), JDK_Version::jdk(28) }, @@ -554,6 +553,8 @@ static SpecialFlag const special_jvm_flags[] = { { "NearCpool", JDK_Version::undefined(), JDK_Version::jdk(25), JDK_Version::undefined() }, #endif + { "PSChunkLargeArrays", JDK_Version::jdk(26), JDK_Version::jdk(27), JDK_Version::jdk(28) }, + #ifdef ASSERT { "DummyObsoleteTestFlag", JDK_Version::undefined(), JDK_Version::jdk(18), JDK_Version::undefined() }, #endif From 5edeb71e3b148d52962c46180c92ebfeda018f67 Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Mon, 15 Dec 2025 04:45:25 +0000 Subject: [PATCH 288/706] 6292135: DefaultTableModel.setColumnIdentifiers() Clears JTable Row Heights Reviewed-by: tr, kizune --- .../share/classes/javax/swing/JTable.java | 2 - .../TestRowHeightWithColIdentifier.java | 64 +++++++++++++++++++ 2 files changed, 64 insertions(+), 2 deletions(-) create mode 100644 test/jdk/javax/swing/JTable/TestRowHeightWithColIdentifier.java diff --git a/src/java.desktop/share/classes/javax/swing/JTable.java b/src/java.desktop/share/classes/javax/swing/JTable.java index e9ae9d82166..6e64b216d58 100644 --- a/src/java.desktop/share/classes/javax/swing/JTable.java +++ b/src/java.desktop/share/classes/javax/swing/JTable.java @@ -4454,8 +4454,6 @@ public class JTable extends JComponent implements TableModelListener, Scrollable // The whole thing changed clearSelectionAndLeadAnchor(); - rowModel = null; - if (sortManager != null) { try { ignoreSortChange = true; diff --git a/test/jdk/javax/swing/JTable/TestRowHeightWithColIdentifier.java b/test/jdk/javax/swing/JTable/TestRowHeightWithColIdentifier.java new file mode 100644 index 00000000000..ad2015e3b45 --- /dev/null +++ b/test/jdk/javax/swing/JTable/TestRowHeightWithColIdentifier.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2025, 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 6292135 + * @summary Verifies DefaultTableModel.setColumnIdentifiers() doesn't + * clear JTable Row Heights + * @run main TestRowHeightWithColIdentifier + */ + +import javax.swing.JTable; +import javax.swing.SwingUtilities; +import javax.swing.table.DefaultTableModel; + +public class TestRowHeightWithColIdentifier{ + + + public static void main(String[] args) throws Exception { + SwingUtilities.invokeAndWait(() -> { + DefaultTableModel model = new DefaultTableModel(null, new Object[] {"FOO", "BAR"}); + JTable table = new JTable(model); + + model.addRow(new Object[] {"00", "01"}); + model.addRow(new Object[] {"10", "11"}); + model.addRow(new Object[] {"20", "21"}); + for (int row = 0; row < table.getRowCount(); row++) { + table.setRowHeight(row, 100); + } + for (int row = 0; row < table.getRowCount(); row++) { + System.out.println("Before table rowHeight " + table.getRowHeight(row)); + } + int oldRowHeight = table.getRowHeight(0); + model.setColumnIdentifiers(new Object[] {"Check", "it out!"}); + for (int row = 0; row < table.getRowCount(); row++) { + System.out.println("After table rowHeight " + table.getRowHeight(row)); + } + int curRowHeight = table.getRowHeight(0); + if (curRowHeight != oldRowHeight) { + throw new RuntimeException("DefaultTableModel.setColumnIdentifiers() Clears JTable Row Height"); + } + }); + } +} From 0e7bc6b0928bd860c665ead26d2237055c0c9d27 Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Mon, 15 Dec 2025 04:52:14 +0000 Subject: [PATCH 289/706] 6681958: Maximization state of JInternalFrames is corrupted by WindowsDesktopManager Reviewed-by: tr, kizune --- .../plaf/windows/WindowsDesktopManager.java | 11 +- .../JIFMaximizedTrfAttribute.java | 100 ++++++++++++++++++ 2 files changed, 107 insertions(+), 4 deletions(-) create mode 100644 test/jdk/javax/swing/JInternalFrame/JIFMaximizedTrfAttribute.java diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsDesktopManager.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsDesktopManager.java index 355f70b4607..79d81bad089 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsDesktopManager.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsDesktopManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, 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 @@ -80,10 +80,13 @@ public final class WindowsDesktopManager extends DefaultDesktopManager if (f.isMaximizable()) { if (!f.isMaximum()) { f.setMaximum(true); - } else if (f.isMaximum() && f.isIcon()) { - f.setIcon(false); } else { - f.setMaximum(false); + // If frame being activated is set to maximised + // and iconified, let it be maximised + // else remain non-maximised + if (f.isIcon()) { + f.setIcon(false); + } } } } diff --git a/test/jdk/javax/swing/JInternalFrame/JIFMaximizedTrfAttribute.java b/test/jdk/javax/swing/JInternalFrame/JIFMaximizedTrfAttribute.java new file mode 100644 index 00000000000..f5030b934b6 --- /dev/null +++ b/test/jdk/javax/swing/JInternalFrame/JIFMaximizedTrfAttribute.java @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2025, 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 6681958 + * @summary Verifies Maximization state of JInternalFrames is + * not corrupted by WindowsDesktopManager + * @requires (os.family == "windows") + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual JIFMaximizedTrfAttribute + */ + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.BorderLayout; + +import javax.swing.JButton; +import javax.swing.JDesktopPane; +import javax.swing.JFrame; +import javax.swing.JInternalFrame; +import javax.swing.UIManager; + +import java.beans.PropertyVetoException; + +public class JIFMaximizedTrfAttribute { + + static final String INSTRUCTIONS = """ + A maximised JInternalFrame would be shown with a + button "open another internal frame". + Press the button on the internal frame. + A second internal frame is created and opened. + If second internal frame is maximized, + press Pass else press Fail."""; + + public static void main(String[] args) throws Exception { + // Set Windows L&F + UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .columns(50) + .testUI(JIFMaximizedTrfAttribute::createUI) + .position(PassFailJFrame.Position.TOP_LEFT_CORNER) + .build() + .awaitAndCheck(); + } + + static JFrame createUI() { + + final JDesktopPane pane = new JDesktopPane(); + final JInternalFrame internal = new JInternalFrame("the first internal frame", true, true, true, true); + pane.add(internal); + internal.setBounds(0, 0, 200, 100); + try { + internal.setMaximum(true); + } catch (PropertyVetoException e) { } + internal.setVisible(true); + JButton button = new JButton("open another internal frame"); + button.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent evt) { + final JInternalFrame internal2 = new JInternalFrame("another one", true, true, true, true); + pane.add(internal2); + internal2.setBounds(250, 150, 200, 100); + try { + internal2.setMaximum(true); + } catch (PropertyVetoException e) {} + internal2.setVisible(true); + } + }); + internal.add(button, BorderLayout.SOUTH); + + JFrame f = new JFrame("JIFMaximizedTrfAttribute"); + f.add(pane, BorderLayout.CENTER); + f.setSize(800, 600); + f.setLocationRelativeTo(null); + return f; + } +} From dc1b0b5f81b6c3de85a0234d0315370b6413c077 Mon Sep 17 00:00:00 2001 From: Jonas Norlinder Date: Mon, 15 Dec 2025 06:13:07 +0000 Subject: [PATCH 290/706] 8373557: Remove stale comments after JDK-8372584 Reviewed-by: dholmes, jsjolen --- src/hotspot/os/linux/os_linux.cpp | 7 ------- src/hotspot/share/runtime/os.hpp | 5 +---- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index ba05fde7f12..8af89bb3a71 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -4298,13 +4298,6 @@ OSReturn os::get_native_priority(const Thread* const thread, return (*priority_ptr != -1 || errno == 0 ? OS_OK : OS_ERR); } -// This is the fastest way to get thread cpu time on Linux. -// Returns cpu time (user+sys) for any thread, not only for current. -// POSIX compliant clocks are implemented in the kernels 2.6.16+. -// It might work on 2.6.10+ with a special kernel/glibc patch. -// For reference, please, see IEEE Std 1003.1-2004: -// http://www.unix.org/single_unix_specification - jlong os::Linux::thread_cpu_time(clockid_t clockid) { struct timespec tp; int status = clock_gettime(clockid, &tp); diff --git a/src/hotspot/share/runtime/os.hpp b/src/hotspot/share/runtime/os.hpp index b65bf643cbf..6798140ed4d 100644 --- a/src/hotspot/share/runtime/os.hpp +++ b/src/hotspot/share/runtime/os.hpp @@ -980,10 +980,7 @@ class os: AllStatic { // The thread_cpu_time() and current_thread_cpu_time() are only // supported if is_thread_cpu_time_supported() returns true. - // Thread CPU Time - return the fast estimate on a platform - // On Linux - fast clock_gettime where available - user+sys - // - otherwise: very slow /proc fs - user+sys - // On Windows - GetThreadTimes - user+sys + // Thread CPU Time - return the fast estimate on a platform - user+sys static jlong current_thread_cpu_time(); static jlong thread_cpu_time(Thread* t); From 01adf28c946580751f7c041b13c987f477a6289a Mon Sep 17 00:00:00 2001 From: Sergey Bylokhov Date: Mon, 15 Dec 2025 07:36:42 +0000 Subject: [PATCH 291/706] 8372974: Add missing @Override annotations in "com.sun.java.swing.plaf.gtk" package Reviewed-by: prr --- .../swing/plaf/gtk/GTKColorChooserPanel.java | 15 ++++- .../java/swing/plaf/gtk/GTKFileChooserUI.java | 65 +++++++++++++++++++ .../java/swing/plaf/gtk/GTKGraphicsUtils.java | 4 +- .../java/swing/plaf/gtk/GTKIconFactory.java | 13 +++- .../java/swing/plaf/gtk/GTKLookAndFeel.java | 19 +++++- .../sun/java/swing/plaf/gtk/GTKPainter.java | 53 ++++++++++++++- .../com/sun/java/swing/plaf/gtk/GTKStyle.java | 8 ++- .../java/swing/plaf/gtk/GTKStyleFactory.java | 3 +- .../com/sun/java/swing/plaf/gtk/Metacity.java | 26 +++++++- 9 files changed, 198 insertions(+), 8 deletions(-) diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKColorChooserPanel.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKColorChooserPanel.java index 1c8c1e88be4..7c243396dda 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKColorChooserPanel.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKColorChooserPanel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2025, 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 @@ -122,6 +122,7 @@ class GTKColorChooserPanel extends AbstractColorChooserPanel implements /** * Returns a user presentable description of this GTKColorChooserPane. */ + @Override public String getDisplayName() { return (String)UIManager.get("GTKColorChooserPanel.nameText"); } @@ -129,6 +130,7 @@ class GTKColorChooserPanel extends AbstractColorChooserPanel implements /** * Returns the mnemonic to use with getDisplayName. */ + @Override public int getMnemonic() { String m = (String)UIManager.get("GTKColorChooserPanel.mnemonic"); @@ -145,6 +147,7 @@ class GTKColorChooserPanel extends AbstractColorChooserPanel implements /** * Character to underline that represents the mnemonic. */ + @Override public int getDisplayedMnemonicIndex() { String m = (String)UIManager.get( "GTKColorChooserPanel.displayedMnemonicIndex"); @@ -159,14 +162,17 @@ class GTKColorChooserPanel extends AbstractColorChooserPanel implements return -1; } + @Override public Icon getSmallDisplayIcon() { return null; } + @Override public Icon getLargeDisplayIcon() { return null; } + @Override public void uninstallChooserPanel(JColorChooser enclosingChooser) { super.uninstallChooserPanel(enclosingChooser); removeAll(); @@ -175,6 +181,7 @@ class GTKColorChooserPanel extends AbstractColorChooserPanel implements /** * Builds and configures the widgets for the GTKColorChooserPanel. */ + @Override protected void buildChooser() { triangle = new ColorTriangle(); triangle.setName("GTKColorChooserPanel.triangle"); @@ -307,6 +314,7 @@ class GTKColorChooserPanel extends AbstractColorChooserPanel implements /** * Refreshes the display from the model. */ + @Override public void updateChooser() { if (!settingColor) { lastLabel.setBackground(getColorFromModel()); @@ -490,6 +498,7 @@ class GTKColorChooserPanel extends AbstractColorChooserPanel implements /** * ChangeListener method, updates the necessary display widgets. */ + @Override public void stateChanged(ChangeEvent e) { if (settingColor) { return; @@ -687,6 +696,7 @@ class GTKColorChooserPanel extends AbstractColorChooserPanel implements return circleY + getIndicatorSize() / 2 - getWheelYOrigin(); } + @Override protected void processEvent(AWTEvent e) { if (!(getGTKColorChooserPanel().isEnabled())) { @@ -741,6 +751,7 @@ class GTKColorChooserPanel extends AbstractColorChooserPanel implements super.processEvent(e); } + @Override public void paintComponent(Graphics g) { super.paintComponent(g); @@ -1259,6 +1270,7 @@ class GTKColorChooserPanel extends AbstractColorChooserPanel implements this.type = type; } + @Override public void actionPerformed(ActionEvent e) { ColorTriangle triangle = (ColorTriangle)e.getSource(); @@ -1318,6 +1330,7 @@ class GTKColorChooserPanel extends AbstractColorChooserPanel implements @SuppressWarnings("serial") // Superclass is not serializable across versions private static class OpaqueLabel extends JLabel { + @Override public boolean isOpaque() { return true; } diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKFileChooserUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKFileChooserUI.java index 4f18dc84f4a..29d77650cb4 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKFileChooserUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKFileChooserUI.java @@ -188,6 +188,7 @@ class GTKFileChooserUI extends SynthFileChooserUI { super(filechooser); } + @Override protected ActionMap createActionMap() { ActionMap map = new ActionMapUIResource(); map.put("approveSelection", getApproveSelectionAction()); @@ -197,6 +198,7 @@ class GTKFileChooserUI extends SynthFileChooserUI { return map; } + @Override @SuppressWarnings("deprecation") public String getFileName() { JFileChooser fc = getFileChooser(); @@ -243,6 +245,7 @@ class GTKFileChooserUI extends SynthFileChooserUI { return sb.toString(); } + @Override public void setFileName(String fileName) { if (fileNameTextField != null) { fileNameTextField.setText(fileName); @@ -253,18 +256,22 @@ class GTKFileChooserUI extends SynthFileChooserUI { // return pathField.getText(); // } + @Override public void setDirectoryName(String dirname) { pathField.setText(dirname); } + @Override public void ensureFileIsVisible(JFileChooser fc, File f) { // PENDING } + @Override public void rescanCurrentDirectory(JFileChooser fc) { getModel().validateFileCache(); } + @Override public JPanel getAccessoryPanel() { return accessoryPanel; } @@ -273,6 +280,7 @@ class GTKFileChooserUI extends SynthFileChooserUI { // * FileView operations * // *********************** + @Override public FileView getFileView(JFileChooser fc) { return fileView; } @@ -282,16 +290,20 @@ class GTKFileChooserUI extends SynthFileChooserUI { iconCache = null; } + @Override public void clearIconCache() { } + @Override public Icon getCachedIcon(File f) { return null; } + @Override public void cacheIcon(File f, Icon i) { } + @Override public Icon getIcon(File f) { return (f != null && f.isDirectory()) ? directoryIcon : fileIcon; } @@ -317,6 +329,7 @@ class GTKFileChooserUI extends SynthFileChooserUI { } } + @Override protected void doSelectedFileChanged(PropertyChangeEvent e) { super.doSelectedFileChanged(e); File f = (File) e.getNewValue(); @@ -325,6 +338,7 @@ class GTKFileChooserUI extends SynthFileChooserUI { } } + @Override protected void doDirectoryChanged(PropertyChangeEvent e) { directoryList.clearSelection(); ListSelectionModel sm = directoryList.getSelectionModel(); @@ -357,6 +371,7 @@ class GTKFileChooserUI extends SynthFileChooserUI { super.doDirectoryChanged(e); } + @Override protected void doAccessoryChanged(PropertyChangeEvent e) { if (getAccessoryPanel() != null) { if (e.getOldValue() != null) { @@ -374,6 +389,7 @@ class GTKFileChooserUI extends SynthFileChooserUI { } } + @Override protected void doFileSelectionModeChanged(PropertyChangeEvent e) { directoryList.clearSelection(); rightPanel.setVisible(((Integer)e.getNewValue()).intValue() != JFileChooser.DIRECTORIES_ONLY); @@ -381,6 +397,7 @@ class GTKFileChooserUI extends SynthFileChooserUI { super.doFileSelectionModeChanged(e); } + @Override protected void doMultiSelectionChanged(PropertyChangeEvent e) { if (getFileChooser().isMultiSelectionEnabled()) { fileList.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); @@ -395,6 +412,7 @@ class GTKFileChooserUI extends SynthFileChooserUI { super.doMultiSelectionChanged(e); } + @Override protected void doControlButtonsChanged(PropertyChangeEvent e) { super.doControlButtonsChanged(e); @@ -407,6 +425,7 @@ class GTKFileChooserUI extends SynthFileChooserUI { updateDefaultButton(); } + @Override protected void doAncestorChanged(PropertyChangeEvent e) { if (e.getOldValue() == null && e.getNewValue() != null) { // Ancestor was added, set initial focus @@ -424,6 +443,7 @@ class GTKFileChooserUI extends SynthFileChooserUI { // ************ Create Listeners ************** // ******************************************** + @Override public ListSelectionListener createListSelectionListener(JFileChooser fc) { return new SelectionListener(); } @@ -434,6 +454,7 @@ class GTKFileChooserUI extends SynthFileChooserUI { this.list = list; } + @Override public void mouseClicked(MouseEvent e) { if (!getFileChooser().isEnabled()) { @@ -464,6 +485,7 @@ class GTKFileChooserUI extends SynthFileChooserUI { } } + @Override public void mouseEntered(MouseEvent evt) { if (list != null) { TransferHandler th1 = getFileChooser().getTransferHandler(); @@ -478,6 +500,7 @@ class GTKFileChooserUI extends SynthFileChooserUI { } } + @Override protected MouseListener createDoubleClickListener(JFileChooser fc, JList list) { return new DoubleClickListener(list); } @@ -486,6 +509,7 @@ class GTKFileChooserUI extends SynthFileChooserUI { @SuppressWarnings("deprecation") protected class SelectionListener implements ListSelectionListener { + @Override public void valueChanged(ListSelectionEvent e) { if (!e.getValueIsAdjusting()) { JFileChooser chooser = getFileChooser(); @@ -547,6 +571,7 @@ class GTKFileChooserUI extends SynthFileChooserUI { return new GTKFileChooserUI((JFileChooser)c); } + @Override public void installUI(JComponent c) { accessoryPanel = new JPanel(new BorderLayout(10, 10)); accessoryPanel.setName("GTKFileChooser.accessoryPanel"); @@ -554,6 +579,7 @@ class GTKFileChooserUI extends SynthFileChooserUI { super.installUI(c); } + @Override public void uninstallUI(JComponent c) { c.removePropertyChangeListener(filterComboBoxModel); super.uninstallUI(c); @@ -565,6 +591,7 @@ class GTKFileChooserUI extends SynthFileChooserUI { getFileChooser().removeAll(); } + @Override public void installComponents(JFileChooser fc) { super.installComponents(fc); @@ -623,6 +650,7 @@ class GTKFileChooserUI extends SynthFileChooserUI { JPanel comboBoxPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 0, 0) { + @Override public void layoutContainer(Container target) { super.layoutContainer(target); JComboBox comboBox = directoryComboBox; @@ -733,6 +761,7 @@ class GTKFileChooserUI extends SynthFileChooserUI { curDirName = currentDirectory.getPath(); } JLabel tmp = new JLabel(curDirName) { + @Override public Dimension getMaximumSize() { Dimension d = super.getMaximumSize(); d.height = getPreferredSize().height; @@ -747,6 +776,7 @@ class GTKFileChooserUI extends SynthFileChooserUI { // add the fileName field JTextField tmp2 = new JTextField() { + @Override public Dimension getMaximumSize() { Dimension d = super.getMaximumSize(); d.height = getPreferredSize().height; @@ -811,6 +841,7 @@ class GTKFileChooserUI extends SynthFileChooserUI { } } + @Override protected void installListeners(JFileChooser fc) { super.installListeners(fc); @@ -822,6 +853,7 @@ class GTKFileChooserUI extends SynthFileChooserUI { return SwingUtilities2.getUIDefaultsInt(key, l); } + @Override protected void uninstallListeners(JFileChooser fc) { super.uninstallListeners(fc); @@ -831,6 +863,7 @@ class GTKFileChooserUI extends SynthFileChooserUI { } private class GTKFCPropertyChangeListener implements PropertyChangeListener { + @Override public void propertyChange(PropertyChangeEvent e) { String prop = e.getPropertyName(); if (prop.equals("GTKFileChooser.showDirectoryIcons")) { @@ -841,6 +874,7 @@ class GTKFileChooserUI extends SynthFileChooserUI { } } + @Override protected void installDefaults(JFileChooser fc) { super.installDefaults(fc); readOnly = UIManager.getBoolean("FileChooser.readOnly"); @@ -850,11 +884,13 @@ class GTKFileChooserUI extends SynthFileChooserUI { Boolean.TRUE.equals(fc.getClientProperty("GTKFileChooser.showFileIcons")); } + @Override protected void installIcons(JFileChooser fc) { directoryIcon = UIManager.getIcon("FileView.directoryIcon"); fileIcon = UIManager.getIcon("FileView.fileIcon"); } + @Override protected void installStrings(JFileChooser fc) { super.installStrings(fc); @@ -894,6 +930,7 @@ class GTKFileChooserUI extends SynthFileChooserUI { filterLabelMnemonic = UIManager.getInt("FileChooser.filterLabelMnemonic"); } + @Override protected void uninstallStrings(JFileChooser fc) { super.uninstallStrings(fc); @@ -972,14 +1009,17 @@ class GTKFileChooserUI extends SynthFileChooserUI { return scrollpane; } + @Override protected void createModel() { model = new GTKDirectoryModel(); } + @Override public BasicDirectoryModel getModel() { return model; } + @Override public Action getApproveSelectionAction() { return approveSelectionAction; } @@ -990,6 +1030,7 @@ class GTKFileChooserUI extends SynthFileChooserUI { super(getFileChooser()); } + @Override protected void sort(Vector v) { FileSystemView fsv = getFileChooser().getFileSystemView(); if (fsv == null) { @@ -1028,6 +1069,7 @@ class GTKFileChooserUI extends SynthFileChooserUI { directoryChanged(); } + @Override public int getSize() { return getModel().getDirectories().size() + 1; } @@ -1038,10 +1080,12 @@ class GTKFileChooserUI extends SynthFileChooserUI { curDir; } + @Override public void intervalAdded(ListDataEvent e) { fireIntervalAdded(this, e.getIndex0(), e.getIndex1()); } + @Override public void intervalRemoved(ListDataEvent e) { fireIntervalRemoved(this, e.getIndex0(), e.getIndex1()); } @@ -1055,6 +1099,7 @@ class GTKFileChooserUI extends SynthFileChooserUI { // PENDING - fire the correct interval changed - currently sending // out that everything has changed + @Override public void contentsChanged(ListDataEvent e) { fireContentsChanged(); } @@ -1071,6 +1116,7 @@ class GTKFileChooserUI extends SynthFileChooserUI { getModel().addListDataListener(this); } + @Override public int getSize() { return getModel().getFiles().size(); } @@ -1088,10 +1134,12 @@ class GTKFileChooserUI extends SynthFileChooserUI { return getModel().getFiles().elementAt(index); } + @Override public void intervalAdded(ListDataEvent e) { fireIntervalAdded(this, e.getIndex0(), e.getIndex1()); } + @Override public void intervalRemoved(ListDataEvent e) { fireIntervalRemoved(this, e.getIndex0(), e.getIndex1()); } @@ -1104,6 +1152,7 @@ class GTKFileChooserUI extends SynthFileChooserUI { } // PENDING - fire the interval changed + @Override public void contentsChanged(ListDataEvent e) { fireContentsChanged(); } @@ -1112,6 +1161,7 @@ class GTKFileChooserUI extends SynthFileChooserUI { @SuppressWarnings("serial") // Superclass is not serializable across versions protected class FileCellRenderer extends DefaultListCellRenderer { + @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { @@ -1129,6 +1179,7 @@ class GTKFileChooserUI extends SynthFileChooserUI { @SuppressWarnings("serial") // Superclass is not serializable across versions protected class DirectoryCellRenderer extends DefaultListCellRenderer { + @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { @@ -1178,6 +1229,7 @@ class GTKFileChooserUI extends SynthFileChooserUI { c.setAlignmentY(JComponent.TOP_ALIGNMENT); } + @Override public Action getNewFolderAction() { if (newFolderAction == null) { newFolderAction = new NewFolderAction(); @@ -1252,15 +1304,18 @@ class GTKFileChooserUI extends SynthFileChooserUI { setSelectedItem(canonical); } + @Override public void setSelectedItem(Object selectedDirectory) { this.selectedDirectory = (File)selectedDirectory; fireContentsChanged(this, -1, -1); } + @Override public Object getSelectedItem() { return selectedDirectory; } + @Override public int getSize() { return directories.size(); } @@ -1280,6 +1335,7 @@ class GTKFileChooserUI extends SynthFileChooserUI { super("DirectoryComboBoxAction"); } + @Override public void actionPerformed(ActionEvent e) { File f = (File)directoryComboBox.getSelectedItem(); getFileChooser().setCurrentDirectory(f); @@ -1294,6 +1350,7 @@ class GTKFileChooserUI extends SynthFileChooserUI { protected NewFolderAction() { super(FilePane.ACTION_NEW_FOLDER); } + @Override public void actionPerformed(ActionEvent e) { if (readOnly) { return; @@ -1327,6 +1384,7 @@ class GTKFileChooserUI extends SynthFileChooserUI { @SuppressWarnings("serial") // Superclass is not serializable across versions private class GTKApproveSelectionAction extends ApproveSelectionAction { + @Override public void actionPerformed(ActionEvent e) { if (isDirectorySelected()) { File dir = getDirectory(); @@ -1362,6 +1420,7 @@ class GTKFileChooserUI extends SynthFileChooserUI { protected RenameFileAction() { super(FilePane.ACTION_EDIT_FILE_NAME); } + @Override public void actionPerformed(ActionEvent e) { if (getFileName().isEmpty()) { return; @@ -1405,6 +1464,7 @@ class GTKFileChooserUI extends SynthFileChooserUI { */ @SuppressWarnings("serial") // Superclass is not serializable across versions public class FilterComboBoxRenderer extends DefaultListCellRenderer { + @Override public String getName() { // As SynthComboBoxRenderer's are asked for a size BEFORE they // are parented getName is overridden to force the name to be @@ -1417,6 +1477,7 @@ class GTKFileChooserUI extends SynthFileChooserUI { return name; } + @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { @@ -1457,6 +1518,7 @@ class GTKFileChooserUI extends SynthFileChooserUI { filters = getFileChooser().getChoosableFileFilters(); } + @Override public void propertyChange(PropertyChangeEvent e) { String prop = e.getPropertyName(); if (prop == JFileChooser.CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY) { @@ -1467,6 +1529,7 @@ class GTKFileChooserUI extends SynthFileChooserUI { } } + @Override public void setSelectedItem(Object filter) { if (filter != null) { getFileChooser().setFileFilter((FileFilter) filter); @@ -1474,6 +1537,7 @@ class GTKFileChooserUI extends SynthFileChooserUI { } } + @Override public Object getSelectedItem() { // Ensure that the current filter is in the list. // NOTE: we shouldn't have to do this, since JFileChooser adds @@ -1495,6 +1559,7 @@ class GTKFileChooserUI extends SynthFileChooserUI { return getFileChooser().getFileFilter(); } + @Override public int getSize() { if (filters != null) { return filters.length; diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKGraphicsUtils.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKGraphicsUtils.java index 2a0aa7be41c..49062277086 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKGraphicsUtils.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKGraphicsUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2025, 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,6 +41,7 @@ import sun.swing.MnemonicHandler; * @author Joshua Outwater */ class GTKGraphicsUtils extends SynthGraphicsUtils { + @Override public void paintText(SynthContext context, Graphics g, String text, int x, int y, int mnemonicIndex) { if (text == null || text.length() <= 0) { @@ -83,6 +84,7 @@ class GTKGraphicsUtils extends SynthGraphicsUtils { * @param bounds Bounds of the text to be drawn. * @param mnemonicIndex Index to draw string at. */ + @Override public void paintText(SynthContext context, Graphics g, String text, Rectangle bounds, int mnemonicIndex) { if (text == null || text.length() <= 0) { diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKIconFactory.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKIconFactory.java index 4f04d729099..ffd7df909b5 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKIconFactory.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKIconFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2025, 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 @@ -163,6 +163,7 @@ class GTKIconFactory { this.method = methodName; } + @Override public void paintIcon(SynthContext context, Graphics g, int x, int y, int w, int h) { if (context != null) { @@ -171,10 +172,12 @@ class GTKIconFactory { } } + @Override public int getIconWidth(SynthContext context) { return getIconDimension(context); } + @Override public int getIconHeight(SynthContext context) { return getIconDimension(context); } @@ -248,6 +251,7 @@ class GTKIconFactory { super(method); } + @Override public void paintIcon(SynthContext context, Graphics g, int x, int y, int w, int h) { if (context != null) { @@ -256,6 +260,7 @@ class GTKIconFactory { } } + @Override int getIconDimension(SynthContext context) { updateSizeIfNecessary(context); return (iconDimension == -1) ? DEFAULT_ICON_SIZE : @@ -285,10 +290,12 @@ class GTKIconFactory { super(TOOL_BAR_HANDLE_ICON); } + @Override protected Class[] getMethodParamTypes() { return PARAM_TYPES; } + @Override public void paintIcon(SynthContext context, Graphics g, int x, int y, int w, int h) { if (context != null) { @@ -309,6 +316,7 @@ class GTKIconFactory { } } + @Override public int getIconWidth(SynthContext context) { if (context == null) { return 10; @@ -321,6 +329,7 @@ class GTKIconFactory { } } + @Override public int getIconHeight(SynthContext context) { if (context == null) { return 10; @@ -344,10 +353,12 @@ class GTKIconFactory { super(MENU_ARROW_ICON); } + @Override protected Class[] getMethodParamTypes() { return PARAM_TYPES; } + @Override public void paintIcon(SynthContext context, Graphics g, int x, int y, int w, int h) { if (context != null) { diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKLookAndFeel.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKLookAndFeel.java index 480b8bacb30..24a1997bdc1 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKLookAndFeel.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKLookAndFeel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2025, 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 @@ -261,6 +261,7 @@ public class GTKLookAndFeel extends SynthLookAndFeel { region == Region.TREE); } + @Override public UIDefaults getDefaults() { // We need to call super for basic's properties file. UIDefaults table = super.getDefaults(); @@ -301,6 +302,7 @@ public class GTKLookAndFeel extends SynthLookAndFeel { "com.sun.java.swing.plaf.gtk.resources.gtk"); } + @Override protected void initComponentDefaults(UIDefaults table) { // For compatibility with apps expecting certain defaults we'll // populate the table with the values from basic. @@ -511,6 +513,7 @@ public class GTKLookAndFeel extends SynthLookAndFeel { FontLazyValue(Region region) { this.region = region; } + @Override public Object createValue(UIDefaults table) { SynthStyleFactory factory = getStyleFactory(); GTKStyle style = (GTKStyle)factory.getStyle(null, region); @@ -556,6 +559,7 @@ public class GTKLookAndFeel extends SynthLookAndFeel { "ColorChooser.showPreviewPanelText", Boolean.FALSE, "ColorChooser.panels", new UIDefaults.ActiveValue() { + @Override public Object createValue(UIDefaults table) { return new AbstractColorChooserPanel[] { new GTKColorChooserPanel() }; @@ -1168,6 +1172,7 @@ public class GTKLookAndFeel extends SynthLookAndFeel { "TitledBorder.titleColor", controlText, "TitledBorder.border", new UIDefaults.LazyValue() { + @Override public Object createValue(UIDefaults table) { return new GTKPainter.TitledBorder(); } @@ -1184,6 +1189,7 @@ public class GTKLookAndFeel extends SynthLookAndFeel { "ToolBar.separatorSize", new DimensionUIResource(10, 10), "ToolBar.handleIcon", new UIDefaults.ActiveValue() { + @Override public Object createValue(UIDefaults table) { return GTKIconFactory.getToolBarHandleIcon(); } @@ -1312,6 +1318,7 @@ public class GTKLookAndFeel extends SynthLookAndFeel { } } + @Override protected void initSystemColorDefaults(UIDefaults table) { SynthStyleFactory factory = getStyleFactory(); GTKStyle windowStyle = @@ -1492,6 +1499,7 @@ public class GTKLookAndFeel extends SynthLookAndFeel { public String getKey() { return key; } + @Override public void propertyChange(final PropertyChangeEvent pce) { final GTKLookAndFeel lnf = get(); @@ -1504,6 +1512,7 @@ public class GTKLookAndFeel extends SynthLookAndFeel { // We are using invokeLater here because we are getting called // on the AWT-Motif thread which can cause a deadlock. SwingUtilities.invokeLater(new Runnable() { + @Override public void run() { String name = pce.getPropertyName(); /* We are listening for GTK desktop text AA settings: @@ -1531,30 +1540,36 @@ public class GTKLookAndFeel extends SynthLookAndFeel { } } + @Override public boolean isSupportedLookAndFeel() { Toolkit toolkit = Toolkit.getDefaultToolkit(); return (toolkit instanceof SunToolkit && ((SunToolkit)toolkit).isNativeGTKAvailable()); } + @Override public boolean isNativeLookAndFeel() { return true; } + @Override public String getDescription() { return "GTK look and feel"; } + @Override public String getName() { return "GTK look and feel"; } + @Override public String getID() { return "GTK"; } // Subclassed to pass in false to the superclass, we don't want to try // and load the system colors. + @Override protected void loadSystemColors(UIDefaults table, String[] systemColors, boolean useNative) { super.loadSystemColors(table, systemColors, false); } @@ -1663,6 +1678,7 @@ public class GTKLookAndFeel extends SynthLookAndFeel { * SynthStyles from the SynthStyleFactory * when the ancestor changed. */ + @Override public boolean shouldUpdateStyleOnAncestorChanged() { return true; } @@ -1670,6 +1686,7 @@ public class GTKLookAndFeel extends SynthLookAndFeel { /** * {@inheritDoc} */ + @Override public LayoutStyle getLayoutStyle() { return GnomeLayoutStyle.INSTANCE; } diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKPainter.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKPainter.java index fa28eb3ca71..cf9cd0f2551 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKPainter.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKPainter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2025, 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 @@ -77,17 +77,20 @@ class GTKPainter extends SynthPainter { context.getComponent().getName(); } + @Override public void paintCheckBoxBackground(SynthContext context, Graphics g, int x, int y, int w, int h) { paintRadioButtonBackground(context, g, x, y, w, h); } + @Override public void paintCheckBoxMenuItemBackground(SynthContext context, Graphics g, int x, int y, int w, int h) { paintRadioButtonMenuItemBackground(context, g, x, y, w, h); } // FORMATTED_TEXT_FIELD + @Override public void paintFormattedTextFieldBackground(SynthContext context, Graphics g, int x, int y, int w, int h) { @@ -97,6 +100,7 @@ class GTKPainter extends SynthPainter { // // TOOL_BAR_DRAG_WINDOW // + @Override public void paintToolBarDragWindowBackground(SynthContext context, Graphics g, int x, int y, int w, int h) { @@ -107,6 +111,7 @@ class GTKPainter extends SynthPainter { // // TOOL_BAR // + @Override public void paintToolBarBackground(SynthContext context, Graphics g, int x, int y, int w, int h) { @@ -126,6 +131,7 @@ class GTKPainter extends SynthPainter { } } + @Override public void paintToolBarContentBackground(SynthContext context, Graphics g, int x, int y, int w, int h) { @@ -144,6 +150,7 @@ class GTKPainter extends SynthPainter { // // PASSWORD_FIELD // + @Override public void paintPasswordFieldBackground(SynthContext context, Graphics g, int x, int y, int w, int h) { @@ -153,6 +160,7 @@ class GTKPainter extends SynthPainter { // // TEXT_FIELD // + @Override public void paintTextFieldBackground(SynthContext context, Graphics g, int x, int y, int w, int h) { if (getName(context) == "Tree.cellEditor") { @@ -166,6 +174,7 @@ class GTKPainter extends SynthPainter { // RADIO_BUTTON // // NOTE: this is called for JCheckBox too + @Override public void paintRadioButtonBackground(SynthContext context, Graphics g, int x, int y, int w, int h) { @@ -204,6 +213,7 @@ class GTKPainter extends SynthPainter { // RADIO_BUTTON_MENU_ITEM // // NOTE: this is called for JCheckBoxMenuItem too + @Override public void paintRadioButtonMenuItemBackground(SynthContext context, Graphics g, int x, int y, int w, int h) { @@ -218,6 +228,7 @@ class GTKPainter extends SynthPainter { // // LABEL // + @Override public void paintLabelBackground(SynthContext context, Graphics g, int x, int y, int w, int h) { @@ -247,6 +258,7 @@ class GTKPainter extends SynthPainter { // // INTERNAL_FRAME // + @Override public void paintInternalFrameBorder(SynthContext context, Graphics g, int x, int y, int w, int h) { @@ -256,6 +268,7 @@ class GTKPainter extends SynthPainter { // // DESKTOP_PANE // + @Override public void paintDesktopPaneBackground(SynthContext context, Graphics g, int x, int y, int w, int h) { @@ -266,12 +279,14 @@ class GTKPainter extends SynthPainter { // // DESKTOP_ICON // + @Override public void paintDesktopIconBorder(SynthContext context, Graphics g, int x, int y, int w, int h) { Metacity.INSTANCE.paintFrameBorder(context, g, x, y, w, h); } + @Override public void paintButtonBackground(SynthContext context, Graphics g, int x, int y, int w, int h) { String name = getName(context); @@ -388,6 +403,7 @@ class GTKPainter extends SynthPainter { // // ARROW_BUTTON // + @Override public void paintArrowButtonForeground(SynthContext context, Graphics g, int x, int y, int w, int h, int direction) { @@ -437,6 +453,7 @@ class GTKPainter extends SynthPainter { } } + @Override public void paintArrowButtonBackground(SynthContext context, Graphics g, int x, int y, int w, int h) { Region id = context.getRegion(); @@ -515,12 +532,14 @@ class GTKPainter extends SynthPainter { // // LIST // + @Override public void paintListBackground(SynthContext context, Graphics g, int x, int y, int w, int h) { // Does not call into ENGINE for better performance fillArea(context, g, x, y, w, h, GTKColorType.TEXT_BACKGROUND); } + @Override public void paintMenuBarBackground(SynthContext context, Graphics g, int x, int y, int w, int h) { Region id = context.getRegion(); @@ -544,6 +563,7 @@ class GTKPainter extends SynthPainter { // // MENU // + @Override public void paintMenuBackground(SynthContext context, Graphics g, int x, int y, int w, int h) { @@ -551,6 +571,7 @@ class GTKPainter extends SynthPainter { } // This is called for both MENU and MENU_ITEM + @Override public void paintMenuItemBackground(SynthContext context, Graphics g, int x, int y, int w, int h) { @@ -561,6 +582,7 @@ class GTKPainter extends SynthPainter { } } + @Override public void paintPopupMenuBackground(SynthContext context, Graphics g, int x, int y, int w, int h) { Region id = context.getRegion(); @@ -604,6 +626,7 @@ class GTKPainter extends SynthPainter { } } + @Override public void paintProgressBarBackground(SynthContext context, Graphics g, int x, int y, int w, int h) { @@ -618,6 +641,7 @@ class GTKPainter extends SynthPainter { } } + @Override public void paintProgressBarForeground(SynthContext context, Graphics g, int x, int y, int w, int h, int orientation) { @@ -637,6 +661,7 @@ class GTKPainter extends SynthPainter { } } + @Override public void paintViewportBorder(SynthContext context, Graphics g, int x, int y, int w, int h) { Region id = context.getRegion(); @@ -650,6 +675,7 @@ class GTKPainter extends SynthPainter { } } + @Override public void paintSeparatorBackground(SynthContext context, Graphics g, int x, int y, int w, int h, @@ -768,6 +794,7 @@ class GTKPainter extends SynthPainter { } } + @Override public void paintSliderTrackBackground(SynthContext context, Graphics g, int x, int y, int w,int h) { @@ -830,6 +857,7 @@ class GTKPainter extends SynthPainter { } } + @Override public void paintSliderThumbBackground(SynthContext context, Graphics g, int x, int y, int w, int h, int dir) { Region id = context.getRegion(); @@ -856,6 +884,7 @@ class GTKPainter extends SynthPainter { // // SPINNER // + @Override public void paintSpinnerBackground(SynthContext context, Graphics g, int x, int y, int w, int h) { @@ -865,6 +894,7 @@ class GTKPainter extends SynthPainter { // // SPLIT_PANE_DIVIDER // + @Override public void paintSplitPaneDividerBackground(SynthContext context, Graphics g, int x, int y, int w, int h) { @@ -886,12 +916,14 @@ class GTKPainter extends SynthPainter { } } + @Override public void paintSplitPaneDragDivider(SynthContext context, Graphics g,int x, int y, int w, int h, int orientation) { paintSplitPaneDividerForeground(context, g, x, y, w, h, orientation); } + @Override public void paintTabbedPaneContentBackground(SynthContext context, Graphics g, int x, int y, int w, int h) { JTabbedPane pane = (JTabbedPane)context.getComponent(); @@ -931,6 +963,7 @@ class GTKPainter extends SynthPainter { } } + @Override public void paintTabbedPaneTabBackground(SynthContext context, Graphics g, int x, int y, int w, int h, @@ -958,6 +991,7 @@ class GTKPainter extends SynthPainter { // // TEXT_PANE // + @Override public void paintTextPaneBackground(SynthContext context, Graphics g, int x, int y, int w, int h) { paintTextAreaBackground(context, g, x, y, w, h); @@ -966,6 +1000,7 @@ class GTKPainter extends SynthPainter { // // EDITOR_PANE // + @Override public void paintEditorPaneBackground(SynthContext context, Graphics g, int x, int y, int w, int h) { paintTextAreaBackground(context, g, x, y, w, h); @@ -974,6 +1009,7 @@ class GTKPainter extends SynthPainter { // // TEXT_AREA // + @Override public void paintTextAreaBackground(SynthContext context, Graphics g, int x, int y, int w, int h) { // Does not call into ENGINE for better performance @@ -1076,6 +1112,7 @@ class GTKPainter extends SynthPainter { // // ROOT_PANE // + @Override public void paintRootPaneBackground(SynthContext context, Graphics g, int x, int y, int w, int h) { // Does not call into ENGINE for better performance @@ -1085,6 +1122,7 @@ class GTKPainter extends SynthPainter { // // TOGGLE_BUTTON // + @Override public void paintToggleButtonBackground(SynthContext context, Graphics g, int x, int y, int w, int h) { @@ -1103,6 +1141,7 @@ class GTKPainter extends SynthPainter { // // SCROLL_BAR // + @Override public void paintScrollBarBackground(SynthContext context, Graphics g, int x, int y, int w,int h) { @@ -1148,6 +1187,7 @@ class GTKPainter extends SynthPainter { // // SCROLL_BAR_THUMB // + @Override public void paintScrollBarThumbBackground(SynthContext context, Graphics g, int x, int y, int w, int h, int dir) { Region id = context.getRegion(); @@ -1206,6 +1246,7 @@ class GTKPainter extends SynthPainter { // // TOOL_TIP // + @Override public void paintToolTipBackground(SynthContext context, Graphics g, int x, int y, int w,int h) { Region id = context.getRegion(); @@ -1224,6 +1265,7 @@ class GTKPainter extends SynthPainter { // // TREE_CELL // + @Override public void paintTreeCellBackground(SynthContext context, Graphics g, int x, int y, int w, int h) { Region id = context.getRegion(); @@ -1243,6 +1285,7 @@ class GTKPainter extends SynthPainter { } } + @Override public void paintTreeCellFocus(SynthContext context, Graphics g, int x, int y, int w, int h) { Region id = Region.TREE_CELL; @@ -1254,6 +1297,7 @@ class GTKPainter extends SynthPainter { // // TREE // + @Override public void paintTreeBackground(SynthContext context, Graphics g, int x, int y, int w, int h) { // As far as I can tell, these don't call into the ENGINE. @@ -1264,6 +1308,7 @@ class GTKPainter extends SynthPainter { // // VIEWPORT // + @Override public void paintViewportBackground(SynthContext context, Graphics g, int x, int y, int w, int h) { // As far as I can tell, these don't call into the ENGINE. @@ -1509,6 +1554,7 @@ class GTKPainter extends SynthPainter { return context; } + @Override public void paintBorder(Component c, Graphics g, int x, int y, int w, int h) { if (focusedCell) { @@ -1523,6 +1569,7 @@ class GTKPainter extends SynthPainter { } } + @Override public Insets getBorderInsets(Component c, Insets i) { SynthContext context = getContext(c); @@ -1533,6 +1580,7 @@ class GTKPainter extends SynthPainter { return i; } + @Override public boolean isBorderOpaque() { return true; } @@ -1542,6 +1590,7 @@ class GTKPainter extends SynthPainter { @SuppressWarnings("serial") // Superclass is not serializable across versions static class TitledBorder extends AbstractBorder implements UIResource { + @Override public void paintBorder(Component c, Graphics g, int x, int y, int w, int h) { SynthContext context = getContext((JComponent)c); @@ -1559,11 +1608,13 @@ class GTKPainter extends SynthPainter { } } + @Override public Insets getBorderInsets(Component c, Insets i) { SynthContext context = getContext((JComponent)c); return context.getStyle().getInsets(context, i); } + @Override public boolean isBorderOpaque() { return true; } diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKStyle.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKStyle.java index cc7a1333b64..baeb249eaa8 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKStyle.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKStyle.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2025, 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,6 +142,7 @@ class GTKStyle extends SynthStyle implements GTKConstants { return GTKPainter.INSTANCE; } + @Override protected Color getColorForState(SynthContext context, ColorType type) { if (type == ColorType.FOCUS || type == GTKColorType.BLACK) { return BLACK_COLOR; @@ -292,6 +293,7 @@ class GTKStyle extends SynthStyle implements GTKConstants { return font; } + @Override protected Font getFontForState(SynthContext context) { Font propFont = UIManager .getFont(context.getRegion().getName() + ".font"); @@ -1053,6 +1055,7 @@ class GTKStyle extends SynthStyle implements GTKConstants { this.size = size; } + @Override public void paintIcon(SynthContext context, Graphics g, int x, int y, int w, int h) { Icon icon = getIcon(context); @@ -1067,6 +1070,7 @@ class GTKStyle extends SynthStyle implements GTKConstants { } } + @Override public int getIconWidth(SynthContext context) { Icon icon = getIcon(context); @@ -1076,6 +1080,7 @@ class GTKStyle extends SynthStyle implements GTKConstants { return 0; } + @Override public int getIconHeight(SynthContext context) { Icon icon = getIcon(context); @@ -1135,6 +1140,7 @@ class GTKStyle extends SynthStyle implements GTKConstants { this.methodName = methodName; } + @Override @SuppressWarnings("deprecation") public Object createValue(UIDefaults table) { try { diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKStyleFactory.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKStyleFactory.java index 9683ba06788..4127e39c172 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKStyleFactory.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKStyleFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2025, 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 @@ -58,6 +58,7 @@ class GTKStyleFactory extends SynthStyleFactory { * @param c this parameter isn't used, may be null. * @param id of the region to get the style. */ + @Override public synchronized SynthStyle getStyle(JComponent c, Region id) { WidgetType wt = GTKEngine.getWidgetType(c, id); diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/Metacity.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/Metacity.java index 4f7d19355c8..6e8f64b457d 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/Metacity.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/Metacity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2025, 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 @@ -693,6 +693,7 @@ class Metacity implements SynthConstants { return new ImageIcon(context.getComponent().createImage(producer)).getImage(); } + @Override public int filterRGB(int x, int y, int rgb) { // Assume all rgb values are shades of gray double grayLevel = 2 * (rgb & 0xff) / 255.0; @@ -729,12 +730,16 @@ class Metacity implements SynthConstants { protected class TitlePaneLayout implements LayoutManager { + @Override public void addLayoutComponent(String name, Component c) {} + @Override public void removeLayoutComponent(Component c) {} + @Override public Dimension preferredLayoutSize(Container c) { return minimumLayoutSize(c); } + @Override public Dimension minimumLayoutSize(Container c) { JComponent titlePane = (JComponent)c; Container titlePaneParent = titlePane.getParent(); @@ -794,6 +799,7 @@ class Metacity implements SynthConstants { return new Dimension(width, height); } + @Override public void layoutContainer(Container c) { JComponent titlePane = (JComponent)c; Container titlePaneParent = titlePane.getParent(); @@ -1943,10 +1949,12 @@ class Metacity implements SynthConstants { return token; } + @Override public boolean hasMoreTokens() { return (token != null || super.hasMoreTokens()); } + @Override public String nextToken() { if (token != null) { String t = token; @@ -2000,18 +2008,22 @@ class Metacity implements SynthConstants { this.archeight = arch; } + @Override public double getX() { return (double)x; } + @Override public double getY() { return (double)y; } + @Override public double getWidth() { return (double)width; } + @Override public double getHeight() { return (double)height; } @@ -2024,10 +2036,12 @@ class Metacity implements SynthConstants { return (double)archeight; } + @Override public boolean isEmpty() { return false; // Not called } + @Override public Rectangle2D getBounds2D() { return null; // Not called } @@ -2036,10 +2050,12 @@ class Metacity implements SynthConstants { return corners; } + @Override public void setFrame(double x, double y, double w, double h) { // Not called } + @Override public boolean contains(double x, double y) { return false; // Not called } @@ -2048,14 +2064,17 @@ class Metacity implements SynthConstants { return 0; // Not called } + @Override public boolean intersects(double x, double y, double w, double h) { return false; // Not called } + @Override public boolean contains(double x, double y, double w, double h) { return false; // Not called } + @Override public PathIterator getPathIterator(AffineTransform at) { return new RoundishRectIterator(this, at); } @@ -2148,18 +2167,22 @@ class Metacity implements SynthConstants { } } + @Override public int getWindingRule() { return WIND_NON_ZERO; } + @Override public boolean isDone() { return index >= ctrlpts.length; } + @Override public void next() { index++; } + @Override public int currentSegment(float[] coords) { if (isDone()) { throw new NoSuchElementException("roundrect iterator out of bounds"); @@ -2176,6 +2199,7 @@ class Metacity implements SynthConstants { return types[index]; } + @Override public int currentSegment(double[] coords) { if (isDone()) { throw new NoSuchElementException("roundrect iterator out of bounds"); From 5141e1a4f4ef7499ddd8684469d8038fd75403d2 Mon Sep 17 00:00:00 2001 From: Anton Artemov Date: Mon, 15 Dec 2025 08:39:47 +0000 Subject: [PATCH 292/706] 8373497: SpinCriticalSection should use SpinYield Reviewed-by: dholmes, coleenp --- .../share/utilities/spinCriticalSection.cpp | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/src/hotspot/share/utilities/spinCriticalSection.cpp b/src/hotspot/share/utilities/spinCriticalSection.cpp index 0bbbc82c12b..4064c234e97 100644 --- a/src/hotspot/share/utilities/spinCriticalSection.cpp +++ b/src/hotspot/share/utilities/spinCriticalSection.cpp @@ -24,30 +24,19 @@ #include "runtime/atomicAccess.hpp" #include "utilities/spinCriticalSection.hpp" +#include "utilities/spinYield.hpp" void SpinCriticalSection::spin_acquire(volatile int* adr) { if (AtomicAccess::cmpxchg(adr, 0, 1) == 0) { return; // normal fast-path return } + SpinYield sy(4096, 5, millis_to_nanos(1)); + // Slow-path : We've encountered contention -- Spin/Yield/Block strategy. - int ctr = 0; - int Yields = 0; for (;;) { while (*adr != 0) { - ++ctr; - if ((ctr & 0xFFF) == 0 || !os::is_MP()) { - if (Yields > 5) { - os::naked_short_sleep(1); - } - else { - os::naked_yield(); - ++Yields; - } - } - else { - SpinPause(); - } + sy.wait(); } if (AtomicAccess::cmpxchg(adr, 0, 1) == 0) return; } From 895232fc65cab9ba3863b48cab27b688096a7435 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Jeli=C5=84ski?= Date: Mon, 15 Dec 2025 08:40:05 +0000 Subject: [PATCH 293/706] 8372731: Detailed authentication failure messages Reviewed-by: dfuchs, michaelm --- .../www/protocol/http/AuthenticationInfo.java | 8 +- .../protocol/http/BasicAuthentication.java | 6 +- .../protocol/http/DigestAuthentication.java | 58 +++--- .../www/protocol/http/HttpURLConnection.java | 60 +++++-- .../http/NegotiateAuthentication.java | 29 ++- .../http/ntlm/NTLMAuthentication.java | 15 +- .../protocol/http/ntlm/NTLMAuthSequence.java | 3 +- .../http/ntlm/NTLMAuthentication.java | 11 +- .../windows/native/libnet/NTLMAuthSequence.c | 4 + .../net/www/protocol/http/NTLMFailTest.java | 167 ++++++++++++++++++ 10 files changed, 276 insertions(+), 85 deletions(-) create mode 100644 test/jdk/sun/net/www/protocol/http/NTLMFailTest.java diff --git a/src/java.base/share/classes/sun/net/www/protocol/http/AuthenticationInfo.java b/src/java.base/share/classes/sun/net/www/protocol/http/AuthenticationInfo.java index f567d7bd643..9c9766e2ce2 100644 --- a/src/java.base/share/classes/sun/net/www/protocol/http/AuthenticationInfo.java +++ b/src/java.base/share/classes/sun/net/www/protocol/http/AuthenticationInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2025, 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,7 @@ package sun.net.www.protocol.http; +import java.io.IOException; import java.net.PasswordAuthentication; import java.net.URL; import java.util.HashMap; @@ -428,9 +429,10 @@ public abstract class AuthenticationInfo extends AuthCacheValue implements Clone * @param conn The connection to apply the header(s) to * @param p A source of header values for this connection, if needed. * @param raw The raw header field (if needed) - * @return true if all goes well, false if no headers were set. + * @throws IOException if no headers were set */ - public abstract boolean setHeaders(HttpURLConnection conn, HeaderParser p, String raw); + public abstract void setHeaders(HttpURLConnection conn, HeaderParser p, String raw) + throws IOException; /** * Check if the header indicates that the current auth. parameters are stale. diff --git a/src/java.base/share/classes/sun/net/www/protocol/http/BasicAuthentication.java b/src/java.base/share/classes/sun/net/www/protocol/http/BasicAuthentication.java index f008c185b5d..aa2a9625a01 100644 --- a/src/java.base/share/classes/sun/net/www/protocol/http/BasicAuthentication.java +++ b/src/java.base/share/classes/sun/net/www/protocol/http/BasicAuthentication.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, 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 @@ -125,15 +125,13 @@ final class BasicAuthentication extends AuthenticationInfo { * @param conn The connection to apply the header(s) to * @param p A source of header values for this connection, if needed. * @param raw The raw header values for this connection, if needed. - * @return true if all goes well, false if no headers were set. */ @Override - public boolean setHeaders(HttpURLConnection conn, HeaderParser p, String raw) { + public void setHeaders(HttpURLConnection conn, HeaderParser p, String raw) { // no need to synchronize here: // already locked by s.n.w.p.h.HttpURLConnection assert conn.isLockHeldByCurrentThread(); conn.setAuthenticationProperty(getHeaderName(), getHeaderValue(null,null)); - return true; } /** diff --git a/src/java.base/share/classes/sun/net/www/protocol/http/DigestAuthentication.java b/src/java.base/share/classes/sun/net/www/protocol/http/DigestAuthentication.java index 28d7bc5cf4e..87ea7c17085 100644 --- a/src/java.base/share/classes/sun/net/www/protocol/http/DigestAuthentication.java +++ b/src/java.base/share/classes/sun/net/www/protocol/http/DigestAuthentication.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, 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 @@ -321,7 +321,11 @@ final class DigestAuthentication extends AuthenticationInfo { */ @Override public String getHeaderValue(URL url, String method) { - return getHeaderValueImpl(url.getFile(), method); + try { + return getHeaderValueImpl(url.getFile(), method); + } catch (IOException _) { + return null; + } } /** @@ -339,7 +343,11 @@ final class DigestAuthentication extends AuthenticationInfo { * @return the value of the HTTP header this authentication wants set */ String getHeaderValue(String requestURI, String method) { - return getHeaderValueImpl(requestURI, method); + try { + return getHeaderValueImpl(requestURI, method); + } catch (IOException _) { + return null; + } } /** @@ -369,10 +377,11 @@ final class DigestAuthentication extends AuthenticationInfo { * @param conn The connection to apply the header(s) to * @param p A source of header values for this connection, if needed. * @param raw Raw header values for this connection, if needed. - * @return true if all goes well, false if no headers were set. + * @throws IOException if no headers were set */ @Override - public boolean setHeaders(HttpURLConnection conn, HeaderParser p, String raw) { + public void setHeaders(HttpURLConnection conn, HeaderParser p, String raw) + throws IOException { // no need to synchronize here: // already locked by s.n.w.p.h.HttpURLConnection assert conn.isLockHeldByCurrentThread(); @@ -380,14 +389,14 @@ final class DigestAuthentication extends AuthenticationInfo { params.setNonce (p.findValue("nonce")); params.setOpaque (p.findValue("opaque")); params.setQop (p.findValue("qop")); - params.setUserhash (Boolean.valueOf(p.findValue("userhash"))); + params.setUserhash (Boolean.parseBoolean(p.findValue("userhash"))); String charset = p.findValue("charset"); if (charset == null) { charset = "ISO_8859_1"; } else if (!charset.equalsIgnoreCase("UTF-8")) { // UTF-8 is only valid value. ISO_8859_1 represents default behavior // when the parameter is not set. - return false; + throw new IOException("Illegal charset in header"); } params.setCharset(charset.toUpperCase(Locale.ROOT)); @@ -405,7 +414,7 @@ final class DigestAuthentication extends AuthenticationInfo { } if (params.nonce == null || authMethod == null || pw == null || realm == null) { - return false; + throw new IOException("Server challenge incomplete"); } if (authMethod.length() >= 1) { // Method seems to get converted to all lower case elsewhere. @@ -415,8 +424,7 @@ final class DigestAuthentication extends AuthenticationInfo { + authMethod.substring(1).toLowerCase(Locale.ROOT); } - if (!setAlgorithmNames(p, params)) - return false; + setAlgorithmNames(p, params); // If authQop is true, then the server is doing RFC2617 and // has offered qop=auth. We do not support any other modes @@ -426,20 +434,17 @@ final class DigestAuthentication extends AuthenticationInfo { params.setNewCnonce(); } - String value = getHeaderValueImpl (uri, method); - if (value != null) { - conn.setAuthenticationProperty(getHeaderName(), value); - return true; - } else { - return false; - } + String value = getHeaderValueImpl(uri, method); + assert value != null; + conn.setAuthenticationProperty(getHeaderName(), value); } // Algorithm name is stored in two separate fields (of Paramaeters) // This allows for variations in digest algorithm name (aliases) // and also allow for the -sess variant defined in HTTP Digest protocol - // returns false if algorithm not supported - private static boolean setAlgorithmNames(HeaderParser p, Parameters params) { + // throws IOException if algorithm not supported + private static void setAlgorithmNames(HeaderParser p, Parameters params) + throws IOException { String algorithm = p.findValue("algorithm"); String digestName = algorithm; if (algorithm == null || algorithm.isEmpty()) { @@ -459,18 +464,17 @@ final class DigestAuthentication extends AuthenticationInfo { var oid = KnownOIDs.findMatch(digestName); if (oid == null) { log("unknown algorithm: " + algorithm); - return false; + throw new IOException("Unknown algorithm: " + algorithm); } digestName = oid.stdName(); params.setAlgorithm (algorithm); params.setDigestName (digestName); - return true; } /* Calculate the Authorization header field given the request URI * and based on the authorization information in params */ - private String getHeaderValueImpl (String uri, String method) { + private String getHeaderValueImpl (String uri, String method) throws IOException { String response; char[] passwd = pw.getPassword(); boolean qop = params.authQop(); @@ -479,11 +483,7 @@ final class DigestAuthentication extends AuthenticationInfo { String nonce = params.getNonce (); String algorithm = params.getAlgorithm (); String digest = params.getDigestName (); - try { - validateDigest(digest); - } catch (IOException e) { - return null; - } + validateDigest(digest); Charset charset = params.getCharset(); boolean userhash = params.getUserhash (); params.incrementNC (); @@ -505,7 +505,7 @@ final class DigestAuthentication extends AuthenticationInfo { digest, session, charset); } catch (CharacterCodingException | NoSuchAlgorithmException ex) { log(ex.getMessage()); - return null; + throw new IOException("Failed to compute digest", ex); } String ncfield = "\""; @@ -534,7 +534,7 @@ final class DigestAuthentication extends AuthenticationInfo { } } catch (CharacterCodingException | NoSuchAlgorithmException ex) { log(ex.getMessage()); - return null; + throw new IOException("Failed to compute user hash", ex); } String value = authMethod diff --git a/src/java.base/share/classes/sun/net/www/protocol/http/HttpURLConnection.java b/src/java.base/share/classes/sun/net/www/protocol/http/HttpURLConnection.java index aee9670ce26..89ad0cc48ed 100644 --- a/src/java.base/share/classes/sun/net/www/protocol/http/HttpURLConnection.java +++ b/src/java.base/share/classes/sun/net/www/protocol/http/HttpURLConnection.java @@ -61,6 +61,7 @@ import java.util.Set; import java.util.StringJoiner; import jdk.internal.access.JavaNetHttpCookieAccess; import jdk.internal.access.SharedSecrets; +import jdk.internal.util.Exceptions; import sun.net.NetProperties; import sun.net.NetworkClient; import sun.net.util.IPAddressUtil; @@ -1469,16 +1470,29 @@ public class HttpURLConnection extends java.net.HttpURLConnection { /* in this case, only one header field will be present */ String raw = responses.findValue ("Proxy-Authenticate"); reset (); - if (!proxyAuthentication.setHeaders(this, - authhdr.headerParser(), raw)) { + try { + proxyAuthentication.setHeaders(this, + authhdr.headerParser(), raw); + } catch (IOException ex) { disconnectInternal(); - throw new IOException ("Authentication failure"); + if (Exceptions.enhancedNonSocketExceptions()) { + throw new IOException ("Authentication failure", ex); + } else { + throw new IOException ("Authentication failure"); + } } - if (serverAuthentication != null && srvHdr != null && - !serverAuthentication.setHeaders(this, - srvHdr.headerParser(), raw)) { - disconnectInternal (); - throw new IOException ("Authentication failure"); + if (serverAuthentication != null && srvHdr != null) { + try { + serverAuthentication.setHeaders(this, + srvHdr.headerParser(), raw); + } catch (IOException ex) { + disconnectInternal(); + if (Exceptions.enhancedNonSocketExceptions()) { + throw new IOException ("Authentication failure", ex); + } else { + throw new IOException ("Authentication failure"); + } + } } authObj = null; doingNTLMp2ndStage = false; @@ -1557,9 +1571,15 @@ public class HttpURLConnection extends java.net.HttpURLConnection { } else { reset (); /* header not used for ntlm */ - if (!serverAuthentication.setHeaders(this, null, raw)) { + try { + serverAuthentication.setHeaders(this, null, raw); + } catch (IOException ex) { disconnectWeb(); - throw new IOException ("Authentication failure"); + if (Exceptions.enhancedNonSocketExceptions()) { + throw new IOException ("Authentication failure", ex); + } else { + throw new IOException ("Authentication failure"); + } } doingNTLM2ndStage = false; authObj = null; @@ -1935,10 +1955,16 @@ public class HttpURLConnection extends java.net.HttpURLConnection { } else { String raw = responses.findValue ("Proxy-Authenticate"); reset (); - if (!proxyAuthentication.setHeaders(this, - authhdr.headerParser(), raw)) { + try { + proxyAuthentication.setHeaders(this, + authhdr.headerParser(), raw); + } catch (IOException ex) { disconnectInternal(); - throw new IOException ("Authentication failure"); + if (Exceptions.enhancedNonSocketExceptions()) { + throw new IOException ("Authentication failure", ex); + } else { + throw new IOException ("Authentication failure"); + } } authObj = null; doingNTLMp2ndStage = false; @@ -2201,7 +2227,9 @@ public class HttpURLConnection extends java.net.HttpURLConnection { }; } if (ret != null) { - if (!ret.setHeaders(this, p, raw)) { + try { + ret.setHeaders(this, p, raw); + } catch (IOException e) { ret.disposeContext(); ret = null; } @@ -2358,7 +2386,9 @@ public class HttpURLConnection extends java.net.HttpURLConnection { } } if (ret != null ) { - if (!ret.setHeaders(this, p, raw)) { + try { + ret.setHeaders(this, p, raw); + } catch (IOException e) { ret.disposeContext(); ret = null; } diff --git a/src/java.base/share/classes/sun/net/www/protocol/http/NegotiateAuthentication.java b/src/java.base/share/classes/sun/net/www/protocol/http/NegotiateAuthentication.java index c27d866f5ef..c016b0dae29 100644 --- a/src/java.base/share/classes/sun/net/www/protocol/http/NegotiateAuthentication.java +++ b/src/java.base/share/classes/sun/net/www/protocol/http/NegotiateAuthentication.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -168,29 +168,24 @@ final class NegotiateAuthentication extends AuthenticationInfo { * @param p A source of header values for this connection, not used because * HeaderParser converts the fields to lower case, use raw instead * @param raw The raw header field. - * @return true if all goes well, false if no headers were set. + * @throws IOException if no headers were set */ @Override - public boolean setHeaders(HttpURLConnection conn, HeaderParser p, String raw) { + public void setHeaders(HttpURLConnection conn, HeaderParser p, String raw) throws IOException { // no need to synchronize here: // already locked by s.n.w.p.h.HttpURLConnection assert conn.isLockHeldByCurrentThread(); - try { - String response; - byte[] incoming = null; - String[] parts = raw.split("\\s+"); - if (parts.length > 1) { - incoming = Base64.getDecoder().decode(parts[1]); - } - response = hci.scheme + " " + Base64.getEncoder().encodeToString( - incoming==null?firstToken():nextToken(incoming)); - - conn.setAuthenticationProperty(getHeaderName(), response); - return true; - } catch (IOException e) { - return false; + String response; + byte[] incoming = null; + String[] parts = raw.split("\\s+"); + if (parts.length > 1) { + incoming = Base64.getDecoder().decode(parts[1]); } + response = hci.scheme + " " + Base64.getEncoder().encodeToString( + incoming==null?firstToken():nextToken(incoming)); + + conn.setAuthenticationProperty(getHeaderName(), response); } /** diff --git a/src/java.base/unix/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java b/src/java.base/unix/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java index dc56abb86df..efe72fc760f 100644 --- a/src/java.base/unix/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java +++ b/src/java.base/unix/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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,7 +35,6 @@ import java.net.URL; import java.security.GeneralSecurityException; import java.util.Base64; import java.util.Locale; -import java.util.Properties; import sun.net.www.HeaderParser; import sun.net.www.protocol.http.AuthenticationInfo; @@ -203,10 +202,10 @@ public final class NTLMAuthentication extends AuthenticationInfo { * @param p A source of header values for this connection, not used because * HeaderParser converts the fields to lower case, use raw instead * @param raw The raw header field. - * @return true if all goes well, false if no headers were set. + * @throws IOException if no headers were set */ @Override - public boolean setHeaders(HttpURLConnection conn, HeaderParser p, String raw) { + public void setHeaders(HttpURLConnection conn, HeaderParser p, String raw) throws IOException { // no need to synchronize here: // already locked by s.n.w.p.h.HttpURLConnection assert conn.isLockHeldByCurrentThread(); @@ -220,9 +219,8 @@ public final class NTLMAuthentication extends AuthenticationInfo { response = buildType3Msg (msg); } conn.setAuthenticationProperty(getHeaderName(), response); - return true; - } catch (IOException | GeneralSecurityException e) { - return false; + } catch (GeneralSecurityException e) { + throw new IOException(e); } } @@ -232,8 +230,7 @@ public final class NTLMAuthentication extends AuthenticationInfo { return result; } - private String buildType3Msg (String challenge) throws GeneralSecurityException, - IOException { + private String buildType3Msg (String challenge) throws GeneralSecurityException { /* First decode the type2 message to get the server nonce */ /* nonce is located at type2[24] for 8 bytes */ diff --git a/src/java.base/windows/classes/sun/net/www/protocol/http/ntlm/NTLMAuthSequence.java b/src/java.base/windows/classes/sun/net/www/protocol/http/ntlm/NTLMAuthSequence.java index 517b4801e2c..76890045724 100644 --- a/src/java.base/windows/classes/sun/net/www/protocol/http/ntlm/NTLMAuthSequence.java +++ b/src/java.base/windows/classes/sun/net/www/protocol/http/ntlm/NTLMAuthSequence.java @@ -91,6 +91,7 @@ public class NTLMAuthSequence { private native long getCredentialsHandle (String user, String domain, String password); - private native byte[] getNextToken (long crdHandle, byte[] lastToken, Status returned); + private native byte[] getNextToken (long crdHandle, byte[] lastToken, Status returned) + throws IOException; } diff --git a/src/java.base/windows/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java b/src/java.base/windows/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java index a7056082e12..75a9dc027b1 100644 --- a/src/java.base/windows/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java +++ b/src/java.base/windows/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2025, 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,9 +26,7 @@ package sun.net.www.protocol.http.ntlm; import java.io.IOException; -import java.net.InetAddress; import java.net.PasswordAuthentication; -import java.net.UnknownHostException; import java.net.URL; import java.util.Locale; import sun.net.NetProperties; @@ -204,10 +202,10 @@ public final class NTLMAuthentication extends AuthenticationInfo { * @param p A source of header values for this connection, not used because * HeaderParser converts the fields to lower case, use raw instead * @param raw The raw header field. - * @return true if all goes well, false if no headers were set. + * @throws IOException if no headers were set */ @Override - public boolean setHeaders(HttpURLConnection conn, HeaderParser p, String raw) { + public void setHeaders(HttpURLConnection conn, HeaderParser p, String raw) throws IOException { // no need to synchronize here: // already locked by s.n.w.p.h.HttpURLConnection @@ -224,10 +222,9 @@ public final class NTLMAuthentication extends AuthenticationInfo { if (seq.isComplete()) { conn.authObj(null); } - return true; } catch (IOException e) { conn.authObj(null); - return false; + throw e; } } } diff --git a/src/java.base/windows/native/libnet/NTLMAuthSequence.c b/src/java.base/windows/native/libnet/NTLMAuthSequence.c index 507409e0ae6..c058c8ad234 100644 --- a/src/java.base/windows/native/libnet/NTLMAuthSequence.c +++ b/src/java.base/windows/native/libnet/NTLMAuthSequence.c @@ -230,6 +230,8 @@ JNIEXPORT jbyteArray JNICALL Java_sun_net_www_protocol_http_ntlm_NTLMAuthSequenc } if (ss < 0) { + SetLastError(ss); + JNU_ThrowIOExceptionWithLastError(env, "InitializeSecurityContext"); endSequence (pCred, pCtx, env, status); return 0; } @@ -238,6 +240,8 @@ JNIEXPORT jbyteArray JNICALL Java_sun_net_www_protocol_http_ntlm_NTLMAuthSequenc ss = CompleteAuthToken( pCtx, &OutBuffDesc ); if (ss < 0) { + SetLastError(ss); + JNU_ThrowIOExceptionWithLastError(env, "CompleteAuthToken"); endSequence (pCred, pCtx, env, status); return 0; } diff --git a/test/jdk/sun/net/www/protocol/http/NTLMFailTest.java b/test/jdk/sun/net/www/protocol/http/NTLMFailTest.java new file mode 100644 index 00000000000..86db3d400da --- /dev/null +++ b/test/jdk/sun/net/www/protocol/http/NTLMFailTest.java @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2025, 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 8372731 + * @library /test/lib + * @run main/othervm NTLMFailTest + * @run main/othervm -Djdk.includeInExceptions= NTLMFailTest + * @summary check that the Authentication failure exception + * honors the jdk.includeInExceptions setting + */ + +import jdk.test.lib.net.HttpHeaderParser; +import jdk.test.lib.net.URIBuilder; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.Authenticator; +import java.net.HttpURLConnection; +import java.net.InetAddress; +import java.net.PasswordAuthentication; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.URL; + +public class NTLMFailTest { + + static final int BODY_LEN = 8192; + + static final String RESP_SERVER_AUTH = + "HTTP/1.1 401 Unauthorized\r\n" + + "WWW-Authenticate: NTLM\r\n" + + "Connection: close\r\n" + + "Content-Length: " + BODY_LEN + "\r\n" + + "\r\n"; + + static final String RESP_SERVER_NTLM = + "HTTP/1.1 401 Unauthorized\r\n" + + "WWW-Authenticate: NTLM InvalidChallenge\r\n" + + "Connection: Keep-Alive\r\n" + + "Content-Length: " + BODY_LEN + "\r\n" + + "\r\n"; + + public static void main(String[] args) throws Exception { + Authenticator.setDefault(new TestAuthenticator()); + try (NTLMServer server = startServer(new ServerSocket(0, 0, InetAddress.getLoopbackAddress()))) { + URL url = URIBuilder.newBuilder() + .scheme("http") + .loopback() + .port(server.getLocalPort()) + .path("/") + .toURLUnchecked(); + HttpURLConnection uc = (HttpURLConnection) url.openConnection(); + uc.setRequestMethod("HEAD"); + uc.getInputStream().readAllBytes(); + throw new RuntimeException("Expected exception was not thrown"); + } catch (IOException e) { + if (e.getMessage().contains("Authentication failure")) { + System.err.println("Got expected exception:"); + e.printStackTrace(); + if (System.getProperty("jdk.includeInExceptions") == null) { + // detailed message enabled by default + if (e.getCause() == null) { + throw new RuntimeException("Expected a detailed exception", e); + } + // no checks on the detailed message; it's platform-specific and may be translated + } else { + // detailed message disabled + if (e.getCause() != null) { + throw new RuntimeException("Unexpected detailed exception", e); + } + } + } else { + throw e; + } + } + } + + static class NTLMServer extends Thread implements AutoCloseable { + final ServerSocket ss; + volatile boolean closed; + + NTLMServer(ServerSocket serverSS) { + super(); + setDaemon(true); + this.ss = serverSS; + } + + int getLocalPort() { return ss.getLocalPort(); } + + @Override + public void run() { + boolean doing2ndStageNTLM = false; + while (!closed) { + try { + Socket s = ss.accept(); + InputStream is = s.getInputStream(); + OutputStream os = s.getOutputStream(); + doServer(is, os, doing2ndStageNTLM); + if (!doing2ndStageNTLM) { + doing2ndStageNTLM = true; + } else { + os.close(); + } + } catch (IOException ioe) { + if (!closed) { + ioe.printStackTrace(); + } + } + } + } + + @Override + public void close() { + if (closed) return; + synchronized(this) { + if (closed) return; + closed = true; + } + try { ss.close(); } catch (IOException x) { }; + } + } + + static NTLMServer startServer(ServerSocket serverSS) { + NTLMServer server = new NTLMServer(serverSS); + server.start(); + return server; + } + + static void doServer(InputStream is, OutputStream os, boolean doing2ndStageNTLM) throws IOException { + if (!doing2ndStageNTLM) { + new HttpHeaderParser(is); + os.write(RESP_SERVER_AUTH.getBytes("ASCII")); + } else { + new HttpHeaderParser(is); + os.write(RESP_SERVER_NTLM.getBytes("ASCII")); + } + } + + static class TestAuthenticator extends Authenticator { + protected PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication("test", "secret".toCharArray()); + } + } +} From ad6611a9a3fd5f9cf8b73ce3ccf976187e344654 Mon Sep 17 00:00:00 2001 From: Fredrik Bredberg Date: Mon, 15 Dec 2025 08:55:08 +0000 Subject: [PATCH 294/706] 8371347: Move the ObjectMonitorTable to a separate new file Reviewed-by: dholmes, coleenp --- .../share/runtime/objectMonitorTable.cpp | 308 ++++++++++++++++++ .../share/runtime/objectMonitorTable.hpp | 77 +++++ src/hotspot/share/runtime/synchronizer.cpp | 286 +--------------- 3 files changed, 386 insertions(+), 285 deletions(-) create mode 100644 src/hotspot/share/runtime/objectMonitorTable.cpp create mode 100644 src/hotspot/share/runtime/objectMonitorTable.hpp diff --git a/src/hotspot/share/runtime/objectMonitorTable.cpp b/src/hotspot/share/runtime/objectMonitorTable.cpp new file mode 100644 index 00000000000..9b522720a28 --- /dev/null +++ b/src/hotspot/share/runtime/objectMonitorTable.cpp @@ -0,0 +1,308 @@ +/* + * Copyright (c) 2024, 2025, 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. + * + */ + +#include "logging/log.hpp" +#include "runtime/interfaceSupport.inline.hpp" +#include "runtime/javaThread.hpp" +#include "runtime/mutexLocker.hpp" +#include "runtime/objectMonitorTable.hpp" +#include "runtime/safepoint.hpp" +#include "runtime/thread.hpp" +#include "runtime/timerTrace.hpp" +#include "runtime/trimNativeHeap.hpp" +#include "utilities/concurrentHashTableTasks.inline.hpp" +#include "utilities/globalDefinitions.hpp" + +// ----------------------------------------------------------------------------- +// ConcurrentHashTable storing links from objects to ObjectMonitors + +using ConcurrentTable = ConcurrentHashTable; + +static ConcurrentTable* _table = nullptr; +static volatile size_t _items_count = 0; +static size_t _table_size = 0; +static volatile bool _resize = false; + +class ObjectMonitorTableConfig : public AllStatic { + public: + using Value = ObjectMonitor*; + static uintx get_hash(Value const& value, bool* is_dead) { + return (uintx)value->hash(); + } + static void* allocate_node(void* context, size_t size, Value const& value) { + ObjectMonitorTable::inc_items_count(); + return AllocateHeap(size, mtObjectMonitor); + }; + static void free_node(void* context, void* memory, Value const& value) { + ObjectMonitorTable::dec_items_count(); + FreeHeap(memory); + } +}; + +class Lookup : public StackObj { + oop _obj; + + public: + explicit Lookup(oop obj) : _obj(obj) {} + + uintx get_hash() const { + uintx hash = _obj->mark().hash(); + assert(hash != 0, "should have a hash"); + return hash; + } + + bool equals(ObjectMonitor** value) { + assert(*value != nullptr, "must be"); + return (*value)->object_refers_to(_obj); + } + + bool is_dead(ObjectMonitor** value) { + assert(*value != nullptr, "must be"); + return false; + } +}; + +class LookupMonitor : public StackObj { + ObjectMonitor* _monitor; + + public: + explicit LookupMonitor(ObjectMonitor* monitor) : _monitor(monitor) {} + + uintx get_hash() const { + return _monitor->hash(); + } + + bool equals(ObjectMonitor** value) { + return (*value) == _monitor; + } + + bool is_dead(ObjectMonitor** value) { + assert(*value != nullptr, "must be"); + return (*value)->object_is_dead(); + } +}; + +void ObjectMonitorTable::inc_items_count() { + AtomicAccess::inc(&_items_count, memory_order_relaxed); +} + +void ObjectMonitorTable::dec_items_count() { + AtomicAccess::dec(&_items_count, memory_order_relaxed); +} + +double ObjectMonitorTable::get_load_factor() { + size_t count = AtomicAccess::load(&_items_count); + return (double)count / (double)_table_size; +} + +size_t ObjectMonitorTable::table_size(Thread* current) { + return ((size_t)1) << _table->get_size_log2(current); +} + +size_t ObjectMonitorTable::max_log_size() { + // TODO[OMTable]: Evaluate the max size. + // TODO[OMTable]: Need to fix init order to use Universe::heap()->max_capacity(); + // Using MaxHeapSize directly this early may be wrong, and there + // are definitely rounding errors (alignment). + const size_t max_capacity = MaxHeapSize; + const size_t min_object_size = CollectedHeap::min_dummy_object_size() * HeapWordSize; + const size_t max_objects = max_capacity / MAX2(MinObjAlignmentInBytes, checked_cast(min_object_size)); + const size_t log_max_objects = log2i_graceful(max_objects); + + return MAX2(MIN2(SIZE_BIG_LOG2, log_max_objects), min_log_size()); +} + +// ~= log(AvgMonitorsPerThreadEstimate default) +size_t ObjectMonitorTable::min_log_size() { + return 10; +} + +template +size_t ObjectMonitorTable::clamp_log_size(V log_size) { + return MAX2(MIN2(log_size, checked_cast(max_log_size())), checked_cast(min_log_size())); +} + +size_t ObjectMonitorTable::initial_log_size() { + const size_t estimate = log2i(MAX2(os::processor_count(), 1)) + log2i(MAX2(AvgMonitorsPerThreadEstimate, size_t(1))); + return clamp_log_size(estimate); +} + +size_t ObjectMonitorTable::grow_hint() { + return ConcurrentTable::DEFAULT_GROW_HINT; +} + +void ObjectMonitorTable::create() { + _table = new ConcurrentTable(initial_log_size(), max_log_size(), grow_hint()); + _items_count = 0; + _table_size = table_size(Thread::current()); + _resize = false; +} + +void ObjectMonitorTable::verify_monitor_get_result(oop obj, ObjectMonitor* monitor) { +#ifdef ASSERT + if (SafepointSynchronize::is_at_safepoint()) { + bool has_monitor = obj->mark().has_monitor(); + assert(has_monitor == (monitor != nullptr), + "Inconsistency between markWord and ObjectMonitorTable has_monitor: %s monitor: " PTR_FORMAT, + BOOL_TO_STR(has_monitor), p2i(monitor)); + } +#endif +} + +ObjectMonitor* ObjectMonitorTable::monitor_get(Thread* current, oop obj) { + ObjectMonitor* result = nullptr; + Lookup lookup_f(obj); + auto found_f = [&](ObjectMonitor** found) { + assert((*found)->object_peek() == obj, "must be"); + result = *found; + }; + _table->get(current, lookup_f, found_f); + verify_monitor_get_result(obj, result); + return result; +} + +void ObjectMonitorTable::try_notify_grow() { + if (!_table->is_max_size_reached() && !AtomicAccess::load(&_resize)) { + AtomicAccess::store(&_resize, true); + if (Service_lock->try_lock()) { + Service_lock->notify(); + Service_lock->unlock(); + } + } +} + +bool ObjectMonitorTable::should_grow() { + return get_load_factor() > GROW_LOAD_FACTOR && !_table->is_max_size_reached(); +} + +bool ObjectMonitorTable::should_resize() { + return should_grow() || should_shrink() || AtomicAccess::load(&_resize); +} + +template +bool ObjectMonitorTable::run_task(JavaThread* current, Task& task, const char* task_name, Args&... args) { + if (task.prepare(current)) { + log_trace(monitortable)("Started to %s", task_name); + TraceTime timer(task_name, TRACETIME_LOG(Debug, monitortable, perf)); + while (task.do_task(current, args...)) { + task.pause(current); + { + ThreadBlockInVM tbivm(current); + } + task.cont(current); + } + task.done(current); + return true; + } + return false; +} + +bool ObjectMonitorTable::grow(JavaThread* current) { + ConcurrentTable::GrowTask grow_task(_table); + if (run_task(current, grow_task, "Grow")) { + _table_size = table_size(current); + log_info(monitortable)("Grown to size: %zu", _table_size); + return true; + } + return false; +} + +bool ObjectMonitorTable::clean(JavaThread* current) { + ConcurrentTable::BulkDeleteTask clean_task(_table); + auto is_dead = [&](ObjectMonitor** monitor) { + return (*monitor)->object_is_dead(); + }; + auto do_nothing = [&](ObjectMonitor** monitor) {}; + NativeHeapTrimmer::SuspendMark sm("ObjectMonitorTable"); + return run_task(current, clean_task, "Clean", is_dead, do_nothing); +} + +bool ObjectMonitorTable::resize(JavaThread* current) { + LogTarget(Info, monitortable) lt; + bool success = false; + + if (should_grow()) { + lt.print("Start growing with load factor %f", get_load_factor()); + success = grow(current); + } else { + if (!_table->is_max_size_reached() && AtomicAccess::load(&_resize)) { + lt.print("WARNING: Getting resize hints with load factor %f", get_load_factor()); + } + lt.print("Start cleaning with load factor %f", get_load_factor()); + success = clean(current); + } + + AtomicAccess::store(&_resize, false); + + return success; +} + +ObjectMonitor* ObjectMonitorTable::monitor_put_get(Thread* current, ObjectMonitor* monitor, oop obj) { + // Enter the monitor into the concurrent hashtable. + ObjectMonitor* result = monitor; + Lookup lookup_f(obj); + auto found_f = [&](ObjectMonitor** found) { + assert((*found)->object_peek() == obj, "must be"); + result = *found; + }; + bool grow; + _table->insert_get(current, lookup_f, monitor, found_f, &grow); + verify_monitor_get_result(obj, result); + if (grow) { + try_notify_grow(); + } + return result; +} + +bool ObjectMonitorTable::remove_monitor_entry(Thread* current, ObjectMonitor* monitor) { + LookupMonitor lookup_f(monitor); + return _table->remove(current, lookup_f); +} + +bool ObjectMonitorTable::contains_monitor(Thread* current, ObjectMonitor* monitor) { + LookupMonitor lookup_f(monitor); + bool result = false; + auto found_f = [&](ObjectMonitor** found) { + result = true; + }; + _table->get(current, lookup_f, found_f); + return result; +} + +void ObjectMonitorTable::print_on(outputStream* st) { + auto printer = [&] (ObjectMonitor** entry) { + ObjectMonitor* om = *entry; + oop obj = om->object_peek(); + st->print("monitor=" PTR_FORMAT ", ", p2i(om)); + st->print("object=" PTR_FORMAT, p2i(obj)); + assert(obj->mark().hash() == om->hash(), "hash must match"); + st->cr(); + return true; + }; + if (SafepointSynchronize::is_at_safepoint()) { + _table->do_safepoint_scan(printer); + } else { + _table->do_scan(Thread::current(), printer); + } +} diff --git a/src/hotspot/share/runtime/objectMonitorTable.hpp b/src/hotspot/share/runtime/objectMonitorTable.hpp new file mode 100644 index 00000000000..146468d46b2 --- /dev/null +++ b/src/hotspot/share/runtime/objectMonitorTable.hpp @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2024, 2025, 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. + * + */ + +#ifndef SHARE_RUNTIME_OBJECTMONITORTABLE_HPP +#define SHARE_RUNTIME_OBJECTMONITORTABLE_HPP + +#include "memory/allStatic.hpp" +#include "oops/oopsHierarchy.hpp" +#include "utilities/globalDefinitions.hpp" + +class JavaThread; +class ObjectMonitor; +class ObjectMonitorTableConfig; +class outputStream; +class Thread; + +class ObjectMonitorTable : AllStatic { + friend class ObjectMonitorTableConfig; + + private: + static void inc_items_count(); + static void dec_items_count(); + static double get_load_factor(); + static size_t table_size(Thread* current); + static size_t max_log_size(); + static size_t min_log_size(); + + template + static size_t clamp_log_size(V log_size); + static size_t initial_log_size(); + static size_t grow_hint(); + + public: + static void create(); + static void verify_monitor_get_result(oop obj, ObjectMonitor* monitor); + static ObjectMonitor* monitor_get(Thread* current, oop obj); + static void try_notify_grow(); + static bool should_shrink() { return false; } // Not implemented + + static constexpr double GROW_LOAD_FACTOR = 0.75; + + static bool should_grow(); + static bool should_resize(); + + template + static bool run_task(JavaThread* current, Task& task, const char* task_name, Args&... args); + static bool grow(JavaThread* current); + static bool clean(JavaThread* current); + static bool resize(JavaThread* current); + static ObjectMonitor* monitor_put_get(Thread* current, ObjectMonitor* monitor, oop obj); + static bool remove_monitor_entry(Thread* current, ObjectMonitor* monitor); + static bool contains_monitor(Thread* current, ObjectMonitor* monitor); + static void print_on(outputStream* st); +}; + +#endif // SHARE_RUNTIME_OBJECTMONITORTABLE_HPP diff --git a/src/hotspot/share/runtime/synchronizer.cpp b/src/hotspot/share/runtime/synchronizer.cpp index fe95320c574..fde1aa50400 100644 --- a/src/hotspot/share/runtime/synchronizer.cpp +++ b/src/hotspot/share/runtime/synchronizer.cpp @@ -44,6 +44,7 @@ #include "runtime/lockStack.inline.hpp" #include "runtime/mutexLocker.hpp" #include "runtime/objectMonitor.inline.hpp" +#include "runtime/objectMonitorTable.hpp" #include "runtime/os.inline.hpp" #include "runtime/osThread.hpp" #include "runtime/safepointMechanism.inline.hpp" @@ -1470,291 +1471,6 @@ void ObjectSynchronizer::log_in_use_monitor_details(outputStream* out, bool log_ out->flush(); } -// ----------------------------------------------------------------------------- -// ConcurrentHashTable storing links from objects to ObjectMonitors -class ObjectMonitorTable : AllStatic { - struct Config { - using Value = ObjectMonitor*; - static uintx get_hash(Value const& value, bool* is_dead) { - return (uintx)value->hash(); - } - static void* allocate_node(void* context, size_t size, Value const& value) { - ObjectMonitorTable::inc_items_count(); - return AllocateHeap(size, mtObjectMonitor); - }; - static void free_node(void* context, void* memory, Value const& value) { - ObjectMonitorTable::dec_items_count(); - FreeHeap(memory); - } - }; - using ConcurrentTable = ConcurrentHashTable; - - static ConcurrentTable* _table; - static volatile size_t _items_count; - static size_t _table_size; - static volatile bool _resize; - - class Lookup : public StackObj { - oop _obj; - - public: - explicit Lookup(oop obj) : _obj(obj) {} - - uintx get_hash() const { - uintx hash = _obj->mark().hash(); - assert(hash != 0, "should have a hash"); - return hash; - } - - bool equals(ObjectMonitor** value) { - assert(*value != nullptr, "must be"); - return (*value)->object_refers_to(_obj); - } - - bool is_dead(ObjectMonitor** value) { - assert(*value != nullptr, "must be"); - return false; - } - }; - - class LookupMonitor : public StackObj { - ObjectMonitor* _monitor; - - public: - explicit LookupMonitor(ObjectMonitor* monitor) : _monitor(monitor) {} - - uintx get_hash() const { - return _monitor->hash(); - } - - bool equals(ObjectMonitor** value) { - return (*value) == _monitor; - } - - bool is_dead(ObjectMonitor** value) { - assert(*value != nullptr, "must be"); - return (*value)->object_is_dead(); - } - }; - - static void inc_items_count() { - AtomicAccess::inc(&_items_count, memory_order_relaxed); - } - - static void dec_items_count() { - AtomicAccess::dec(&_items_count, memory_order_relaxed); - } - - static double get_load_factor() { - size_t count = AtomicAccess::load(&_items_count); - return (double)count / (double)_table_size; - } - - static size_t table_size(Thread* current = Thread::current()) { - return ((size_t)1) << _table->get_size_log2(current); - } - - static size_t max_log_size() { - // TODO[OMTable]: Evaluate the max size. - // TODO[OMTable]: Need to fix init order to use Universe::heap()->max_capacity(); - // Using MaxHeapSize directly this early may be wrong, and there - // are definitely rounding errors (alignment). - const size_t max_capacity = MaxHeapSize; - const size_t min_object_size = CollectedHeap::min_dummy_object_size() * HeapWordSize; - const size_t max_objects = max_capacity / MAX2(MinObjAlignmentInBytes, checked_cast(min_object_size)); - const size_t log_max_objects = log2i_graceful(max_objects); - - return MAX2(MIN2(SIZE_BIG_LOG2, log_max_objects), min_log_size()); - } - - static size_t min_log_size() { - // ~= log(AvgMonitorsPerThreadEstimate default) - return 10; - } - - template - static size_t clamp_log_size(V log_size) { - return MAX2(MIN2(log_size, checked_cast(max_log_size())), checked_cast(min_log_size())); - } - - static size_t initial_log_size() { - const size_t estimate = log2i(MAX2(os::processor_count(), 1)) + log2i(MAX2(AvgMonitorsPerThreadEstimate, size_t(1))); - return clamp_log_size(estimate); - } - - static size_t grow_hint () { - return ConcurrentTable::DEFAULT_GROW_HINT; - } - - public: - static void create() { - _table = new ConcurrentTable(initial_log_size(), max_log_size(), grow_hint()); - _items_count = 0; - _table_size = table_size(); - _resize = false; - } - - static void verify_monitor_get_result(oop obj, ObjectMonitor* monitor) { -#ifdef ASSERT - if (SafepointSynchronize::is_at_safepoint()) { - bool has_monitor = obj->mark().has_monitor(); - assert(has_monitor == (monitor != nullptr), - "Inconsistency between markWord and ObjectMonitorTable has_monitor: %s monitor: " PTR_FORMAT, - BOOL_TO_STR(has_monitor), p2i(monitor)); - } -#endif - } - - static ObjectMonitor* monitor_get(Thread* current, oop obj) { - ObjectMonitor* result = nullptr; - Lookup lookup_f(obj); - auto found_f = [&](ObjectMonitor** found) { - assert((*found)->object_peek() == obj, "must be"); - result = *found; - }; - _table->get(current, lookup_f, found_f); - verify_monitor_get_result(obj, result); - return result; - } - - static void try_notify_grow() { - if (!_table->is_max_size_reached() && !AtomicAccess::load(&_resize)) { - AtomicAccess::store(&_resize, true); - if (Service_lock->try_lock()) { - Service_lock->notify(); - Service_lock->unlock(); - } - } - } - - static bool should_shrink() { - // Not implemented; - return false; - } - - static constexpr double GROW_LOAD_FACTOR = 0.75; - - static bool should_grow() { - return get_load_factor() > GROW_LOAD_FACTOR && !_table->is_max_size_reached(); - } - - static bool should_resize() { - return should_grow() || should_shrink() || AtomicAccess::load(&_resize); - } - - template - static bool run_task(JavaThread* current, Task& task, const char* task_name, Args&... args) { - if (task.prepare(current)) { - log_trace(monitortable)("Started to %s", task_name); - TraceTime timer(task_name, TRACETIME_LOG(Debug, monitortable, perf)); - while (task.do_task(current, args...)) { - task.pause(current); - { - ThreadBlockInVM tbivm(current); - } - task.cont(current); - } - task.done(current); - return true; - } - return false; - } - - static bool grow(JavaThread* current) { - ConcurrentTable::GrowTask grow_task(_table); - if (run_task(current, grow_task, "Grow")) { - _table_size = table_size(current); - log_info(monitortable)("Grown to size: %zu", _table_size); - return true; - } - return false; - } - - static bool clean(JavaThread* current) { - ConcurrentTable::BulkDeleteTask clean_task(_table); - auto is_dead = [&](ObjectMonitor** monitor) { - return (*monitor)->object_is_dead(); - }; - auto do_nothing = [&](ObjectMonitor** monitor) {}; - NativeHeapTrimmer::SuspendMark sm("ObjectMonitorTable"); - return run_task(current, clean_task, "Clean", is_dead, do_nothing); - } - - static bool resize(JavaThread* current) { - LogTarget(Info, monitortable) lt; - bool success = false; - - if (should_grow()) { - lt.print("Start growing with load factor %f", get_load_factor()); - success = grow(current); - } else { - if (!_table->is_max_size_reached() && AtomicAccess::load(&_resize)) { - lt.print("WARNING: Getting resize hints with load factor %f", get_load_factor()); - } - lt.print("Start cleaning with load factor %f", get_load_factor()); - success = clean(current); - } - - AtomicAccess::store(&_resize, false); - - return success; - } - - static ObjectMonitor* monitor_put_get(Thread* current, ObjectMonitor* monitor, oop obj) { - // Enter the monitor into the concurrent hashtable. - ObjectMonitor* result = monitor; - Lookup lookup_f(obj); - auto found_f = [&](ObjectMonitor** found) { - assert((*found)->object_peek() == obj, "must be"); - result = *found; - }; - bool grow; - _table->insert_get(current, lookup_f, monitor, found_f, &grow); - verify_monitor_get_result(obj, result); - if (grow) { - try_notify_grow(); - } - return result; - } - - static bool remove_monitor_entry(Thread* current, ObjectMonitor* monitor) { - LookupMonitor lookup_f(monitor); - return _table->remove(current, lookup_f); - } - - static bool contains_monitor(Thread* current, ObjectMonitor* monitor) { - LookupMonitor lookup_f(monitor); - bool result = false; - auto found_f = [&](ObjectMonitor** found) { - result = true; - }; - _table->get(current, lookup_f, found_f); - return result; - } - - static void print_on(outputStream* st) { - auto printer = [&] (ObjectMonitor** entry) { - ObjectMonitor* om = *entry; - oop obj = om->object_peek(); - st->print("monitor=" PTR_FORMAT ", ", p2i(om)); - st->print("object=" PTR_FORMAT, p2i(obj)); - assert(obj->mark().hash() == om->hash(), "hash must match"); - st->cr(); - return true; - }; - if (SafepointSynchronize::is_at_safepoint()) { - _table->do_safepoint_scan(printer); - } else { - _table->do_scan(Thread::current(), printer); - } - } -}; - -ObjectMonitorTable::ConcurrentTable* ObjectMonitorTable::_table = nullptr; -volatile size_t ObjectMonitorTable::_items_count = 0; -size_t ObjectMonitorTable::_table_size = 0; -volatile bool ObjectMonitorTable::_resize = false; - ObjectMonitor* ObjectSynchronizer::get_or_insert_monitor_from_table(oop object, JavaThread* current, bool* inserted) { ObjectMonitor* monitor = get_monitor_from_table(current, object); if (monitor != nullptr) { From 3559eeca0edd537c6160c6753cf6fc304afee4ca Mon Sep 17 00:00:00 2001 From: Hamlin Li Date: Mon, 15 Dec 2025 09:10:51 +0000 Subject: [PATCH 295/706] 8373428: Refine variables with the same name in nested scopes in PhaseChaitin::gather_lrg_masks Reviewed-by: phh --- src/hotspot/share/opto/chaitin.cpp | 40 +++++++++++++++--------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/hotspot/share/opto/chaitin.cpp b/src/hotspot/share/opto/chaitin.cpp index 667270d96b4..3ba3ffc1045 100644 --- a/src/hotspot/share/opto/chaitin.cpp +++ b/src/hotspot/share/opto/chaitin.cpp @@ -1076,8 +1076,8 @@ void PhaseChaitin::gather_lrg_masks( bool after_aggressive ) { // Prepare register mask for each input for( uint k = input_edge_start; k < cnt; k++ ) { - uint vreg = _lrg_map.live_range_id(n->in(k)); - if (!vreg) { + uint vreg_in = _lrg_map.live_range_id(n->in(k)); + if (!vreg_in) { continue; } @@ -1099,7 +1099,7 @@ void PhaseChaitin::gather_lrg_masks( bool after_aggressive ) { if (k >= cur_node->num_opnds()) continue; } - LRG &lrg = lrgs(vreg); + LRG &lrg_in = lrgs(vreg_in); // // Testing for floating point code shape // Node *test = n->in(k); // if( test->is_Mach() ) { @@ -1114,25 +1114,25 @@ void PhaseChaitin::gather_lrg_masks( bool after_aggressive ) { // Do not limit registers from uncommon uses before // AggressiveCoalesce. This effectively pre-virtual-splits // around uncommon uses of common defs. - const RegMask &rm = n->in_RegMask(k); + const RegMask &rm_in = n->in_RegMask(k); if (!after_aggressive && _cfg.get_block_for_node(n->in(k))->_freq > 1000 * block->_freq) { // Since we are BEFORE aggressive coalesce, leave the register // mask untrimmed by the call. This encourages more coalescing. // Later, AFTER aggressive, this live range will have to spill // but the spiller handles slow-path calls very nicely. } else { - lrg.and_with(rm); + lrg_in.and_with(rm_in); } // Check for bound register masks - const RegMask &lrgmask = lrg.mask(); + const RegMask &lrgmask_in = lrg_in.mask(); uint kreg = n->in(k)->ideal_reg(); bool is_vect = RegMask::is_vector(kreg); assert(n->in(k)->bottom_type()->isa_vect() == nullptr || is_vect || kreg == Op_RegD || kreg == Op_RegL || kreg == Op_RegVectMask, "vector must be in vector registers"); - if (lrgmask.is_bound(kreg)) - lrg._is_bound = 1; + if (lrgmask_in.is_bound(kreg)) + lrg_in._is_bound = 1; // If this use of a double forces a mis-aligned double, // flag as '_fat_proj' - really flag as allowing misalignment @@ -1141,30 +1141,30 @@ void PhaseChaitin::gather_lrg_masks( bool after_aggressive ) { // FOUR registers! #ifdef ASSERT if (is_vect && !_scheduling_info_generated) { - if (lrg.num_regs() != 0) { - assert(lrgmask.is_aligned_sets(lrg.num_regs()), "vector should be aligned"); - assert(!lrg._fat_proj, "sanity"); - assert(RegMask::num_registers(kreg) == lrg.num_regs(), "sanity"); + if (lrg_in.num_regs() != 0) { + assert(lrgmask_in.is_aligned_sets(lrg_in.num_regs()), "vector should be aligned"); + assert(!lrg_in._fat_proj, "sanity"); + assert(RegMask::num_registers(kreg) == lrg_in.num_regs(), "sanity"); } else { assert(n->is_Phi(), "not all inputs processed only if Phi"); } } #endif - if (!is_vect && lrg.num_regs() == 2 && !lrg._fat_proj && rm.is_misaligned_pair()) { - lrg._fat_proj = 1; - lrg._is_bound = 1; + if (!is_vect && lrg_in.num_regs() == 2 && !lrg_in._fat_proj && rm_in.is_misaligned_pair()) { + lrg_in._fat_proj = 1; + lrg_in._is_bound = 1; } // if the LRG is an unaligned pair, we will have to spill // so clear the LRG's register mask if it is not already spilled if (!is_vect && !n->is_SpillCopy() && - (lrg._def == nullptr || lrg.is_multidef() || !lrg._def->is_SpillCopy()) && - lrgmask.is_misaligned_pair()) { - lrg.clear(); + (lrg_in._def == nullptr || lrg_in.is_multidef() || !lrg_in._def->is_SpillCopy()) && + lrgmask_in.is_misaligned_pair()) { + lrg_in.clear(); } // Check for maximum frequency value - if (lrg._maxfreq < block->_freq) { - lrg._maxfreq = block->_freq; + if (lrg_in._maxfreq < block->_freq) { + lrg_in._maxfreq = block->_freq; } } // End for all allocated inputs From 629bf20f59f98a735ca22018ad00c93580aff5f3 Mon Sep 17 00:00:00 2001 From: Casper Norrbin Date: Mon, 15 Dec 2025 10:23:31 +0000 Subject: [PATCH 296/706] 8371408: [Linux] VM.info output for container information is confusing Reviewed-by: sgehwolf, dholmes --- .../os/linux/cgroupV1Subsystem_linux.cpp | 6 +- .../os/linux/cgroupV2Subsystem_linux.cpp | 4 +- src/hotspot/os/linux/osContainer_linux.cpp | 34 +++++++++-- src/hotspot/os/linux/osContainer_linux.hpp | 2 + src/hotspot/os/linux/os_linux.cpp | 59 ++++++++----------- .../containers/docker/TestContainerInfo.java | 16 +---- .../containers/docker/TestLimitsUpdating.java | 12 ++-- .../docker/TestMemoryAwareness.java | 6 +- .../jtreg/containers/docker/TestMisc.java | 22 +++---- .../containers/docker/DockerTestUtils.java | 11 ++++ 10 files changed, 95 insertions(+), 77 deletions(-) diff --git a/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp b/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp index ddcb0db2161..2df604083d2 100644 --- a/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp +++ b/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp @@ -467,9 +467,9 @@ void CgroupV1MemoryController::print_version_specific_info(outputStream* st, phy kmem_max_usage.set_value(temp); } - OSContainer::print_container_helper(st, kmem_limit, "kernel_memory_limit_in_bytes"); - OSContainer::print_container_helper(st, kmem_usage, "kernel_memory_usage_in_bytes"); - OSContainer::print_container_helper(st, kmem_max_usage, "kernel_memory_max_usage_in_bytes"); + OSContainer::print_container_helper(st, kmem_limit, "kernel_memory_limit"); + OSContainer::print_container_helper(st, kmem_usage, "kernel_memory_usage"); + OSContainer::print_container_helper(st, kmem_max_usage, "kernel_memory_max_usage"); } char* CgroupV1Subsystem::cpu_cpuset_cpus() { diff --git a/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp b/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp index f435e53c02c..c61d30e9236 100644 --- a/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp +++ b/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp @@ -378,8 +378,8 @@ void CgroupV2MemoryController::print_version_specific_info(outputStream* st, phy if (memory_swap_limit_value(reader(), swap_limit_val)) { swap_limit.set_value(swap_limit_val); } - OSContainer::print_container_helper(st, swap_current, "memory_swap_current_in_bytes"); - OSContainer::print_container_helper(st, swap_limit, "memory_swap_max_limit_in_bytes"); + OSContainer::print_container_helper(st, swap_current, "memory_swap_current"); + OSContainer::print_container_helper(st, swap_limit, "memory_swap_max_limit"); } char* CgroupV2Controller::construct_path(char* mount_path, const char* cgroup_path) { diff --git a/src/hotspot/os/linux/osContainer_linux.cpp b/src/hotspot/os/linux/osContainer_linux.cpp index d86bbf7428a..15a6403d07f 100644 --- a/src/hotspot/os/linux/osContainer_linux.cpp +++ b/src/hotspot/os/linux/osContainer_linux.cpp @@ -287,20 +287,44 @@ bool OSContainer::pids_current(uint64_t& value) { return cgroup_subsystem->pids_current(value); } +template struct metric_fmt; +template<> struct metric_fmt { static constexpr const char* fmt = "%llu"; }; +template<> struct metric_fmt { static constexpr const char* fmt = "%lu"; }; +template<> struct metric_fmt { static constexpr const char* fmt = "%d"; }; +template<> struct metric_fmt { static constexpr const char* fmt = "%s"; }; + +template void OSContainer::print_container_metric(outputStream*, const char*, unsigned long long int, const char*); +template void OSContainer::print_container_metric(outputStream*, const char*, unsigned long int, const char*); +template void OSContainer::print_container_metric(outputStream*, const char*, int, const char*); +template void OSContainer::print_container_metric(outputStream*, const char*, const char*, const char*); + +template +void OSContainer::print_container_metric(outputStream* st, const char* metrics, T value, const char* unit) { + constexpr int max_length = 38; // Longest "metric: value" string ("maximum number of tasks: not supported") + constexpr int longest_value = max_length - 11; // Max length - shortest "metric: " string ("cpu_quota: ") + char value_str[longest_value + 1] = {}; + os::snprintf_checked(value_str, longest_value, metric_fmt::fmt, value); + st->print("%s: %*s", metrics, max_length - static_cast(strlen(metrics)) - 2, value_str); // -2 for the ": " + if (unit[0] != '\0') { + st->print_cr(" %s", unit); + } else { + st->print_cr(""); + } +} + void OSContainer::print_container_helper(outputStream* st, MetricResult& res, const char* metrics) { - st->print("%s: ", metrics); if (res.success()) { if (res.value() != value_unlimited) { if (res.value() >= 1024) { - st->print_cr(PHYS_MEM_TYPE_FORMAT " k", (physical_memory_size_type)(res.value() / K)); + print_container_metric(st, metrics, res.value() / K, "kB"); } else { - st->print_cr(PHYS_MEM_TYPE_FORMAT, res.value()); + print_container_metric(st, metrics, res.value(), "B"); } } else { - st->print_cr("%s", "unlimited"); + print_container_metric(st, metrics, "unlimited"); } } else { // Not supported - st->print_cr("%s", "unavailable"); + print_container_metric(st, metrics, "unavailable"); } } diff --git a/src/hotspot/os/linux/osContainer_linux.hpp b/src/hotspot/os/linux/osContainer_linux.hpp index 895c99ba167..11c3e086feb 100644 --- a/src/hotspot/os/linux/osContainer_linux.hpp +++ b/src/hotspot/os/linux/osContainer_linux.hpp @@ -65,6 +65,8 @@ class OSContainer: AllStatic { static void init(); static void print_version_specific_info(outputStream* st); static void print_container_helper(outputStream* st, MetricResult& res, const char* metrics); + template + static void print_container_metric(outputStream* st, const char* metrics, T value, const char* unit = ""); static inline bool is_containerized(); static const char * container_type(); diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index 8af89bb3a71..7f6b4851013 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -2432,62 +2432,57 @@ bool os::Linux::print_container_info(outputStream* st) { st->print_cr("container (cgroup) information:"); const char *p_ct = OSContainer::container_type(); - st->print_cr("container_type: %s", p_ct != nullptr ? p_ct : "not supported"); + OSContainer::print_container_metric(st, "container_type", p_ct != nullptr ? p_ct : "not supported"); char *p = OSContainer::cpu_cpuset_cpus(); - st->print_cr("cpu_cpuset_cpus: %s", p != nullptr ? p : "not supported"); + OSContainer::print_container_metric(st, "cpu_cpuset_cpus", p != nullptr ? p : "not supported"); free(p); p = OSContainer::cpu_cpuset_memory_nodes(); - st->print_cr("cpu_memory_nodes: %s", p != nullptr ? p : "not supported"); + OSContainer::print_container_metric(st, "cpu_memory_nodes", p != nullptr ? p : "not supported"); free(p); int i = -1; bool supported = OSContainer::active_processor_count(i); - st->print("active_processor_count: "); if (supported) { assert(i > 0, "must be"); if (ActiveProcessorCount > 0) { - st->print_cr("%d, but overridden by -XX:ActiveProcessorCount %d", i, ActiveProcessorCount); + OSContainer::print_container_metric(st, "active_processor_count", ActiveProcessorCount, "(from -XX:ActiveProcessorCount)"); } else { - st->print_cr("%d", i); + OSContainer::print_container_metric(st, "active_processor_count", i); } } else { - st->print_cr("not supported"); + OSContainer::print_container_metric(st, "active_processor_count", "not supported"); } supported = OSContainer::cpu_quota(i); - st->print("cpu_quota: "); if (supported && i > 0) { - st->print_cr("%d", i); + OSContainer::print_container_metric(st, "cpu_quota", i); } else { - st->print_cr("%s", !supported ? "not supported" : "no quota"); + OSContainer::print_container_metric(st, "cpu_quota", !supported ? "not supported" : "no quota"); } supported = OSContainer::cpu_period(i); - st->print("cpu_period: "); if (supported && i > 0) { - st->print_cr("%d", i); + OSContainer::print_container_metric(st, "cpu_period", i); } else { - st->print_cr("%s", !supported ? "not supported" : "no period"); + OSContainer::print_container_metric(st, "cpu_period", !supported ? "not supported" : "no period"); } supported = OSContainer::cpu_shares(i); - st->print("cpu_shares: "); if (supported && i > 0) { - st->print_cr("%d", i); + OSContainer::print_container_metric(st, "cpu_shares", i); } else { - st->print_cr("%s", !supported ? "not supported" : "no shares"); + OSContainer::print_container_metric(st, "cpu_shares", !supported ? "not supported" : "no shares"); } uint64_t j = 0; supported = OSContainer::cpu_usage_in_micros(j); - st->print("cpu_usage_in_micros: "); if (supported && j > 0) { - st->print_cr(UINT64_FORMAT, j); + OSContainer::print_container_metric(st, "cpu_usage", j, "us"); } else { - st->print_cr("%s", !supported ? "not supported" : "no usage"); + OSContainer::print_container_metric(st, "cpu_usage", !supported ? "not supported" : "no usage"); } MetricResult memory_limit; @@ -2530,31 +2525,29 @@ bool os::Linux::print_container_info(outputStream* st) { if (OSContainer::cache_usage_in_bytes(val)) { cache_usage.set_value(val); } - OSContainer::print_container_helper(st, memory_limit, "memory_limit_in_bytes"); - OSContainer::print_container_helper(st, mem_swap_limit, "memory_and_swap_limit_in_bytes"); - OSContainer::print_container_helper(st, mem_soft_limit, "memory_soft_limit_in_bytes"); - OSContainer::print_container_helper(st, mem_throttle_limit, "memory_throttle_limit_in_bytes"); - OSContainer::print_container_helper(st, mem_usage, "memory_usage_in_bytes"); - OSContainer::print_container_helper(st, mem_max_usage, "memory_max_usage_in_bytes"); - OSContainer::print_container_helper(st, rss_usage, "rss_usage_in_bytes"); - OSContainer::print_container_helper(st, cache_usage, "cache_usage_in_bytes"); + OSContainer::print_container_helper(st, memory_limit, "memory_limit"); + OSContainer::print_container_helper(st, mem_swap_limit, "memory_and_swap_limit"); + OSContainer::print_container_helper(st, mem_soft_limit, "memory_soft_limit"); + OSContainer::print_container_helper(st, mem_throttle_limit, "memory_throttle_limit"); + OSContainer::print_container_helper(st, mem_usage, "memory_usage"); + OSContainer::print_container_helper(st, mem_max_usage, "memory_max_usage"); + OSContainer::print_container_helper(st, rss_usage, "rss_usage"); + OSContainer::print_container_helper(st, cache_usage, "cache_usage"); OSContainer::print_version_specific_info(st); supported = OSContainer::pids_max(j); - st->print("maximum number of tasks: "); if (supported && j != value_unlimited) { - st->print_cr(UINT64_FORMAT, j); + OSContainer::print_container_metric(st, "maximum number of tasks", j); } else { - st->print_cr("%s", !supported ? "not supported" : "unlimited"); + OSContainer::print_container_metric(st, "maximum number of tasks", !supported ? "not supported" : "unlimited"); } supported = OSContainer::pids_current(j); - st->print("current number of tasks: "); if (supported && j > 0) { - st->print_cr(UINT64_FORMAT, j); + OSContainer::print_container_metric(st, "current number of tasks", j); } else { - st->print_cr("%s", !supported ? "not supported" : "no current tasks"); + OSContainer::print_container_metric(st, "current number of tasks", !supported ? "not supported" : "no tasks"); } return true; diff --git a/test/hotspot/jtreg/containers/docker/TestContainerInfo.java b/test/hotspot/jtreg/containers/docker/TestContainerInfo.java index a5579aa9528..5e7a0000cf5 100644 --- a/test/hotspot/jtreg/containers/docker/TestContainerInfo.java +++ b/test/hotspot/jtreg/containers/docker/TestContainerInfo.java @@ -73,23 +73,11 @@ public class TestContainerInfo { checkContainerInfo(out); } - private static void shouldMatchWithValue(OutputAnalyzer output, String match, String value) { - output.shouldContain(match); - String str = output.getOutput(); - for (String s : str.split(System.lineSeparator())) { - if (s.contains(match)) { - if (!s.contains(value)) { - throw new RuntimeException("memory_swap_current_in_bytes NOT " + value + "! Line was : " + s); - } - } - } - } - private static void checkContainerInfo(OutputAnalyzer out) throws Exception { String str = out.getOutput(); if (str.contains("cgroupv2")) { - shouldMatchWithValue(out, "memory_swap_max_limit_in_bytes", "0"); - shouldMatchWithValue(out, "memory_swap_current_in_bytes", "0"); + DockerTestUtils.shouldMatchWithValue(out, "memory_swap_max_limit", "0"); + DockerTestUtils.shouldMatchWithValue(out, "memory_swap_current", "0"); } else { throw new SkippedException("This test is cgroups v2 specific, skipped on cgroups v1"); } diff --git a/test/hotspot/jtreg/containers/docker/TestLimitsUpdating.java b/test/hotspot/jtreg/containers/docker/TestLimitsUpdating.java index df8ba5b6161..db8f4fd1826 100644 --- a/test/hotspot/jtreg/containers/docker/TestLimitsUpdating.java +++ b/test/hotspot/jtreg/containers/docker/TestLimitsUpdating.java @@ -128,12 +128,12 @@ public class TestLimitsUpdating { // Do assertions based on the output in target container OutputAnalyzer targetOut = out[0]; - targetOut.shouldContain("active_processor_count: 2"); // initial value - targetOut.shouldContain("active_processor_count: 3"); // updated value - targetOut.shouldContain("memory_limit_in_bytes: 512000 k"); // initial value - targetOut.shouldContain("memory_and_swap_limit_in_bytes: 512000 k"); // initial value - targetOut.shouldContain("memory_limit_in_bytes: 307200 k"); // updated value - targetOut.shouldContain("memory_and_swap_limit_in_bytes: 307200 k"); // updated value + DockerTestUtils.shouldMatchWithValue(targetOut, "active_processor_count", "2"); // initial value + DockerTestUtils.shouldMatchWithValue(targetOut, "active_processor_count", "3"); // updated value + DockerTestUtils.shouldMatchWithValue(targetOut, "memory_limit", "512000 kB"); // initial value + DockerTestUtils.shouldMatchWithValue(targetOut, "memory_and_swap_limit", "512000 kB"); // initial value + DockerTestUtils.shouldMatchWithValue(targetOut, "memory_limit", "307200 kB"); // updated value + DockerTestUtils.shouldMatchWithValue(targetOut, "memory_and_swap_limit", "307200 kB"); // updated value } private static List getContainerUpdate(int cpuQuota, int cpuPeriod, String memory) { diff --git a/test/hotspot/jtreg/containers/docker/TestMemoryAwareness.java b/test/hotspot/jtreg/containers/docker/TestMemoryAwareness.java index 4cf895156fe..6034aefcd6e 100644 --- a/test/hotspot/jtreg/containers/docker/TestMemoryAwareness.java +++ b/test/hotspot/jtreg/containers/docker/TestMemoryAwareness.java @@ -169,11 +169,11 @@ public class TestMemoryAwareness { opts.addDockerOpts("--memory-swap=" + swapToSet); Common.run(opts) - .shouldMatch("memory_limit_in_bytes:.*" + expectedMem) - .shouldNotMatch("memory_and_swap_limit_in_bytes:.*not supported") + .shouldMatch("memory_limit:.*" + expectedMem) + .shouldNotMatch("memory_and_swap_limit:.*not supported") // On systems with swapaccount=0 this returns the memory limit. // On systems with swapaccount=1 this returns the set memory+swap value. - .shouldMatch("memory_and_swap_limit_in_bytes:.*(" + expectedMem + "|" + expectedSwap + ")"); + .shouldMatch("memory_and_swap_limit:.*(" + expectedMem + "|" + expectedSwap + ")"); } /* diff --git a/test/hotspot/jtreg/containers/docker/TestMisc.java b/test/hotspot/jtreg/containers/docker/TestMisc.java index fca3cef5513..794bbc7b355 100644 --- a/test/hotspot/jtreg/containers/docker/TestMisc.java +++ b/test/hotspot/jtreg/containers/docker/TestMisc.java @@ -127,10 +127,10 @@ public class TestMisc { // mapping function. if (numberMatch) { int valueExpected = isCgroupV2 ? expected : cpuShares; - out.shouldContain("cpu_shares: " + valueExpected); + DockerTestUtils.shouldMatchWithValue(out, "cpu_shares", String.valueOf(valueExpected)); } else { // must not print "no shares" - out.shouldNotContain("cpu_shares: no shares"); + DockerTestUtils.shouldNotMatchWithValue(out, "cpu_shares", "no shares"); } } @@ -141,7 +141,7 @@ public class TestMisc { Common.addWhiteBoxOpts(opts); OutputAnalyzer out = Common.run(opts); - out.shouldContain("but overridden by -XX:ActiveProcessorCount 2"); + DockerTestUtils.shouldMatchWithValue(out, "active_processor_count", "2 (from -XX:ActiveProcessorCount)"); } private static void checkContainerInfo(OutputAnalyzer out) throws Exception { @@ -158,11 +158,11 @@ public class TestMisc { "Memory Throttle Limit", "Memory Usage", "Maximum Memory Usage", - "memory_max_usage_in_bytes", + "memory_max_usage", "maximum number of tasks", "current number of tasks", - "rss_usage_in_bytes", - "cache_usage_in_bytes" + "rss_usage", + "cache_usage" }; for (String s : expectedToContain) { @@ -170,13 +170,13 @@ public class TestMisc { } String str = out.getOutput(); if (str.contains("cgroupv1")) { - out.shouldContain("kernel_memory_usage_in_bytes"); - out.shouldContain("kernel_memory_max_usage_in_bytes"); - out.shouldContain("kernel_memory_limit_in_bytes"); + out.shouldContain("kernel_memory_usage"); + out.shouldContain("kernel_memory_max_usage"); + out.shouldContain("kernel_memory_limit"); } else { if (str.contains("cgroupv2")) { - out.shouldContain("memory_swap_current_in_bytes"); - out.shouldContain("memory_swap_max_limit_in_bytes"); + out.shouldContain("memory_swap_current"); + out.shouldContain("memory_swap_max_limit"); } else { throw new RuntimeException("Output has to contain information about cgroupv1 or cgroupv2"); } diff --git a/test/lib/jdk/test/lib/containers/docker/DockerTestUtils.java b/test/lib/jdk/test/lib/containers/docker/DockerTestUtils.java index ec3e6d773b1..22a8572af46 100644 --- a/test/lib/jdk/test/lib/containers/docker/DockerTestUtils.java +++ b/test/lib/jdk/test/lib/containers/docker/DockerTestUtils.java @@ -38,6 +38,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.EnumSet; import java.util.List; +import java.util.regex.Pattern; import jdk.internal.platform.Metrics; import jdk.test.lib.Container; import jdk.test.lib.Utils; @@ -341,6 +342,16 @@ public class DockerTestUtils { return output; } + public static void shouldMatchWithValue(OutputAnalyzer output, String metric, String value) throws Exception { + String pattern = "^" + Pattern.quote(metric) + ":\\s*" + Pattern.quote(value) + ".*$"; + output.shouldMatch(pattern); + } + + public static void shouldNotMatchWithValue(OutputAnalyzer output, String metric, String value) throws Exception { + String pattern = "^" + Pattern.quote(metric) + ":\\s*" + Pattern.quote(value) + ".*$"; + output.shouldNotMatch(pattern); + } + private static void writeOutputToFile(String output, String fileName) throws Exception { try (FileWriter fw = new FileWriter(fileName)) { From f5187ebf7a4d4241f01612b62c514a1e4e272658 Mon Sep 17 00:00:00 2001 From: Stefan Karlsson Date: Mon, 15 Dec 2025 12:57:03 +0000 Subject: [PATCH 297/706] 8373599: Cleanup arguments.hpp includes Reviewed-by: coleenp, kbarrett --- .../compiler/compilerDefinitions.inline.hpp | 1 + .../share/runtime/abstract_vm_version.cpp | 1 + src/hotspot/share/runtime/arguments.cpp | 11 ++++++++++ src/hotspot/share/runtime/arguments.hpp | 21 +++++++----------- src/hotspot/share/runtime/java.cpp | 21 ++++++++++++++++++ src/hotspot/share/runtime/java.hpp | 22 +++++-------------- test/hotspot/gtest/runtime/test_arguments.cpp | 1 + 7 files changed, 48 insertions(+), 30 deletions(-) diff --git a/src/hotspot/share/compiler/compilerDefinitions.inline.hpp b/src/hotspot/share/compiler/compilerDefinitions.inline.hpp index 21bf80549f4..8bf70477cb3 100644 --- a/src/hotspot/share/compiler/compilerDefinitions.inline.hpp +++ b/src/hotspot/share/compiler/compilerDefinitions.inline.hpp @@ -29,6 +29,7 @@ #include "compiler/compiler_globals.hpp" #include "runtime/arguments.hpp" +#include "runtime/globals.hpp" inline bool CompilerConfig::is_interpreter_only() { return Arguments::is_interpreter_only() || TieredStopAtLevel == CompLevel_none; diff --git a/src/hotspot/share/runtime/abstract_vm_version.cpp b/src/hotspot/share/runtime/abstract_vm_version.cpp index 3860307f8df..54c8c917fb3 100644 --- a/src/hotspot/share/runtime/abstract_vm_version.cpp +++ b/src/hotspot/share/runtime/abstract_vm_version.cpp @@ -26,6 +26,7 @@ #include "compiler/compilerDefinitions.hpp" #include "jvm_io.h" #include "runtime/arguments.hpp" +#include "runtime/os.hpp" #include "runtime/vm_version.hpp" #include "utilities/globalDefinitions.hpp" diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index d4ba599fa9b..cf0a1ab9757 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -1092,6 +1092,13 @@ void Arguments::print_summary_on(outputStream* st) { st->cr(); } +void Arguments::set_jvm_flags_file(const char *value) { + if (_jvm_flags_file != nullptr) { + os::free(_jvm_flags_file); + } + _jvm_flags_file = os::strdup_check_oom(value); +} + void Arguments::print_jvm_flags_on(outputStream* st) { if (_num_jvm_flags > 0) { for (int i=0; i < _num_jvm_flags; i++) { @@ -2844,6 +2851,10 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, JVMFlagOrigin return JNI_OK; } +void Arguments::set_ext_dirs(char *value) { + _ext_dirs = os::strdup_check_oom(value); +} + void Arguments::add_patch_mod_prefix(const char* module_name, const char* path) { // For java.base check for duplicate --patch-module options being specified on the command line. // This check is only required for java.base, all other duplicate module specifications diff --git a/src/hotspot/share/runtime/arguments.hpp b/src/hotspot/share/runtime/arguments.hpp index 3d83959d76a..f2bcc21e123 100644 --- a/src/hotspot/share/runtime/arguments.hpp +++ b/src/hotspot/share/runtime/arguments.hpp @@ -25,18 +25,17 @@ #ifndef SHARE_RUNTIME_ARGUMENTS_HPP #define SHARE_RUNTIME_ARGUMENTS_HPP -#include "logging/logLevel.hpp" -#include "logging/logTag.hpp" +#include "jni.h" #include "memory/allocation.hpp" #include "memory/allStatic.hpp" -#include "runtime/globals.hpp" +#include "runtime/flags/jvmFlag.hpp" #include "runtime/java.hpp" -#include "runtime/os.hpp" -#include "utilities/debug.hpp" -#include "utilities/vmEnums.hpp" +#include "utilities/globalDefinitions.hpp" // Arguments parses the command line and recognizes options +template +class GrowableArray; class JVMFlag; // Invocation API hook typedefs (these should really be defined in jni.h) @@ -412,12 +411,8 @@ class Arguments : AllStatic { // convenient methods to get and set jvm_flags_file static const char* get_jvm_flags_file() { return _jvm_flags_file; } - static void set_jvm_flags_file(const char *value) { - if (_jvm_flags_file != nullptr) { - os::free(_jvm_flags_file); - } - _jvm_flags_file = os::strdup_check_oom(value); - } + static void set_jvm_flags_file(const char *value); + // convenient methods to obtain / print jvm_flags and jvm_args static const char* jvm_flags() { return build_resource_string(_jvm_flags_array, _num_jvm_flags); } static const char* jvm_args() { return build_resource_string(_jvm_args_array, _num_jvm_args); } @@ -479,7 +474,7 @@ class Arguments : AllStatic { static void set_dll_dir(const char *value) { _sun_boot_library_path->set_value(value); } static void set_java_home(const char *value) { _java_home->set_value(value); } static void set_library_path(const char *value) { _java_library_path->set_value(value); } - static void set_ext_dirs(char *value) { _ext_dirs = os::strdup_check_oom(value); } + static void set_ext_dirs(char *value); // Set up the underlying pieces of the boot class path static void add_patch_mod_prefix(const char *module_name, const char *path); diff --git a/src/hotspot/share/runtime/java.cpp b/src/hotspot/share/runtime/java.cpp index fb4abdac2ef..c49a9f5d4b8 100644 --- a/src/hotspot/share/runtime/java.cpp +++ b/src/hotspot/share/runtime/java.cpp @@ -71,6 +71,7 @@ #include "runtime/interfaceSupport.inline.hpp" #include "runtime/java.hpp" #include "runtime/javaThread.hpp" +#include "runtime/os.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/stubRoutines.hpp" #include "runtime/task.hpp" @@ -765,3 +766,23 @@ void JDK_Version::to_string(char* buffer, size_t buflen) const { } } } + +void JDK_Version::set_java_version(const char* version) { + _java_version = os::strdup(version); +} + +void JDK_Version::set_runtime_name(const char* name) { + _runtime_name = os::strdup(name); +} + +void JDK_Version::set_runtime_version(const char* version) { + _runtime_version = os::strdup(version); +} + +void JDK_Version::set_runtime_vendor_version(const char* vendor_version) { + _runtime_vendor_version = os::strdup(vendor_version); +} + +void JDK_Version::set_runtime_vendor_vm_bug_url(const char* vendor_vm_bug_url) { + _runtime_vendor_vm_bug_url = os::strdup(vendor_vm_bug_url); +} diff --git a/src/hotspot/share/runtime/java.hpp b/src/hotspot/share/runtime/java.hpp index 67cf3fb686a..f7f1fb5e892 100644 --- a/src/hotspot/share/runtime/java.hpp +++ b/src/hotspot/share/runtime/java.hpp @@ -25,7 +25,6 @@ #ifndef SHARE_RUNTIME_JAVA_HPP #define SHARE_RUNTIME_JAVA_HPP -#include "runtime/os.hpp" #include "utilities/globalDefinitions.hpp" class Handle; @@ -133,38 +132,27 @@ class JDK_Version { static const char* java_version() { return _java_version; } - static void set_java_version(const char* version) { - _java_version = os::strdup(version); - } + static void set_java_version(const char* version); static const char* runtime_name() { return _runtime_name; } - static void set_runtime_name(const char* name) { - _runtime_name = os::strdup(name); - } + static void set_runtime_name(const char* name); static const char* runtime_version() { return _runtime_version; } - static void set_runtime_version(const char* version) { - _runtime_version = os::strdup(version); - } + static void set_runtime_version(const char* version); static const char* runtime_vendor_version() { return _runtime_vendor_version; } - static void set_runtime_vendor_version(const char* vendor_version) { - _runtime_vendor_version = os::strdup(vendor_version); - } + static void set_runtime_vendor_version(const char* vendor_version); static const char* runtime_vendor_vm_bug_url() { return _runtime_vendor_vm_bug_url; } - static void set_runtime_vendor_vm_bug_url(const char* vendor_vm_bug_url) { - _runtime_vendor_vm_bug_url = os::strdup(vendor_vm_bug_url); - } - + static void set_runtime_vendor_vm_bug_url(const char* vendor_vm_bug_url); }; #endif // SHARE_RUNTIME_JAVA_HPP diff --git a/test/hotspot/gtest/runtime/test_arguments.cpp b/test/hotspot/gtest/runtime/test_arguments.cpp index 074636fea0d..17404f45be2 100644 --- a/test/hotspot/gtest/runtime/test_arguments.cpp +++ b/test/hotspot/gtest/runtime/test_arguments.cpp @@ -24,6 +24,7 @@ #include "jvm.h" #include "runtime/arguments.hpp" #include "runtime/flags/jvmFlag.hpp" +#include "runtime/os.hpp" #include "utilities/align.hpp" #include "utilities/globalDefinitions.hpp" From 1f47294cd336db34030ea16132490ab51310ace5 Mon Sep 17 00:00:00 2001 From: Jaikiran Pai Date: Mon, 15 Dec 2025 13:36:12 +0000 Subject: [PATCH 298/706] 8287062: com/sun/jndi/ldap/LdapPoolTimeoutTest.java failed due to different timeout message Reviewed-by: aefimov --- .../sun/jndi/ldap/LdapPoolTimeoutTest.java | 91 +++++++++++-------- 1 file changed, 53 insertions(+), 38 deletions(-) diff --git a/test/jdk/com/sun/jndi/ldap/LdapPoolTimeoutTest.java b/test/jdk/com/sun/jndi/ldap/LdapPoolTimeoutTest.java index 294e0f5f1a8..b47433ca16f 100644 --- a/test/jdk/com/sun/jndi/ldap/LdapPoolTimeoutTest.java +++ b/test/jdk/com/sun/jndi/ldap/LdapPoolTimeoutTest.java @@ -35,6 +35,8 @@ import org.testng.annotations.Test; import javax.naming.Context; import javax.naming.NamingException; import javax.naming.directory.InitialDirContext; + +import java.net.SocketTimeoutException; import java.util.ArrayList; import java.util.Hashtable; import java.util.List; @@ -82,14 +84,10 @@ public class LdapPoolTimeoutTest { env.put(Context.PROVIDER_URL, "ldap://example.com:1234"); try { - futures.add(executorService.submit(() -> { attemptConnect(env); return null; })); - futures.add(executorService.submit(() -> { attemptConnect(env); return null; })); - futures.add(executorService.submit(() -> { attemptConnect(env); return null; })); - futures.add(executorService.submit(() -> { attemptConnect(env); return null; })); - futures.add(executorService.submit(() -> { attemptConnect(env); return null; })); - futures.add(executorService.submit(() -> { attemptConnect(env); return null; })); - futures.add(executorService.submit(() -> { attemptConnect(env); return null; })); - futures.add(executorService.submit(() -> { attemptConnect(env); return null; })); + // launch a few concurrent connection attempts + for (int i = 0; i < 8; i++) { + futures.add(executorService.submit(() -> { attemptConnect(env); return null; })); + } } finally { executorService.shutdown(); } @@ -109,38 +107,55 @@ public class LdapPoolTimeoutTest { private static void attemptConnect(Hashtable env) throws Exception { try { - LdapTimeoutTest.assertCompletion(CONNECT_MILLIS - 1000, - 2 * CONNECT_MILLIS + TOLERANCE, - () -> new InitialDirContext(env)); - } catch (RuntimeException e) { - final String msg = e.getCause() == null ? e.getMessage() : e.getCause().getMessage(); - // assertCompletion may wrap a CommunicationException in an RTE - if (msg != null && - (msg.contains("Network is unreachable") - || msg.contains("No route to host") - || msg.contains("Connection timed out"))) { - // got the expected exception - System.out.println("Received expected RuntimeException message: " + msg); - } else { - // propagate the unexpected exception - throw e; - } - } catch (NamingException ex) { - final String msg = ex.getCause() == null ? ex.getMessage() : ex.getCause().getMessage(); - if (msg != null && - (msg.contains("Network is unreachable") - || msg.contains("Timed out waiting for lock") - || msg.contains("Connect timed out") - || msg.contains("Timeout exceeded while waiting for a connection"))) { - // got the expected exception - System.out.println("Received expected NamingException message: " + msg); - } else { - // propagate the unexpected exception - throw ex; - } + final InitialDirContext unexpectedCtx = + LdapTimeoutTest.assertCompletion(CONNECT_MILLIS - 1000, + 2 * CONNECT_MILLIS + TOLERANCE, + () -> new InitialDirContext(env)); + throw new RuntimeException("InitialDirContext construction was expected to fail," + + " but returned " + unexpectedCtx); } catch (Throwable t) { - throw new RuntimeException(t); + final NamingException namingEx = findNamingException(t); + if (namingEx != null) { + // found the NamingException, verify it's the right reason + if (namingEx.getCause() instanceof SocketTimeoutException ste) { + // got the expected exception + System.out.println("Received expected SocketTimeoutException: " + ste); + return; + } + // rely on the exception message to verify the expected exception + final String msg = namingEx.getCause() == null + ? namingEx.getMessage() + : namingEx.getCause().getMessage(); + if (msg != null && + (msg.contains("Network is unreachable") + || msg.contains("No route to host") + || msg.contains("Timed out waiting for lock") + || msg.contains("Connect timed out") + || msg.contains("Timeout exceeded while waiting for a connection"))) { + // got the expected exception + System.out.println("Received expected NamingException with message: " + msg); + return; + } + } + // unexpected exception, propagate it + if (t instanceof Exception e) { + throw e; + } else { + throw new Exception(t); + } } } + // Find and return the NamingException from the given Throwable. Returns null if none found. + private static NamingException findNamingException(final Throwable t) { + Throwable cause = t; + while (cause != null) { + if (cause instanceof NamingException ne) { + return ne; + } + cause = cause.getCause(); + } + return null; + } + } From 34f241317ecd7473cfb6dcc2e6e5cf3a40299e2c Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Mon, 15 Dec 2025 14:18:46 +0000 Subject: [PATCH 299/706] 8371503: RETAIN_IMAGE_AFTER_TEST do not work for some tests Reviewed-by: lmesnik, dholmes --- test/hotspot/jtreg/containers/docker/DockerBasicTest.java | 4 +--- test/hotspot/jtreg/containers/docker/ShareTmpDir.java | 4 +--- test/hotspot/jtreg/containers/docker/TestCPUAwareness.java | 4 +--- test/hotspot/jtreg/containers/docker/TestLimitsUpdating.java | 4 +--- test/hotspot/jtreg/containers/docker/TestMemoryAwareness.java | 4 +--- test/hotspot/jtreg/containers/docker/TestPids.java | 4 +--- .../jdk/internal/platform/docker/TestDockerMemoryMetrics.java | 4 +--- .../internal/platform/docker/TestGetFreeSwapSpaceSize.java | 4 +--- test/jdk/jdk/internal/platform/docker/TestLimitsUpdating.java | 4 +--- test/jdk/jdk/internal/platform/docker/TestPidsLimit.java | 4 +--- test/lib/jdk/test/lib/containers/docker/DockerTestUtils.java | 2 ++ 11 files changed, 12 insertions(+), 30 deletions(-) diff --git a/test/hotspot/jtreg/containers/docker/DockerBasicTest.java b/test/hotspot/jtreg/containers/docker/DockerBasicTest.java index e564cae9d8e..403f46f6ab4 100644 --- a/test/hotspot/jtreg/containers/docker/DockerBasicTest.java +++ b/test/hotspot/jtreg/containers/docker/DockerBasicTest.java @@ -54,9 +54,7 @@ public class DockerBasicTest { testHelloDocker(); testJavaVersionWithCgMounts(); } finally { - if (!DockerTestUtils.RETAIN_IMAGE_AFTER_TEST) { - DockerTestUtils.removeDockerImage(imageNameAndTag); - } + DockerTestUtils.removeDockerImage(imageNameAndTag); } } diff --git a/test/hotspot/jtreg/containers/docker/ShareTmpDir.java b/test/hotspot/jtreg/containers/docker/ShareTmpDir.java index a84cdacefa1..b7f807d76a3 100644 --- a/test/hotspot/jtreg/containers/docker/ShareTmpDir.java +++ b/test/hotspot/jtreg/containers/docker/ShareTmpDir.java @@ -57,9 +57,7 @@ public class ShareTmpDir { try { test(); } finally { - if (!DockerTestUtils.RETAIN_IMAGE_AFTER_TEST) { - DockerTestUtils.removeDockerImage(imageName); - } + DockerTestUtils.removeDockerImage(imageName); } } diff --git a/test/hotspot/jtreg/containers/docker/TestCPUAwareness.java b/test/hotspot/jtreg/containers/docker/TestCPUAwareness.java index 26f160ab27d..6b0a536e4d4 100644 --- a/test/hotspot/jtreg/containers/docker/TestCPUAwareness.java +++ b/test/hotspot/jtreg/containers/docker/TestCPUAwareness.java @@ -85,9 +85,7 @@ public class TestCPUAwareness { } } finally { - if (!DockerTestUtils.RETAIN_IMAGE_AFTER_TEST) { - DockerTestUtils.removeDockerImage(imageName); - } + DockerTestUtils.removeDockerImage(imageName); } } diff --git a/test/hotspot/jtreg/containers/docker/TestLimitsUpdating.java b/test/hotspot/jtreg/containers/docker/TestLimitsUpdating.java index db8f4fd1826..32436cec1d7 100644 --- a/test/hotspot/jtreg/containers/docker/TestLimitsUpdating.java +++ b/test/hotspot/jtreg/containers/docker/TestLimitsUpdating.java @@ -63,9 +63,7 @@ public class TestLimitsUpdating { try { testLimitUpdates(); } finally { - if (!DockerTestUtils.RETAIN_IMAGE_AFTER_TEST) { - DockerTestUtils.removeDockerImage(imageName); - } + DockerTestUtils.removeDockerImage(imageName); } } diff --git a/test/hotspot/jtreg/containers/docker/TestMemoryAwareness.java b/test/hotspot/jtreg/containers/docker/TestMemoryAwareness.java index 6034aefcd6e..522b2904c43 100644 --- a/test/hotspot/jtreg/containers/docker/TestMemoryAwareness.java +++ b/test/hotspot/jtreg/containers/docker/TestMemoryAwareness.java @@ -102,9 +102,7 @@ public class TestMemoryAwareness { testMetricsSwapExceedingPhysical(); testContainerMemExceedsPhysical(); } finally { - if (!DockerTestUtils.RETAIN_IMAGE_AFTER_TEST) { - DockerTestUtils.removeDockerImage(imageName); - } + DockerTestUtils.removeDockerImage(imageName); } } diff --git a/test/hotspot/jtreg/containers/docker/TestPids.java b/test/hotspot/jtreg/containers/docker/TestPids.java index 0e39268184e..2bc5f8c03c2 100644 --- a/test/hotspot/jtreg/containers/docker/TestPids.java +++ b/test/hotspot/jtreg/containers/docker/TestPids.java @@ -63,9 +63,7 @@ public class TestPids { try { testPids(); } finally { - if (!DockerTestUtils.RETAIN_IMAGE_AFTER_TEST) { - DockerTestUtils.removeDockerImage(imageName); - } + DockerTestUtils.removeDockerImage(imageName); } } diff --git a/test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetrics.java b/test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetrics.java index 818c2c04a1d..12f90d65516 100644 --- a/test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetrics.java +++ b/test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetrics.java @@ -81,9 +81,7 @@ public class TestDockerMemoryMetrics { testMemorySoftLimit("500m","200m"); } finally { - if (!DockerTestUtils.RETAIN_IMAGE_AFTER_TEST) { - DockerTestUtils.removeDockerImage(imageName); - } + DockerTestUtils.removeDockerImage(imageName); } } diff --git a/test/jdk/jdk/internal/platform/docker/TestGetFreeSwapSpaceSize.java b/test/jdk/jdk/internal/platform/docker/TestGetFreeSwapSpaceSize.java index 1e5160330de..6e07d2e9ed5 100644 --- a/test/jdk/jdk/internal/platform/docker/TestGetFreeSwapSpaceSize.java +++ b/test/jdk/jdk/internal/platform/docker/TestGetFreeSwapSpaceSize.java @@ -53,9 +53,7 @@ public class TestGetFreeSwapSpaceSize { "150M", Integer.toString(0) ); } finally { - if (!DockerTestUtils.RETAIN_IMAGE_AFTER_TEST) { - DockerTestUtils.removeDockerImage(imageName); - } + DockerTestUtils.removeDockerImage(imageName); } } diff --git a/test/jdk/jdk/internal/platform/docker/TestLimitsUpdating.java b/test/jdk/jdk/internal/platform/docker/TestLimitsUpdating.java index a3df580fed1..a42eee358c3 100644 --- a/test/jdk/jdk/internal/platform/docker/TestLimitsUpdating.java +++ b/test/jdk/jdk/internal/platform/docker/TestLimitsUpdating.java @@ -62,9 +62,7 @@ public class TestLimitsUpdating { try { testLimitUpdates(); } finally { - if (!DockerTestUtils.RETAIN_IMAGE_AFTER_TEST) { - DockerTestUtils.removeDockerImage(imageName); - } + DockerTestUtils.removeDockerImage(imageName); } } diff --git a/test/jdk/jdk/internal/platform/docker/TestPidsLimit.java b/test/jdk/jdk/internal/platform/docker/TestPidsLimit.java index 87ecae7ee62..0313fcc582d 100644 --- a/test/jdk/jdk/internal/platform/docker/TestPidsLimit.java +++ b/test/jdk/jdk/internal/platform/docker/TestPidsLimit.java @@ -59,9 +59,7 @@ public class TestPidsLimit { testPidsLimit("2000"); testPidsLimit("Unlimited"); } finally { - if (!DockerTestUtils.RETAIN_IMAGE_AFTER_TEST) { - DockerTestUtils.removeDockerImage(imageName); - } + DockerTestUtils.removeDockerImage(imageName); } } diff --git a/test/lib/jdk/test/lib/containers/docker/DockerTestUtils.java b/test/lib/jdk/test/lib/containers/docker/DockerTestUtils.java index 22a8572af46..b013561be0b 100644 --- a/test/lib/jdk/test/lib/containers/docker/DockerTestUtils.java +++ b/test/lib/jdk/test/lib/containers/docker/DockerTestUtils.java @@ -291,7 +291,9 @@ public class DockerTestUtils { * @throws Exception */ public static void removeDockerImage(String imageNameAndTag) throws Exception { + if(!DockerTestUtils.RETAIN_IMAGE_AFTER_TEST) { execute(Container.ENGINE_COMMAND, "rmi", "--force", imageNameAndTag); + } } From ea6493c4e1de2bc9615beee389b2d335669dc542 Mon Sep 17 00:00:00 2001 From: William Kemper Date: Mon, 15 Dec 2025 15:52:01 +0000 Subject: [PATCH 300/706] 8373100: Genshen: Control thread can miss allocation failure notification Reviewed-by: ysr, kdnilsen, xpeng --- .../shenandoahGenerationalControlThread.cpp | 23 +++++++++---------- .../shenandoahGenerationalControlThread.hpp | 11 ++++----- 2 files changed, 15 insertions(+), 19 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp index ece4150f577..dfb28fd9ebb 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp @@ -96,8 +96,7 @@ void ShenandoahGenerationalControlThread::stop_service() { log_debug(gc, thread)("Stopping control thread"); MonitorLocker ml(&_control_lock, Mutex::_no_safepoint_check_flag); _heap->cancel_gc(GCCause::_shenandoah_stop_vm); - _requested_gc_cause = GCCause::_shenandoah_stop_vm; - notify_cancellation(ml, GCCause::_shenandoah_stop_vm); + notify_control_thread(ml, GCCause::_shenandoah_stop_vm); // We can't wait here because it may interfere with the active cycle's ability // to reach a safepoint (this runs on a java thread). } @@ -140,7 +139,8 @@ void ShenandoahGenerationalControlThread::check_for_request(ShenandoahGCRequest& } ShenandoahGenerationalControlThread::GCMode ShenandoahGenerationalControlThread::prepare_for_allocation_failure_gc(ShenandoahGCRequest &request) { - + // Important: not all paths update the request.generation. This is intentional. + // A degenerated cycle must use the same generation carried over from the previous request. if (_degen_point == ShenandoahGC::_degenerated_unset) { _degen_point = ShenandoahGC::_degenerated_outside_cycle; request.generation = _heap->young_generation(); @@ -633,9 +633,7 @@ void ShenandoahGenerationalControlThread::service_stw_degenerated_cycle(const Sh void ShenandoahGenerationalControlThread::request_gc(GCCause::Cause cause) { if (ShenandoahCollectorPolicy::is_allocation_failure(cause)) { - // GC should already be cancelled. Here we are just notifying the control thread to - // wake up and handle the cancellation request, so we don't need to set _requested_gc_cause. - notify_cancellation(cause); + notify_control_thread(cause); } else if (ShenandoahCollectorPolicy::should_handle_requested_gc(cause)) { handle_requested_gc(cause); } @@ -661,7 +659,7 @@ bool ShenandoahGenerationalControlThread::request_concurrent_gc(ShenandoahGenera log_info(gc)("Preempting old generation mark to allow %s GC", generation->name()); while (gc_mode() == servicing_old) { ShenandoahHeap::heap()->cancel_gc(GCCause::_shenandoah_concurrent_gc); - notify_cancellation(ml, GCCause::_shenandoah_concurrent_gc); + notify_control_thread(ml, GCCause::_shenandoah_concurrent_gc); ml.wait(); } return true; @@ -701,14 +699,15 @@ void ShenandoahGenerationalControlThread::notify_control_thread(MonitorLocker& m ml.notify(); } -void ShenandoahGenerationalControlThread::notify_cancellation(GCCause::Cause cause) { +void ShenandoahGenerationalControlThread::notify_control_thread(GCCause::Cause cause) { MonitorLocker ml(&_control_lock, Mutex::_no_safepoint_check_flag); - notify_cancellation(ml, cause); + notify_control_thread(ml, cause); } -void ShenandoahGenerationalControlThread::notify_cancellation(MonitorLocker& ml, GCCause::Cause cause) { - assert(_heap->cancelled_gc(), "GC should already be cancelled"); - log_debug(gc,thread)("Notify control (%s): %s", gc_mode_name(gc_mode()), GCCause::to_string(cause)); +void ShenandoahGenerationalControlThread::notify_control_thread(MonitorLocker& ml, GCCause::Cause cause) { + assert(_control_lock.is_locked(), "Request lock must be held here"); + log_debug(gc, thread)("Notify control (%s): %s", gc_mode_name(gc_mode()), GCCause::to_string(cause)); + _requested_gc_cause = cause; ml.notify(); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.hpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.hpp index b7dbedd5e84..13e69d25268 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.hpp @@ -135,16 +135,13 @@ private: // Return printable name for the given gc mode. static const char* gc_mode_name(GCMode mode); - // Takes the request lock and updates the requested cause and generation, then notifies the control thread. - // The overloaded variant should be used when the _control_lock is already held. + // These notify the control thread after updating _requested_gc_cause and (optionally) _requested_generation. + // Updating the requested generation is not necessary for allocation failures nor when stopping the thread. + void notify_control_thread(GCCause::Cause cause); + void notify_control_thread(MonitorLocker& ml, GCCause::Cause cause); void notify_control_thread(GCCause::Cause cause, ShenandoahGeneration* generation); void notify_control_thread(MonitorLocker& ml, GCCause::Cause cause, ShenandoahGeneration* generation); - // Notifies the control thread, but does not update the requested cause or generation. - // The overloaded variant should be used when the _control_lock is already held. - void notify_cancellation(GCCause::Cause cause); - void notify_cancellation(MonitorLocker& ml, GCCause::Cause cause); - // Configure the heap to age objects and regions if the aging period has elapsed. void maybe_set_aging_cycle(); From ad29642d8f4e8e0fb1223b14b85ab7841d7b1b51 Mon Sep 17 00:00:00 2001 From: Roland Westrelin Date: Mon, 15 Dec 2025 16:18:44 +0000 Subject: [PATCH 301/706] 8351889: C2 crash: assertion failed: Base pointers must match (addp 344) Reviewed-by: rcastanedalo, epeter --- src/hotspot/share/opto/addnode.hpp | 7 ++ src/hotspot/share/opto/c2_globals.hpp | 3 +- src/hotspot/share/opto/cfgnode.cpp | 36 +++++++++ src/hotspot/share/opto/cfgnode.hpp | 2 + src/hotspot/share/opto/compile.cpp | 5 +- src/hotspot/share/opto/phaseX.cpp | 21 ++++- src/hotspot/share/opto/phaseX.hpp | 5 ++ .../flags/jvmFlagConstraintsCompiler.cpp | 2 +- .../c2/TestMismatchedAddPAfterMaxUnroll.java | 80 +++++++++++++++++++ .../compiler/c2/TestVerifyIterativeGVN.java | 6 +- 10 files changed, 156 insertions(+), 11 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/c2/TestMismatchedAddPAfterMaxUnroll.java diff --git a/src/hotspot/share/opto/addnode.hpp b/src/hotspot/share/opto/addnode.hpp index 28ed73121ed..1bbdae92e48 100644 --- a/src/hotspot/share/opto/addnode.hpp +++ b/src/hotspot/share/opto/addnode.hpp @@ -246,6 +246,13 @@ public: // Do not match base-ptr edge virtual uint match_edge(uint idx) const; + +#ifdef ASSERT + bool address_input_has_same_base() const { + Node *addp = in(Address); + return !addp->is_AddP() || addp->in(Base)->is_top() || addp->in(Base) == in(Base); + } +#endif }; //------------------------------OrINode---------------------------------------- diff --git a/src/hotspot/share/opto/c2_globals.hpp b/src/hotspot/share/opto/c2_globals.hpp index 2b2b4db47b1..7fa3ca638c2 100644 --- a/src/hotspot/share/opto/c2_globals.hpp +++ b/src/hotspot/share/opto/c2_globals.hpp @@ -697,7 +697,8 @@ "Print progress during Iterative Global Value Numbering") \ \ develop(uint, VerifyIterativeGVN, 0, \ - "Verify Iterative Global Value Numbering =DCBA, with:" \ + "Verify Iterative Global Value Numbering =EDCBA, with:" \ + " E: verify node specific invariants" \ " D: verify Node::Identity did not miss opportunities" \ " C: verify Node::Ideal did not miss opportunities" \ " B: verify that type(n) == n->Value() after IGVN" \ diff --git a/src/hotspot/share/opto/cfgnode.cpp b/src/hotspot/share/opto/cfgnode.cpp index 203aa69ce1b..07657dd0883 100644 --- a/src/hotspot/share/opto/cfgnode.cpp +++ b/src/hotspot/share/opto/cfgnode.cpp @@ -2096,6 +2096,20 @@ bool PhiNode::is_split_through_mergemem_terminating() const { return true; } +// Is one of the inputs a Cast that has not been processed by igvn yet? +bool PhiNode::wait_for_cast_input_igvn(const PhaseIterGVN* igvn) const { + for (uint i = 1, cnt = req(); i < cnt; ++i) { + Node* n = in(i); + while (n != nullptr && n->is_ConstraintCast()) { + if (igvn->_worklist.member(n)) { + return true; + } + n = n->in(1); + } + } + return false; +} + //------------------------------Ideal------------------------------------------ // Return a node which is more "ideal" than the current node. Must preserve // the CFG, but we can still strip out dead paths. @@ -2154,6 +2168,28 @@ Node *PhiNode::Ideal(PhaseGVN *phase, bool can_reshape) { // If there is a chance that the region can be optimized out do // not add a cast node that we can't remove yet. !wait_for_region_igvn(phase)) { + // If one of the inputs is a cast that has yet to be processed by igvn, delay processing of this node to give the + // inputs a chance to optimize and possibly end up with identical inputs (casts included). + // Say we have: + // (Phi region (Cast#1 c uin) (Cast#2 c uin)) + // and Cast#1 and Cast#2 have not had a chance to common yet + // if the unique_input() transformation below proceeds, then PhiNode::Ideal returns: + // (Cast#3 region uin) (1) + // If PhiNode::Ideal is delayed until Cast#1 and Cast#2 common, then it returns: + // (Cast#1 c uin) (2) + // + // In (1) the resulting cast is conservatively pinned at a later control and while Cast#3 and Cast#1/Cast#2 still + // have a chance to common, that requires proving that c dominates region in ConstraintCastNode::dominating_cast() + // which may not happen if control flow is too complicated and another pass of loop opts doesn't run. Delaying the + // transformation here should allow a more optimal result. + // Beyond the efficiency concern, there is a risk, if the casts are CastPPs, to end up with a chain of AddPs with + // different base inputs (but a unique uncasted base input). This breaks an invariant in the shape of address + // subtrees. + PhaseIterGVN* igvn = phase->is_IterGVN(); + if (wait_for_cast_input_igvn(igvn)) { + igvn->_worklist.push(this); + return nullptr; + } uncasted = true; uin = unique_input(phase, true); } diff --git a/src/hotspot/share/opto/cfgnode.hpp b/src/hotspot/share/opto/cfgnode.hpp index bc0b38e2f97..f3ccf23703f 100644 --- a/src/hotspot/share/opto/cfgnode.hpp +++ b/src/hotspot/share/opto/cfgnode.hpp @@ -182,6 +182,8 @@ class PhiNode : public TypeNode { bool is_split_through_mergemem_terminating() const; + bool wait_for_cast_input_igvn(const PhaseIterGVN* igvn) const; + public: // Node layout (parallels RegionNode): enum { Region, // Control input is the Phi's region. diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index 621ba684da1..16f5be50805 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -3418,10 +3418,7 @@ void Compile::final_graph_reshaping_main_switch(Node* n, Final_Reshape_Counts& f case Op_AddP: { // Assert sane base pointers Node *addp = n->in(AddPNode::Address); - assert( !addp->is_AddP() || - addp->in(AddPNode::Base)->is_top() || // Top OK for allocation - addp->in(AddPNode::Base) == n->in(AddPNode::Base), - "Base pointers must match (addp %u)", addp->_idx ); + assert(n->as_AddP()->address_input_has_same_base(), "Base pointers must match (addp %u)", addp->_idx ); #ifdef _LP64 if ((UseCompressedOops || UseCompressedClassPointers) && addp->Opcode() == Op_ConP && diff --git a/src/hotspot/share/opto/phaseX.cpp b/src/hotspot/share/opto/phaseX.cpp index 4a0933b89f2..1e4cd42e09a 100644 --- a/src/hotspot/share/opto/phaseX.cpp +++ b/src/hotspot/share/opto/phaseX.cpp @@ -1076,7 +1076,8 @@ void PhaseIterGVN::verify_optimize() { if (is_verify_Value() || is_verify_Ideal() || - is_verify_Identity()) { + is_verify_Identity() || + is_verify_invariants()) { ResourceMark rm; Unique_Node_List worklist; bool failure = false; @@ -1088,6 +1089,7 @@ void PhaseIterGVN::verify_optimize() { if (is_verify_Ideal()) { failure |= verify_Ideal_for(n, false); } if (is_verify_Ideal()) { failure |= verify_Ideal_for(n, true); } if (is_verify_Identity()) { failure |= verify_Identity_for(n); } + if (is_verify_invariants()) { failure |= verify_node_invariants_for(n); } // traverse all inputs and outputs for (uint i = 0; i < n->req(); i++) { if (n->in(i) != nullptr) { @@ -1102,7 +1104,7 @@ void PhaseIterGVN::verify_optimize() { // We should either make sure that these nodes are properly added back to the IGVN worklist // in PhaseIterGVN::add_users_to_worklist to update them again or add an exception // in the verification code above if that is not possible for some reason (like Load nodes). - assert(!failure, "Missed optimization opportunity in PhaseIterGVN"); + assert(!failure, "Missed optimization opportunity/broken graph in PhaseIterGVN"); } verify_empty_worklist(nullptr); @@ -2058,6 +2060,21 @@ bool PhaseIterGVN::verify_Identity_for(Node* n) { tty->print_cr("%s", ss.as_string()); return true; } + +// Some other verifications that are not specific to a particular transformation. +bool PhaseIterGVN::verify_node_invariants_for(const Node* n) { + if (n->is_AddP()) { + if (!n->as_AddP()->address_input_has_same_base()) { + stringStream ss; // Print as a block without tty lock. + ss.cr(); + ss.print_cr("Base pointers must match for AddP chain:"); + n->dump_bfs(2, nullptr, "", &ss); + tty->print_cr("%s", ss.as_string()); + return true; + } + } + return false; +} #endif /** diff --git a/src/hotspot/share/opto/phaseX.hpp b/src/hotspot/share/opto/phaseX.hpp index 473231e6af5..3f75aab8980 100644 --- a/src/hotspot/share/opto/phaseX.hpp +++ b/src/hotspot/share/opto/phaseX.hpp @@ -493,6 +493,7 @@ public: bool verify_Value_for(Node* n, bool strict = false); bool verify_Ideal_for(Node* n, bool can_reshape); bool verify_Identity_for(Node* n); + bool verify_node_invariants_for(const Node* n); void verify_empty_worklist(Node* n); #endif @@ -616,6 +617,10 @@ public: // '-XX:VerifyIterativeGVN=1000' return ((VerifyIterativeGVN % 10000) / 1000) == 1; } + static bool is_verify_invariants() { + // '-XX:VerifyIterativeGVN=10000' + return ((VerifyIterativeGVN % 100000) / 10000) == 1; + } protected: // Sub-quadratic implementation of '-XX:VerifyIterativeGVN=1' (Use-Def verification). julong _verify_counter; diff --git a/src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.cpp b/src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.cpp index d0141c2e6cc..63d3424b3ed 100644 --- a/src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.cpp +++ b/src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.cpp @@ -306,7 +306,7 @@ JVMFlag::Error TypeProfileLevelConstraintFunc(uint value, bool verbose) { } JVMFlag::Error VerifyIterativeGVNConstraintFunc(uint value, bool verbose) { - const int max_modes = 4; + const int max_modes = 5; uint original_value = value; for (int i = 0; i < max_modes; i++) { if (value % 10 > 1) { diff --git a/test/hotspot/jtreg/compiler/c2/TestMismatchedAddPAfterMaxUnroll.java b/test/hotspot/jtreg/compiler/c2/TestMismatchedAddPAfterMaxUnroll.java new file mode 100644 index 00000000000..2dcafd2cf6a --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/TestMismatchedAddPAfterMaxUnroll.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2025, Red Hat, Inc. 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 8351889 + * @summary C2 crash: assertion failed: Base pointers must match (addp 344) + * @run main/othervm -XX:-BackgroundCompilation -XX:CompileOnly=TestMismatchedAddPAfterMaxUnroll::test1 + * -XX:+UnlockDiagnosticVMOptions -XX:+IgnoreUnrecognizedVMOptions -XX:-UseLoopPredicate + * -XX:+StressIGVN -XX:StressSeed=383593806 -XX:VerifyIterativeGVN=10000 + * TestMismatchedAddPAfterMaxUnroll + * @run main/othervm -XX:-BackgroundCompilation -XX:CompileOnly=TestMismatchedAddPAfterMaxUnroll::test1 + * -XX:+UnlockDiagnosticVMOptions -XX:+IgnoreUnrecognizedVMOptions -XX:-UseLoopPredicate + * -XX:+StressIGVN -XX:VerifyIterativeGVN=10000 TestMismatchedAddPAfterMaxUnroll + * @run main/othervm TestMismatchedAddPAfterMaxUnroll + */ + +public class TestMismatchedAddPAfterMaxUnroll { + private static C[] arrayField = new C[4]; + + public static void main(String[] args) { + C c = new C(); + Object lock = new Object(); + for (int i = 0; i < 20_000; i++) { + arrayField[3] = null; + test1(3, c, arrayField, true, true, lock); + arrayField[3] = null; + test1(3, c, arrayField, true, false, lock); + arrayField[3] = null; + test1(3, c, arrayField, false, false, lock); + arrayField[3] = c; + test1(3, c, arrayField, false, false, lock); + } + } + + static class C { + + } + + private static void test1(int j, C c, C[] otherArray, boolean flag, boolean flag2, Object lock) { + C[] array = arrayField; + int i = 0; + for (;;) { + synchronized (lock) {} + if (array[j] == null) { + break; + } + otherArray[i] = c; + i++; + if (i >= 3) { + return; + } + } + if (flag) { + if (flag2) { + } + } + array[j] = c; + } +} diff --git a/test/hotspot/jtreg/compiler/c2/TestVerifyIterativeGVN.java b/test/hotspot/jtreg/compiler/c2/TestVerifyIterativeGVN.java index 83f3540226f..4b6215b25bd 100644 --- a/test/hotspot/jtreg/compiler/c2/TestVerifyIterativeGVN.java +++ b/test/hotspot/jtreg/compiler/c2/TestVerifyIterativeGVN.java @@ -23,11 +23,11 @@ /* * @test - * @bug 8238756 + * @bug 8238756 8351889 * @requires vm.debug == true & vm.flavor == "server" - * @summary Run with -Xcomp to test -XX:VerifyIterativeGVN=1111 in debug builds. + * @summary Run with -Xcomp to test -XX:VerifyIterativeGVN=11111 in debug builds. * - * @run main/othervm/timeout=300 -Xcomp -XX:VerifyIterativeGVN=1111 compiler.c2.TestVerifyIterativeGVN + * @run main/othervm/timeout=300 -Xcomp -XX:VerifyIterativeGVN=11111 compiler.c2.TestVerifyIterativeGVN */ package compiler.c2; From 45ee89c4c8e3d8bb418b8578fb361e7dc1c12be5 Mon Sep 17 00:00:00 2001 From: Chris Plummer Date: Mon, 15 Dec 2025 19:50:46 +0000 Subject: [PATCH 302/706] 8373297: Test com/sun/jdi/AfterThreadDeathTest.java failed with unexpected ObjectCollectedException Reviewed-by: kevinw, sspitsyn, amenkov, lmesnik --- test/jdk/com/sun/jdi/AfterThreadDeathTest.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/test/jdk/com/sun/jdi/AfterThreadDeathTest.java b/test/jdk/com/sun/jdi/AfterThreadDeathTest.java index 27904021442..25987de864c 100644 --- a/test/jdk/com/sun/jdi/AfterThreadDeathTest.java +++ b/test/jdk/com/sun/jdi/AfterThreadDeathTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, 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 @@ -93,6 +93,7 @@ public class AfterThreadDeathTest extends TestScaffold { println("Ok; got expected IllegalThreadStateException"); return; } catch (Exception ee) { + ee.printStackTrace(System.err); failure("FAILED: Did not get expected" + " IllegalThreadStateException" + " on a StepRequest.enable(). \n" @@ -133,6 +134,13 @@ public class AfterThreadDeathTest extends TestScaffold { mainThread = bpe.thread(); erm = vm().eventRequestManager(); + /* + * The "main" thread will be referenced during the ThreadDeathEvent, which + * uses SUSPEND_NONE, so the thread might get gc'd and cause an unexpected + * ObjectCollectedException. Disable it from collection to prevent problems. + */ + mainThread.disableCollection(); + /* * Set event requests */ From f52d49925f9c60814a0a34720d7443e748b35c25 Mon Sep 17 00:00:00 2001 From: Sergey Chernyshev Date: Mon, 15 Dec 2025 20:19:05 +0000 Subject: [PATCH 303/706] 8319589: Attach from root to a user java process not supported in Mac Reviewed-by: sspitsyn --- src/hotspot/os/bsd/os_bsd.cpp | 84 +++++++++++++++++ src/hotspot/os/bsd/os_bsd.hpp | 8 +- src/hotspot/os/posix/os_posix.cpp | 4 + src/hotspot/os/posix/os_posix.hpp | 3 + src/hotspot/os/posix/perfMemory_posix.cpp | 18 +++- .../sun/tools/attach/VirtualMachineImpl.java | 56 +++++++++--- .../native/libattach/VirtualMachineImpl.c | 26 +----- .../sun/jvmstat/PlatformSupportImpl.java | 91 +++++++++++++++++++ .../share/classes/module-info.java | 4 +- 9 files changed, 252 insertions(+), 42 deletions(-) create mode 100644 src/jdk.internal.jvmstat/macosx/classes/sun/jvmstat/PlatformSupportImpl.java diff --git a/src/hotspot/os/bsd/os_bsd.cpp b/src/hotspot/os/bsd/os_bsd.cpp index dc8f5187b5a..61de48bb7fa 100644 --- a/src/hotspot/os/bsd/os_bsd.cpp +++ b/src/hotspot/os/bsd/os_bsd.cpp @@ -861,6 +861,90 @@ pid_t os::Bsd::gettid() { } } +// Returns the uid of a process or -1 on error. +uid_t os::Bsd::get_process_uid(pid_t pid) { + struct kinfo_proc kp; + size_t size = sizeof kp; + int mib_kern[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid}; + if (sysctl(mib_kern, 4, &kp, &size, nullptr, 0) == 0) { + if (size > 0 && kp.kp_proc.p_pid == pid) { + return kp.kp_eproc.e_ucred.cr_uid; + } + } + return (uid_t)-1; +} + +// Returns true if the process is running as root. +bool os::Bsd::is_process_root(pid_t pid) { + uid_t uid = get_process_uid(pid); + return (uid != (uid_t)-1) ? os::Posix::is_root(uid) : false; +} + +#ifdef __APPLE__ + +// macOS has a secure per-user temporary directory. +// Root can attach to a non-root process, hence it needs +// to lookup /var/folders for the user specific temporary directory +// of the form /var/folders/*/*/T, that contains PERFDATA_NAME_user +// directory. +static const char VAR_FOLDERS[] = "/var/folders/"; +int os::Bsd::get_user_tmp_dir_macos(const char* user, int vmid, char* output_path, int output_size) { + + // read the var/folders directory + DIR* varfolders_dir = os::opendir(VAR_FOLDERS); + if (varfolders_dir != nullptr) { + + // var/folders directory contains 2-characters subdirectories (buckets) + struct dirent* bucket_de; + + // loop until the PERFDATA_NAME_user directory has been found + while ((bucket_de = os::readdir(varfolders_dir)) != nullptr) { + // skip over files and special "." and ".." + if (bucket_de->d_type != DT_DIR || bucket_de->d_name[0] == '.') { + continue; + } + // absolute path to the bucket + char bucket[PATH_MAX]; + int b = os::snprintf(bucket, PATH_MAX, "%s%s/", VAR_FOLDERS, bucket_de->d_name); + + // the total length of the absolute path must not exceed the buffer size + if (b >= PATH_MAX || b < 0) { + continue; + } + // each bucket contains next level subdirectories + DIR* bucket_dir = os::opendir(bucket); + if (bucket_dir == nullptr) { + continue; + } + // read each subdirectory, skipping over regular files + struct dirent* subbucket_de; + while ((subbucket_de = os::readdir(bucket_dir)) != nullptr) { + if (subbucket_de->d_type != DT_DIR || subbucket_de->d_name[0] == '.') { + continue; + } + // If the PERFDATA_NAME_user directory exists in the T subdirectory, + // this means the subdirectory is the temporary directory of the user. + char perfdata_path[PATH_MAX]; + int p = os::snprintf(perfdata_path, PATH_MAX, "%s%s/T/%s_%s/", bucket, subbucket_de->d_name, PERFDATA_NAME, user); + + // the total length must not exceed the output buffer size + if (p >= PATH_MAX || p < 0) { + continue; + } + // check if the subdirectory exists + if (os::file_exists(perfdata_path)) { + // the return value of snprintf is not checked for the second time + return os::snprintf(output_path, output_size, "%s%s/T", bucket, subbucket_de->d_name); + } + } + os::closedir(bucket_dir); + } + os::closedir(varfolders_dir); + } + return -1; +} +#endif + intx os::current_thread_id() { #ifdef __APPLE__ return (intx)os::Bsd::gettid(); diff --git a/src/hotspot/os/bsd/os_bsd.hpp b/src/hotspot/os/bsd/os_bsd.hpp index 82002917f39..da73211b9a7 100644 --- a/src/hotspot/os/bsd/os_bsd.hpp +++ b/src/hotspot/os/bsd/os_bsd.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2025, 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 @@ -61,6 +61,12 @@ class os::Bsd { static pthread_t main_thread(void) { return _main_thread; } static pid_t gettid(); + static uid_t get_process_uid(pid_t pid); + static bool is_process_root(pid_t pid); + +#ifdef __APPLE__ + static int get_user_tmp_dir_macos(const char* user, int vmid, char* output_buffer, int buffer_size); +#endif static intptr_t* ucontext_get_sp(const ucontext_t* uc); static intptr_t* ucontext_get_fp(const ucontext_t* uc); diff --git a/src/hotspot/os/posix/os_posix.cpp b/src/hotspot/os/posix/os_posix.cpp index ef52b946cc6..07e1920c62d 100644 --- a/src/hotspot/os/posix/os_posix.cpp +++ b/src/hotspot/os/posix/os_posix.cpp @@ -1352,6 +1352,10 @@ bool os::Posix::is_root(uid_t uid){ return ROOT_UID == uid; } +bool os::Posix::is_current_user_root(){ + return is_root(geteuid()); +} + bool os::Posix::matches_effective_uid_or_root(uid_t uid) { return is_root(uid) || geteuid() == uid; } diff --git a/src/hotspot/os/posix/os_posix.hpp b/src/hotspot/os/posix/os_posix.hpp index 4b8b75ea07e..424d737cf42 100644 --- a/src/hotspot/os/posix/os_posix.hpp +++ b/src/hotspot/os/posix/os_posix.hpp @@ -76,6 +76,9 @@ public: // Returns true if given uid is root. static bool is_root(uid_t uid); + // Returns true if the current user is root. + static bool is_current_user_root(); + // Returns true if given uid is effective or root uid. static bool matches_effective_uid_or_root(uid_t uid); diff --git a/src/hotspot/os/posix/perfMemory_posix.cpp b/src/hotspot/os/posix/perfMemory_posix.cpp index 2cc0263d291..39bfc72a486 100644 --- a/src/hotspot/os/posix/perfMemory_posix.cpp +++ b/src/hotspot/os/posix/perfMemory_posix.cpp @@ -40,6 +40,9 @@ #if defined(LINUX) #include "os_linux.hpp" #endif +#if defined(BSD) +#include "os_bsd.hpp" +#endif # include # include @@ -142,6 +145,18 @@ static char* get_user_tmp_dir(const char* user, int vmid, int nspid) { jio_snprintf(buffer, TMP_BUFFER_LEN, "/proc/%d/root%s", vmid, tmpdir); tmpdir = buffer; } +#endif +#ifdef __APPLE__ + char buffer[PATH_MAX] = {0}; + // Check if the current user is root and the target VM is running as non-root. + // Otherwise the output of os::get_temp_directory() is used. + // + if (os::Posix::is_current_user_root() && !os::Bsd::is_process_root(vmid)) { + int path_size = os::Bsd::get_user_tmp_dir_macos(user, vmid, buffer, sizeof buffer); + if (path_size > 0 && (size_t)path_size < sizeof buffer) { + tmpdir = buffer; + } + } #endif const char* perfdir = PERFDATA_NAME; size_t nbytes = strlen(tmpdir) + strlen(perfdir) + strlen(user) + 3; @@ -1138,7 +1153,8 @@ static void mmap_attach_shared(int vmid, char** addr, size_t* sizep, TRAPS) { // for linux, determine if vmid is for a containerized process int nspid = LINUX_ONLY(os::Linux::get_namespace_pid(vmid)) NOT_LINUX(-1); - const char* luser = get_user_name(vmid, &nspid, CHECK); + const char* luser = NOT_MACOS(get_user_name(vmid, &nspid, CHECK)) + MACOS_ONLY(get_user_name(os::Bsd::get_process_uid(vmid))); if (luser == nullptr) { THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), diff --git a/src/jdk.attach/macosx/classes/sun/tools/attach/VirtualMachineImpl.java b/src/jdk.attach/macosx/classes/sun/tools/attach/VirtualMachineImpl.java index 5c786db1366..a7a348affe3 100644 --- a/src/jdk.attach/macosx/classes/sun/tools/attach/VirtualMachineImpl.java +++ b/src/jdk.attach/macosx/classes/sun/tools/attach/VirtualMachineImpl.java @@ -28,9 +28,13 @@ import com.sun.tools.attach.AgentLoadException; import com.sun.tools.attach.AttachNotSupportedException; import com.sun.tools.attach.spi.AttachProvider; +import sun.jvmstat.PlatformSupport; + import java.io.InputStream; import java.io.IOException; import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; import static java.nio.charset.StandardCharsets.UTF_8; @@ -39,14 +43,17 @@ import static java.nio.charset.StandardCharsets.UTF_8; */ @SuppressWarnings("restricted") public class VirtualMachineImpl extends HotSpotVirtualMachine { - // "tmpdir" is used as a global well-known location for the files - // .java_pid. and .attach_pid. It is important that this - // location is the same for all processes, otherwise the tools - // will not be able to find all Hotspot processes. - // This is intentionally not the same as java.io.tmpdir, since - // the latter can be changed by the user. - // Any changes to this needs to be synchronized with HotSpot. - private static final String tmpdir; + + /** + * HotSpot PerfData file prefix + */ + private static final String HSPERFDATA_PREFIX = "hsperfdata_"; + + /** + * Use platform specific methods for looking up temporary directories. + */ + private static final PlatformSupport platformSupport = PlatformSupport.getInstance(); + String socket_path; private OperationProperties props = new OperationProperties(VERSION_1); // updated in ctor @@ -67,10 +74,12 @@ public class VirtualMachineImpl extends HotSpotVirtualMachine { // Find the socket file. If not found then we attempt to start the // attach mechanism in the target VM by sending it a QUIT signal. // Then we attempt to find the socket file again. - File socket_file = new File(tmpdir, ".java_pid" + pid); + // In macOS the socket file is located in per-user temp directory. + String tempdir = getTempDirFromPid(pid); + File socket_file = new File(tempdir, ".java_pid" + pid); socket_path = socket_file.getPath(); if (!socket_file.exists()) { - File f = createAttachFile(pid); + File f = createAttachFile(tempdir, pid); try { checkCatchesAndSendQuitTo(pid, false); @@ -211,12 +220,34 @@ public class VirtualMachineImpl extends HotSpotVirtualMachine { } } - private File createAttachFile(int pid) throws IOException { + private File createAttachFile(String tmpdir, int pid) throws IOException { File f = new File(tmpdir, ".attach_pid" + pid); createAttachFile0(f.getPath()); return f; } + /* + * Returns a platform-specific temporary directory for a given process. + * In VMs running as unprivileged user it returns the default platform-specific + * temporary directory. In VMs running as root it searches over the list of + * temporary directories for one containing HotSpot PerfData directory. + */ + private String getTempDirFromPid(int pid) { + ProcessHandle ph = ProcessHandle.of(pid).orElse(null); + if (ph != null) { + String user = ph.info().user().orElse(null); + if (user != null) { + for (String dir : platformSupport.getTemporaryDirectories(pid)) { + Path fullPath = Path.of(dir, HSPERFDATA_PREFIX + user, String.valueOf(pid)); + if (Files.exists(fullPath)) { + return dir; + } + } + } + } + return PlatformSupport.getTemporaryDirectory(); + } + //-- native methods static native boolean checkCatchesAndSendQuitTo(int pid, boolean throwIfNotReady) throws IOException, AttachNotSupportedException; @@ -235,10 +266,7 @@ public class VirtualMachineImpl extends HotSpotVirtualMachine { static native void createAttachFile0(String path); - static native String getTempDir(); - static { System.loadLibrary("attach"); - tmpdir = getTempDir(); } } diff --git a/src/jdk.attach/macosx/native/libattach/VirtualMachineImpl.c b/src/jdk.attach/macosx/native/libattach/VirtualMachineImpl.c index d105d7d3b1b..5b2579eba39 100644 --- a/src/jdk.attach/macosx/native/libattach/VirtualMachineImpl.c +++ b/src/jdk.attach/macosx/native/libattach/VirtualMachineImpl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -335,27 +335,3 @@ JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_createAttachFile JNU_ReleaseStringPlatformChars(env, path, _path); } } - -/* - * Class: sun_tools_attach_BSDVirtualMachine - * Method: getTempDir - * Signature: (V)Ljava.lang.String; - */ -JNIEXPORT jstring JNICALL Java_sun_tools_attach_VirtualMachineImpl_getTempDir(JNIEnv *env, jclass cls) -{ - // This must be hard coded because it's the system's temporary - // directory not the java application's temp directory, ala java.io.tmpdir. - -#ifdef __APPLE__ - // macosx has a secure per-user temporary directory. - // Don't cache the result as this is only called once. - char path[PATH_MAX]; - int pathSize = confstr(_CS_DARWIN_USER_TEMP_DIR, path, PATH_MAX); - if (pathSize == 0 || pathSize > PATH_MAX) { - strlcpy(path, "/tmp", sizeof(path)); - } - return JNU_NewStringPlatform(env, path); -#else /* __APPLE__ */ - return (*env)->NewStringUTF(env, "/tmp"); -#endif /* __APPLE__ */ -} diff --git a/src/jdk.internal.jvmstat/macosx/classes/sun/jvmstat/PlatformSupportImpl.java b/src/jdk.internal.jvmstat/macosx/classes/sun/jvmstat/PlatformSupportImpl.java new file mode 100644 index 00000000000..f858fde4dce --- /dev/null +++ b/src/jdk.internal.jvmstat/macosx/classes/sun/jvmstat/PlatformSupportImpl.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, BELLSOFT. 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 sun.jvmstat; + +import java.io.IOException; +import java.nio.file.DirectoryStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; + +/* + * macOS specific implementation of the PlatformSupport routines + * providing temporary directory support. + */ +public class PlatformSupportImpl extends PlatformSupport { + + private static final String VAR_FOLDERS_PATH = "/var/folders"; + private static final String USER_NAME_SYSTEM_PROPERTY = "user.name"; + private static final String USER_NAME_ROOT = "root"; + private static final String DIRHELPER_TEMP_STR = "T"; + + private static final boolean isCurrentUserRoot = + System.getProperty(USER_NAME_SYSTEM_PROPERTY).equals(USER_NAME_ROOT); + + public PlatformSupportImpl() { + super(); + } + + /* + * Return a list of the temporary directories that the VM uses + * for the attach and perf data files. + * + * This function returns the traditional temp directory. Additionally, + * when called by root, it returns other temporary directories of non-root + * users. + * + * macOS per-user temp directories are located under /var/folders + * and have the form /var/folders///T + */ + @Override + public List getTemporaryDirectories(int pid) { + if (!isCurrentUserRoot) { + // early exit for non-root + return List.of(PlatformSupport.getTemporaryDirectory()); + } + List result = new ArrayList<>(); + try (DirectoryStream bs = Files.newDirectoryStream(Path.of(VAR_FOLDERS_PATH))) { + for (Path bucket : bs) { + try (DirectoryStream encUuids = Files.newDirectoryStream(bucket)) { + for (Path encUuid : encUuids) { + try { + Path tempDir = encUuid.resolve(DIRHELPER_TEMP_STR); + if (Files.isDirectory(tempDir) && Files.isReadable(tempDir)) { + result.add(tempDir.toString()); + } + } catch (Exception ignore) { // ignored unreadable bucket/encUuid, continue + } + } + } catch (IOException ignore) { // IOException ignored, continue to the next bucket + } + } + } catch (Exception ignore) { // var/folders directory is inaccessible / other errors + } + return result.isEmpty() ? List.of(PlatformSupport.getTemporaryDirectory()) : result; + } +} diff --git a/src/jdk.internal.jvmstat/share/classes/module-info.java b/src/jdk.internal.jvmstat/share/classes/module-info.java index 9e12c98b016..d9e1bc68008 100644 --- a/src/jdk.internal.jvmstat/share/classes/module-info.java +++ b/src/jdk.internal.jvmstat/share/classes/module-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, 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 @@ -40,6 +40,8 @@ module jdk.internal.jvmstat { jdk.jstatd; exports sun.jvmstat.perfdata.monitor to jdk.jstatd; + exports sun.jvmstat to + jdk.attach; uses sun.jvmstat.monitor.MonitoredHostService; From 6aeabd4bfaca168e9c88716b185979cf1e1b85ed Mon Sep 17 00:00:00 2001 From: Kieran Farrell Date: Mon, 15 Dec 2025 20:51:08 +0000 Subject: [PATCH 304/706] 8370910: Cleanup terminology of UUID vs Global Identifiers in UUID Reviewed-by: alanb, rriggs, jpai --- src/java.base/share/classes/java/util/UUID.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/java.base/share/classes/java/util/UUID.java b/src/java.base/share/classes/java/util/UUID.java index fa66d199239..f69ca8171cf 100644 --- a/src/java.base/share/classes/java/util/UUID.java +++ b/src/java.base/share/classes/java/util/UUID.java @@ -32,12 +32,11 @@ import jdk.internal.access.SharedSecrets; import jdk.internal.util.ByteArrayLittleEndian; /** - * A class that represents an immutable universally unique identifier (UUID). + * A class that represents an immutable Universally Unique IDentifier (UUID). * A UUID represents a 128-bit value. * - *

      There exist different variants of these global identifiers. The methods - * of this class are for manipulating the Leach-Salz variant, although the - * constructors allow the creation of any variant of UUID (described below). + *

      This class is primarily designed for manipulating Leach-Salz variant UUIDs, + * but it also supports the creation of UUIDs of other variants. * *

      The layout of a variant 2 (Leach-Salz) UUID is as follows: * From 317788ff12ee231bd3c9e8f1a0c9b38c8dad3feb Mon Sep 17 00:00:00 2001 From: Damon Nguyen Date: Mon, 15 Dec 2025 22:39:09 +0000 Subject: [PATCH 305/706] 8360160: ubuntu-22-04 machine is failing client tests Reviewed-by: prr, azvegint --- test/jdk/java/awt/Frame/FrameVisualTest.java | 73 +++++++++++--------- 1 file changed, 41 insertions(+), 32 deletions(-) diff --git a/test/jdk/java/awt/Frame/FrameVisualTest.java b/test/jdk/java/awt/Frame/FrameVisualTest.java index 767eb0a1896..39853822c44 100644 --- a/test/jdk/java/awt/Frame/FrameVisualTest.java +++ b/test/jdk/java/awt/Frame/FrameVisualTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2025, 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 @@ -46,62 +46,71 @@ import javax.imageio.ImageIO; public class FrameVisualTest { private static GraphicsConfiguration[] gcs; private static volatile Frame[] frames; - private static volatile int index; - private static Frame f; private static Robot robot; + private static volatile int frameNum; private static volatile Point p; private static volatile Dimension d; private static final int TOLERANCE = 5; + private static final int MAX_FRAME_COUNT = 30; public static void main(String[] args) throws Exception { - gcs = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getConfigurations(); + gcs = GraphicsEnvironment.getLocalGraphicsEnvironment() + .getDefaultScreenDevice().getConfigurations(); robot = new Robot(); robot.setAutoDelay(100); - try { - EventQueue.invokeAndWait(() -> { - createAndShowUI(); - }); - robot.delay(1000); - System.out.println("frames.length: "+frames.length); - for (index = 0; index < frames.length; index++) { + + // Limit the number of frames tested if needed + if (gcs.length > MAX_FRAME_COUNT) { + frames = new Frame[MAX_FRAME_COUNT]; + } else { + frames = new Frame[gcs.length]; + } + System.out.println(gcs.length + " gcs found. Testing " + + frames.length + " frame(s)."); + + for (frameNum = 0; frameNum < frames.length; frameNum++) { + try { EventQueue.invokeAndWait(() -> { - p = frames[index].getLocation(); - d = frames[index].getSize(); + frames[frameNum] = new Frame("Frame w/ gc " + + frameNum, gcs[frameNum]); + frames[frameNum].setSize(100, 100); + frames[frameNum].setUndecorated(true); + frames[frameNum].setBackground(Color.WHITE); + frames[frameNum].setVisible(true); + System.out.println("Frame " + frameNum + " created"); }); + + robot.delay(1000); + + EventQueue.invokeAndWait(() -> { + p = frames[frameNum].getLocation(); + d = frames[frameNum].getSize(); + }); + Rectangle rect = new Rectangle(p, d); BufferedImage img = robot.createScreenCapture(rect); if (chkImgBackgroundColor(img)) { try { - ImageIO.write(img, "png", new File("Frame_" + index + ".png")); + ImageIO.write(img, "png", + new File("Frame_" + + frameNum + ".png")); } catch (IOException ignored) {} - throw new RuntimeException("Frame visual test failed with non-white background color"); + throw new RuntimeException("Frame visual test " + + "failed with non-white background color"); } - } - } finally { - for (index = 0; index < frames.length; index++) { + } finally { EventQueue.invokeAndWait(() -> { - if (frames[index] != null) { - frames[index].dispose(); + if (frames[frameNum] != null) { + frames[frameNum].dispose(); + System.out.println("Frame " + frameNum + " disposed"); } }); } } } - private static void createAndShowUI() { - frames = new Frame[gcs.length]; - for (int i = 0; i < frames.length; i++) { - frames[i] = new Frame("Frame w/ gc " + i, gcs[i]); - frames[i].setSize(100, 100); - frames[i].setUndecorated(true); - frames[i].setBackground(Color.WHITE); - frames[i].setVisible(true); - } - } - private static boolean chkImgBackgroundColor(BufferedImage img) { - // scan for mid-line and if it is non-white color then return true. for (int x = 1; x < img.getWidth() - 1; ++x) { Color c = new Color(img.getRGB(x, img.getHeight() / 2)); From 1748737b99f283f69b4be0910b6623a27d804e68 Mon Sep 17 00:00:00 2001 From: David Holmes Date: Tue, 16 Dec 2025 00:19:01 +0000 Subject: [PATCH 306/706] 8372988: Test runtime/Nestmates/membership/TestNestHostErrorWithMultiThread.java failed: Unexpected interrupt Reviewed-by: coleenp, iklam, jsjolen --- src/hotspot/share/classfile/resolutionErrors.cpp | 6 ++---- src/hotspot/share/classfile/systemDictionary.cpp | 15 ++++++++++----- src/hotspot/share/classfile/systemDictionary.hpp | 2 +- src/hotspot/share/oops/instanceKlass.cpp | 10 ++++------ 4 files changed, 17 insertions(+), 16 deletions(-) diff --git a/src/hotspot/share/classfile/resolutionErrors.cpp b/src/hotspot/share/classfile/resolutionErrors.cpp index f5a335f17f3..c41d5d2f052 100644 --- a/src/hotspot/share/classfile/resolutionErrors.cpp +++ b/src/hotspot/share/classfile/resolutionErrors.cpp @@ -127,10 +127,8 @@ ResolutionErrorEntry::~ResolutionErrorEntry() { } void ResolutionErrorEntry::set_nest_host_error(const char* message) { - // If a message is already set, free it. - if (nest_host_error() != nullptr) { - FREE_C_HEAP_ARRAY(char, _nest_host_error); - } + assert(_nest_host_error == nullptr, "caller should have checked"); + assert_lock_strong(SystemDictionary_lock); _nest_host_error = message; } diff --git a/src/hotspot/share/classfile/systemDictionary.cpp b/src/hotspot/share/classfile/systemDictionary.cpp index e03d198eb9f..73738412017 100644 --- a/src/hotspot/share/classfile/systemDictionary.cpp +++ b/src/hotspot/share/classfile/systemDictionary.cpp @@ -1859,7 +1859,7 @@ Symbol* SystemDictionary::find_resolution_error(const constantPoolHandle& pool, void SystemDictionary::add_nest_host_error(const constantPoolHandle& pool, int which, - const char* message) { + const stringStream& message) { { MutexLocker ml(Thread::current(), SystemDictionary_lock); ResolutionErrorEntry* entry = ResolutionErrorTable::find_entry(pool, which); @@ -1868,14 +1868,19 @@ void SystemDictionary::add_nest_host_error(const constantPoolHandle& pool, // constant pool index. In this case resolution succeeded but there's an error in this nest host // that we use the table to record. assert(pool->resolved_klass_at(which) != nullptr, "klass should be resolved if there is no entry"); - ResolutionErrorTable::add_entry(pool, which, message); + ResolutionErrorTable::add_entry(pool, which, message.as_string(true /* on C-heap */)); } else { // An existing entry means we had a true resolution failure (LinkageError) with our nest host, but we // still want to add the error message for the higher-level access checks to report. We should // only reach here under the same error condition, so we can ignore the potential race with setting - // the message, and set it again. - assert(entry->nest_host_error() == nullptr || strcmp(entry->nest_host_error(), message) == 0, "should be the same message"); - entry->set_nest_host_error(message); + // the message. + const char* nhe = entry->nest_host_error(); + if (nhe == nullptr) { + entry->set_nest_host_error(message.as_string(true /* on C-heap */)); + } else { + DEBUG_ONLY(const char* msg = message.base();) + assert(strcmp(nhe, msg) == 0, "New message %s, differs from original %s", msg, nhe); + } } } } diff --git a/src/hotspot/share/classfile/systemDictionary.hpp b/src/hotspot/share/classfile/systemDictionary.hpp index 99e13fea61e..e32e0082f8f 100644 --- a/src/hotspot/share/classfile/systemDictionary.hpp +++ b/src/hotspot/share/classfile/systemDictionary.hpp @@ -280,7 +280,7 @@ public: // Record a nest host resolution/validation error static void add_nest_host_error(const constantPoolHandle& pool, int which, - const char* message); + const stringStream& message); static const char* find_nest_host_error(const constantPoolHandle& pool, int which); static void add_to_initiating_loader(JavaThread* current, InstanceKlass* k, diff --git a/src/hotspot/share/oops/instanceKlass.cpp b/src/hotspot/share/oops/instanceKlass.cpp index e74bc80d893..56a80daed60 100644 --- a/src/hotspot/share/oops/instanceKlass.cpp +++ b/src/hotspot/share/oops/instanceKlass.cpp @@ -312,12 +312,11 @@ InstanceKlass* InstanceKlass::nest_host(TRAPS) { ss.print("Nest host resolution of %s with host %s failed: ", this->external_name(), target_host_class); java_lang_Throwable::print(PENDING_EXCEPTION, &ss); - const char* msg = ss.as_string(true /* on C-heap */); constantPoolHandle cph(THREAD, constants()); - SystemDictionary::add_nest_host_error(cph, _nest_host_index, msg); + SystemDictionary::add_nest_host_error(cph, _nest_host_index, ss); CLEAR_PENDING_EXCEPTION; - log_trace(class, nestmates)("%s", msg); + log_trace(class, nestmates)("%s", ss.base()); } else { // A valid nest-host is an instance class in the current package that lists this // class as a nest member. If any of these conditions are not met the class is @@ -356,10 +355,9 @@ InstanceKlass* InstanceKlass::nest_host(TRAPS) { k->external_name(), k->class_loader_data()->loader_name_and_id(), error); - const char* msg = ss.as_string(true /* on C-heap */); constantPoolHandle cph(THREAD, constants()); - SystemDictionary::add_nest_host_error(cph, _nest_host_index, msg); - log_trace(class, nestmates)("%s", msg); + SystemDictionary::add_nest_host_error(cph, _nest_host_index, ss); + log_trace(class, nestmates)("%s", ss.base()); } } } else { From 3f33eaa42aff45422c94300573c898868189fdfc Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Tue, 16 Dec 2025 04:03:12 +0000 Subject: [PATCH 307/706] 8373649: Convert simple AtomicAccess usage in ConcurrentHashTable to use Atomic Reviewed-by: tschatzl, iwalulya --- .../share/utilities/concurrentHashTable.hpp | 11 +-- .../utilities/concurrentHashTable.inline.hpp | 73 ++++++++++--------- .../concurrentHashTableTasks.inline.hpp | 29 ++++---- 3 files changed, 58 insertions(+), 55 deletions(-) diff --git a/src/hotspot/share/utilities/concurrentHashTable.hpp b/src/hotspot/share/utilities/concurrentHashTable.hpp index a837a56a19a..1a50ecabc3e 100644 --- a/src/hotspot/share/utilities/concurrentHashTable.hpp +++ b/src/hotspot/share/utilities/concurrentHashTable.hpp @@ -26,6 +26,7 @@ #define SHARE_UTILITIES_CONCURRENTHASHTABLE_HPP #include "memory/allocation.hpp" +#include "runtime/atomic.hpp" #include "runtime/mutex.hpp" #include "utilities/globalCounter.hpp" #include "utilities/globalDefinitions.hpp" @@ -246,7 +247,7 @@ class ConcurrentHashTable : public CHeapObj { const size_t _log2_start_size; // Start size. const size_t _grow_hint; // Number of linked items - volatile bool _size_limit_reached; + Atomic _size_limit_reached; // We serialize resizers and other bulk operations which do not support // concurrent resize with this lock. @@ -255,7 +256,7 @@ class ConcurrentHashTable : public CHeapObj { // taking the mutex after a safepoint this bool is the actual state. After // acquiring the mutex you must check if this is already locked. If so you // must drop the mutex until the real lock holder grabs the mutex. - volatile Thread* _resize_lock_owner; + Atomic _resize_lock_owner; // Return true if lock mutex/state succeeded. bool try_resize_lock(Thread* locker); @@ -273,7 +274,7 @@ class ConcurrentHashTable : public CHeapObj { // this field keep tracks if a version of the hash-table was ever been seen. // We the working thread pointer as tag for debugging. The _invisible_epoch // can only be used by the owner of _resize_lock. - volatile Thread* _invisible_epoch; + Atomic _invisible_epoch; // Scoped critical section, which also handles the invisible epochs. // An invisible epoch/version do not need a write_synchronize(). @@ -435,11 +436,11 @@ class ConcurrentHashTable : public CHeapObj { size_t get_size_log2(Thread* thread); static size_t get_node_size() { return sizeof(Node); } static size_t get_dynamic_node_size(size_t value_size); - bool is_max_size_reached() { return _size_limit_reached; } + bool is_max_size_reached() { return _size_limit_reached.load_relaxed(); } // This means no paused bucket resize operation is going to resume // on this table. - bool is_safepoint_safe() { return _resize_lock_owner == nullptr; } + bool is_safepoint_safe() { return _resize_lock_owner.load_relaxed() == nullptr; } // Re-size operations. bool shrink(Thread* thread, size_t size_limit_log2 = 0); diff --git a/src/hotspot/share/utilities/concurrentHashTable.inline.hpp b/src/hotspot/share/utilities/concurrentHashTable.inline.hpp index eeaff0167b2..b96a487324c 100644 --- a/src/hotspot/share/utilities/concurrentHashTable.inline.hpp +++ b/src/hotspot/share/utilities/concurrentHashTable.inline.hpp @@ -29,6 +29,7 @@ #include "cppstdlib/type_traits.hpp" #include "memory/allocation.inline.hpp" +#include "runtime/atomic.hpp" #include "runtime/atomicAccess.hpp" #include "runtime/orderAccess.hpp" #include "runtime/prefetch.inline.hpp" @@ -221,8 +222,8 @@ inline ConcurrentHashTable:: _cs_context(GlobalCounter::critical_section_begin(_thread)) { // This version is published now. - if (AtomicAccess::load_acquire(&_cht->_invisible_epoch) != nullptr) { - AtomicAccess::release_store_fence(&_cht->_invisible_epoch, (Thread*)nullptr); + if (_cht->_invisible_epoch.load_acquire() != nullptr) { + _cht->_invisible_epoch.release_store_fence(nullptr); } } @@ -282,16 +283,16 @@ template inline void ConcurrentHashTable:: write_synchonize_on_visible_epoch(Thread* thread) { - assert(_resize_lock_owner == thread, "Re-size lock not held"); + assert(_resize_lock_owner.load_relaxed() == thread, "Re-size lock not held"); OrderAccess::fence(); // Prevent below load from floating up. // If no reader saw this version we can skip write_synchronize. - if (AtomicAccess::load_acquire(&_invisible_epoch) == thread) { + if (_invisible_epoch.load_acquire() == thread) { return; } - assert(_invisible_epoch == nullptr, "Two thread doing bulk operations"); + assert(_invisible_epoch.load_relaxed() == nullptr, "Two thread doing bulk operations"); // We set this/next version that we are synchronizing for to not published. // A reader will zero this flag if it reads this/next version. - AtomicAccess::release_store(&_invisible_epoch, thread); + _invisible_epoch.release_store(thread); GlobalCounter::write_synchronize(); } @@ -300,8 +301,8 @@ inline bool ConcurrentHashTable:: try_resize_lock(Thread* locker) { if (_resize_lock->try_lock()) { - if (_resize_lock_owner != nullptr) { - assert(locker != _resize_lock_owner, "Already own lock"); + if (_resize_lock_owner.load_relaxed() != nullptr) { + assert(locker != _resize_lock_owner.load_relaxed(), "Already own lock"); // We got mutex but internal state is locked. _resize_lock->unlock(); return false; @@ -309,8 +310,8 @@ inline bool ConcurrentHashTable:: } else { return false; } - _invisible_epoch = nullptr; - _resize_lock_owner = locker; + _invisible_epoch.store_relaxed(nullptr); + _resize_lock_owner.store_relaxed(locker); return true; } @@ -326,8 +327,8 @@ inline void ConcurrentHashTable:: _resize_lock->lock_without_safepoint_check(); // If holder of lock dropped mutex for safepoint mutex might be unlocked, // and _resize_lock_owner will contain the owner. - if (_resize_lock_owner != nullptr) { - assert(locker != _resize_lock_owner, "Already own lock"); + if (_resize_lock_owner.load_relaxed() != nullptr) { + assert(locker != _resize_lock_owner.load_relaxed(), "Already own lock"); // We got mutex but internal state is locked. _resize_lock->unlock(); yield.wait(); @@ -335,17 +336,17 @@ inline void ConcurrentHashTable:: break; } } while(true); - _resize_lock_owner = locker; - _invisible_epoch = nullptr; + _resize_lock_owner.store_relaxed(locker); + _invisible_epoch.store_relaxed(nullptr); } template inline void ConcurrentHashTable:: unlock_resize_lock(Thread* locker) { - _invisible_epoch = nullptr; - assert(locker == _resize_lock_owner, "Not unlocked by locker."); - _resize_lock_owner = nullptr; + _invisible_epoch.store_relaxed(nullptr); + assert(locker == _resize_lock_owner.load_relaxed(), "Not unlocked by locker."); + _resize_lock_owner.store_relaxed(nullptr); _resize_lock->unlock(); } @@ -477,8 +478,8 @@ inline void ConcurrentHashTable:: { // Here we have resize lock so table is SMR safe, and there is no new // table. Can do this in parallel if we want. - assert((is_mt && _resize_lock_owner != nullptr) || - (!is_mt && _resize_lock_owner == thread), "Re-size lock not held"); + assert((is_mt && _resize_lock_owner.load_relaxed() != nullptr) || + (!is_mt && _resize_lock_owner.load_relaxed() == thread), "Re-size lock not held"); Node* ndel_stack[StackBufferSize]; InternalTable* table = get_table(); assert(start_idx < stop_idx, "Must be"); @@ -696,7 +697,7 @@ inline bool ConcurrentHashTable:: if (!try_resize_lock(thread)) { return false; } - assert(_resize_lock_owner == thread, "Re-size lock not held"); + assert(_resize_lock_owner.load_relaxed() == thread, "Re-size lock not held"); if (_table->_log2_size == _log2_start_size || _table->_log2_size <= log2_size) { unlock_resize_lock(thread); @@ -710,10 +711,10 @@ template inline void ConcurrentHashTable:: internal_shrink_epilog(Thread* thread) { - assert(_resize_lock_owner == thread, "Re-size lock not held"); + assert(_resize_lock_owner.load_relaxed() == thread, "Re-size lock not held"); InternalTable* old_table = set_table_from_new(); - _size_limit_reached = false; + _size_limit_reached.store_relaxed(false); unlock_resize_lock(thread); #ifdef ASSERT for (size_t i = 0; i < old_table->_size; i++) { @@ -767,13 +768,13 @@ inline bool ConcurrentHashTable:: internal_shrink(Thread* thread, size_t log2_size) { if (!internal_shrink_prolog(thread, log2_size)) { - assert(_resize_lock_owner != thread, "Re-size lock held"); + assert(_resize_lock_owner.load_relaxed() != thread, "Re-size lock held"); return false; } - assert(_resize_lock_owner == thread, "Should be locked by me"); + assert(_resize_lock_owner.load_relaxed() == thread, "Should be locked by me"); internal_shrink_range(thread, 0, _new_table->_size); internal_shrink_epilog(thread); - assert(_resize_lock_owner != thread, "Re-size lock held"); + assert(_resize_lock_owner.load_relaxed() != thread, "Re-size lock held"); return true; } @@ -787,7 +788,7 @@ inline void ConcurrentHashTable:: delete _table; // Create and publish a new table InternalTable* table = new InternalTable(log2_size); - _size_limit_reached = (log2_size == _log2_size_limit); + _size_limit_reached.store_relaxed(log2_size == _log2_size_limit); AtomicAccess::release_store(&_table, table); } @@ -812,7 +813,7 @@ inline bool ConcurrentHashTable:: } _new_table = new InternalTable(_table->_log2_size + 1); - _size_limit_reached = _new_table->_log2_size == _log2_size_limit; + _size_limit_reached.store_relaxed(_new_table->_log2_size == _log2_size_limit); return true; } @@ -821,7 +822,7 @@ template inline void ConcurrentHashTable:: internal_grow_epilog(Thread* thread) { - assert(_resize_lock_owner == thread, "Should be locked"); + assert(_resize_lock_owner.load_relaxed() == thread, "Should be locked"); InternalTable* old_table = set_table_from_new(); unlock_resize_lock(thread); @@ -840,13 +841,13 @@ inline bool ConcurrentHashTable:: internal_grow(Thread* thread, size_t log2_size) { if (!internal_grow_prolog(thread, log2_size)) { - assert(_resize_lock_owner != thread, "Re-size lock held"); + assert(_resize_lock_owner.load_relaxed() != thread, "Re-size lock held"); return false; } - assert(_resize_lock_owner == thread, "Should be locked by me"); + assert(_resize_lock_owner.load_relaxed() == thread, "Should be locked by me"); internal_grow_range(thread, 0, _table->_size); internal_grow_epilog(thread); - assert(_resize_lock_owner != thread, "Re-size lock held"); + assert(_resize_lock_owner.load_relaxed() != thread, "Re-size lock held"); return true; } @@ -961,7 +962,7 @@ template inline void ConcurrentHashTable:: do_scan_locked(Thread* thread, FUNC& scan_f) { - assert(_resize_lock_owner == thread, "Re-size lock not held"); + assert(_resize_lock_owner.load_relaxed() == thread, "Re-size lock not held"); // We can do a critical section over the entire loop but that would block // updates for a long time. Instead we choose to block resizes. InternalTable* table = get_table(); @@ -1020,7 +1021,7 @@ ConcurrentHashTable(size_t log2size, size_t log2size_limit, size_t grow_hint, bo _resize_lock = new Mutex(rank, "ConcurrentHashTableResize_lock"); _table = new InternalTable(log2size); assert(log2size_limit >= log2size, "bad ergo"); - _size_limit_reached = _table->_log2_size == _log2_size_limit; + _size_limit_reached.store_relaxed(_table->_log2_size == _log2_size_limit); } template @@ -1139,11 +1140,11 @@ inline void ConcurrentHashTable:: { assert(!SafepointSynchronize::is_at_safepoint(), "must be outside a safepoint"); - assert(_resize_lock_owner != thread, "Re-size lock held"); + assert(_resize_lock_owner.load_relaxed() != thread, "Re-size lock held"); lock_resize_lock(thread); do_scan_locked(thread, scan_f); unlock_resize_lock(thread); - assert(_resize_lock_owner != thread, "Re-size lock held"); + assert(_resize_lock_owner.load_relaxed() != thread, "Re-size lock held"); } template @@ -1205,7 +1206,7 @@ inline bool ConcurrentHashTable:: } do_bulk_delete_locked(thread, eval_f, del_f); unlock_resize_lock(thread); - assert(_resize_lock_owner != thread, "Re-size lock held"); + assert(_resize_lock_owner.load_relaxed() != thread, "Re-size lock held"); return true; } diff --git a/src/hotspot/share/utilities/concurrentHashTableTasks.inline.hpp b/src/hotspot/share/utilities/concurrentHashTableTasks.inline.hpp index 086a548ede5..054008953a8 100644 --- a/src/hotspot/share/utilities/concurrentHashTableTasks.inline.hpp +++ b/src/hotspot/share/utilities/concurrentHashTableTasks.inline.hpp @@ -27,6 +27,7 @@ // No concurrentHashTableTasks.hpp +#include "runtime/atomic.hpp" #include "runtime/atomicAccess.hpp" #include "utilities/concurrentHashTable.inline.hpp" #include "utilities/globalDefinitions.hpp" @@ -41,7 +42,7 @@ class ConcurrentHashTable::BucketsOperation { ConcurrentHashTable* _cht; class InternalTableClaimer { - volatile size_t _next; + Atomic _next; size_t _limit; size_t _size; @@ -56,14 +57,14 @@ public: void set(size_t claim_size, InternalTable* table) { assert(table != nullptr, "precondition"); - _next = 0; + _next.store_relaxed(0); _limit = table->_size; _size = MIN2(claim_size, _limit); } bool claim(size_t* start, size_t* stop) { - if (AtomicAccess::load(&_next) < _limit) { - size_t claimed = AtomicAccess::fetch_then_add(&_next, _size); + if (_next.load_relaxed() < _limit) { + size_t claimed = _next.fetch_then_add(_size); if (claimed < _limit) { *start = claimed; *stop = MIN2(claimed + _size, _limit); @@ -78,7 +79,7 @@ public: } bool have_more_work() { - return AtomicAccess::load_acquire(&_next) >= _limit; + return _next.load_acquire() >= _limit; } }; @@ -108,13 +109,13 @@ public: } void thread_owns_resize_lock(Thread* thread) { - assert(BucketsOperation::_cht->_resize_lock_owner == thread, + assert(BucketsOperation::_cht->_resize_lock_owner.load_relaxed() == thread, "Should be locked by me"); assert(BucketsOperation::_cht->_resize_lock->owned_by_self(), "Operations lock not held"); } void thread_owns_only_state_lock(Thread* thread) { - assert(BucketsOperation::_cht->_resize_lock_owner == thread, + assert(BucketsOperation::_cht->_resize_lock_owner.load_relaxed() == thread, "Should be locked by me"); assert(!BucketsOperation::_cht->_resize_lock->owned_by_self(), "Operations lock held"); @@ -122,7 +123,7 @@ public: void thread_do_not_own_resize_lock(Thread* thread) { assert(!BucketsOperation::_cht->_resize_lock->owned_by_self(), "Operations lock held"); - assert(BucketsOperation::_cht->_resize_lock_owner != thread, + assert(BucketsOperation::_cht->_resize_lock_owner.load_relaxed() != thread, "Should not be locked by me"); } @@ -169,7 +170,7 @@ class ConcurrentHashTable::BulkDeleteTask : template bool do_task(Thread* thread, EVALUATE_FUNC& eval_f, DELETE_FUNC& del_f) { size_t start, stop; - assert(BucketsOperation::_cht->_resize_lock_owner != nullptr, + assert(BucketsOperation::_cht->_resize_lock_owner.load_relaxed() != nullptr, "Should be locked"); if (!this->claim(&start, &stop)) { return false; @@ -177,7 +178,7 @@ class ConcurrentHashTable::BulkDeleteTask : BucketsOperation::_cht->do_bulk_delete_locked_for(thread, start, stop, eval_f, del_f, BucketsOperation::_is_mt); - assert(BucketsOperation::_cht->_resize_lock_owner != nullptr, + assert(BucketsOperation::_cht->_resize_lock_owner.load_relaxed() != nullptr, "Should be locked"); return true; } @@ -210,13 +211,13 @@ class ConcurrentHashTable::GrowTask : // Re-sizes a portion of the table. Returns true if there is more work. bool do_task(Thread* thread) { size_t start, stop; - assert(BucketsOperation::_cht->_resize_lock_owner != nullptr, + assert(BucketsOperation::_cht->_resize_lock_owner.load_relaxed() != nullptr, "Should be locked"); if (!this->claim(&start, &stop)) { return false; } BucketsOperation::_cht->internal_grow_range(thread, start, stop); - assert(BucketsOperation::_cht->_resize_lock_owner != nullptr, + assert(BucketsOperation::_cht->_resize_lock_owner.load_relaxed() != nullptr, "Should be locked"); return true; } @@ -253,13 +254,13 @@ class ConcurrentHashTable::StatisticsTask : template bool do_task(Thread* thread, VALUE_SIZE_FUNC& sz) { size_t start, stop; - assert(BucketsOperation::_cht->_resize_lock_owner != nullptr, + assert(BucketsOperation::_cht->_resize_lock_owner.load_relaxed() != nullptr, "Should be locked"); if (!this->claim(&start, &stop)) { return false; } BucketsOperation::_cht->internal_statistics_range(thread, start, stop, sz, _summary, _literal_bytes); - assert(BucketsOperation::_cht->_resize_lock_owner != nullptr, + assert(BucketsOperation::_cht->_resize_lock_owner.load_relaxed() != nullptr, "Should be locked"); return true; } From b1e8c4e030f42ea3146b2502c9ab030bc79a8147 Mon Sep 17 00:00:00 2001 From: Rui Li Date: Tue, 16 Dec 2025 07:02:15 +0000 Subject: [PATCH 308/706] 8372543: Shenandoah: undercalculated the available size when soft max takes effect Reviewed-by: wkemper, kdnilsen --- .../shenandoahAdaptiveHeuristics.cpp | 13 +- .../shenandoahCompactHeuristics.cpp | 14 +- .../heuristics/shenandoahSpaceInfo.hpp | 2 +- .../heuristics/shenandoahStaticHeuristics.cpp | 16 +-- .../share/gc/shenandoah/shenandoahFreeSet.cpp | 82 +++++------- .../share/gc/shenandoah/shenandoahFreeSet.hpp | 1 + .../gc/shenandoah/shenandoahGeneration.cpp | 4 +- .../gc/shenandoah/shenandoahGeneration.hpp | 2 +- .../shenandoah/shenandoahGlobalGeneration.cpp | 9 -- .../shenandoah/shenandoahGlobalGeneration.hpp | 1 - .../shenandoah/shenandoahYoungGeneration.cpp | 4 +- .../shenandoah/shenandoahYoungGeneration.hpp | 2 +- .../TestSoftMaxHeapSizeAvailableCalc.java | 123 ++++++++++++++++++ 13 files changed, 182 insertions(+), 91 deletions(-) create mode 100644 test/hotspot/jtreg/gc/shenandoah/TestSoftMaxHeapSizeAvailableCalc.java diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.cpp index 6498f0acdb6..41535f302d7 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.cpp @@ -31,7 +31,6 @@ #include "gc/shenandoah/heuristics/shenandoahSpaceInfo.hpp" #include "gc/shenandoah/shenandoahCollectionSet.hpp" #include "gc/shenandoah/shenandoahCollectorPolicy.hpp" -#include "gc/shenandoah/shenandoahFreeSet.hpp" #include "gc/shenandoah/shenandoahHeap.inline.hpp" #include "gc/shenandoah/shenandoahHeapRegion.inline.hpp" #include "logging/log.hpp" @@ -234,11 +233,12 @@ static double saturate(double value, double min, double max) { // allocation rate computation independent. bool ShenandoahAdaptiveHeuristics::should_start_gc() { size_t capacity = ShenandoahHeap::heap()->soft_max_capacity(); - size_t available = _space_info->soft_available(); + size_t available = _space_info->soft_mutator_available(); size_t allocated = _space_info->bytes_allocated_since_gc_start(); - log_debug(gc)("should_start_gc? available: %zu, soft_max_capacity: %zu" - ", allocated: %zu", available, capacity, allocated); + log_debug(gc, ergo)("should_start_gc calculation: available: " PROPERFMT ", soft_max_capacity: " PROPERFMT ", " + "allocated_since_gc_start: " PROPERFMT, + PROPERFMTARGS(available), PROPERFMTARGS(capacity), PROPERFMTARGS(allocated)); // Track allocation rate even if we decide to start a cycle for other reasons. double rate = _allocation_rate.sample(allocated); @@ -252,9 +252,8 @@ bool ShenandoahAdaptiveHeuristics::should_start_gc() { size_t min_threshold = min_free_threshold(); if (available < min_threshold) { - log_trigger("Free (%zu%s) is below minimum threshold (%zu%s)", - byte_size_in_proper_unit(available), proper_unit_for_byte_size(available), - byte_size_in_proper_unit(min_threshold), proper_unit_for_byte_size(min_threshold)); + log_trigger("Free (Soft) (" PROPERFMT ") is below minimum threshold (" PROPERFMT ")", + PROPERFMTARGS(available), PROPERFMTARGS(min_threshold)); accept_trigger_with_type(OTHER); return true; } diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahCompactHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahCompactHeuristics.cpp index f8a77d95d51..28673b28612 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahCompactHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahCompactHeuristics.cpp @@ -26,7 +26,6 @@ #include "gc/shenandoah/heuristics/shenandoahCompactHeuristics.hpp" #include "gc/shenandoah/shenandoahCollectionSet.hpp" -#include "gc/shenandoah/shenandoahFreeSet.hpp" #include "gc/shenandoah/shenandoahHeap.inline.hpp" #include "gc/shenandoah/shenandoahHeapRegion.inline.hpp" #include "logging/log.hpp" @@ -47,26 +46,25 @@ ShenandoahCompactHeuristics::ShenandoahCompactHeuristics(ShenandoahSpaceInfo* sp } bool ShenandoahCompactHeuristics::should_start_gc() { - size_t max_capacity = _space_info->max_capacity(); size_t capacity = ShenandoahHeap::heap()->soft_max_capacity(); - size_t available = _space_info->available(); + size_t available = _space_info->soft_mutator_available(); + size_t bytes_allocated = _space_info->bytes_allocated_since_gc_start(); - // Make sure the code below treats available without the soft tail. - size_t soft_tail = max_capacity - capacity; - available = (available > soft_tail) ? (available - soft_tail) : 0; + log_debug(gc, ergo)("should_start_gc calculation: available: " PROPERFMT ", soft_max_capacity: " PROPERFMT ", " + "allocated_since_gc_start: " PROPERFMT, + PROPERFMTARGS(available), PROPERFMTARGS(capacity), PROPERFMTARGS(bytes_allocated)); size_t threshold_bytes_allocated = capacity / 100 * ShenandoahAllocationThreshold; size_t min_threshold = capacity / 100 * ShenandoahMinFreeThreshold; if (available < min_threshold) { - log_trigger("Free (%zu%s) is below minimum threshold (%zu%s)", + log_trigger("Free (Soft) (%zu%s) is below minimum threshold (%zu%s)", byte_size_in_proper_unit(available), proper_unit_for_byte_size(available), byte_size_in_proper_unit(min_threshold), proper_unit_for_byte_size(min_threshold)); accept_trigger(); return true; } - size_t bytes_allocated = _space_info->bytes_allocated_since_gc_start(); if (bytes_allocated > threshold_bytes_allocated) { log_trigger("Allocated since last cycle (%zu%s) is larger than allocation threshold (%zu%s)", byte_size_in_proper_unit(bytes_allocated), proper_unit_for_byte_size(bytes_allocated), diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahSpaceInfo.hpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahSpaceInfo.hpp index 7fb44c7b71b..6ed05abf0b1 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahSpaceInfo.hpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahSpaceInfo.hpp @@ -38,7 +38,7 @@ class ShenandoahSpaceInfo { public: virtual const char* name() const = 0; virtual size_t max_capacity() const = 0; - virtual size_t soft_available() const = 0; + virtual size_t soft_mutator_available() const = 0; virtual size_t available() const = 0; virtual size_t used() const = 0; diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahStaticHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahStaticHeuristics.cpp index 205135751aa..d4d66fef6a1 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahStaticHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahStaticHeuristics.cpp @@ -26,7 +26,6 @@ #include "gc/shenandoah/heuristics/shenandoahStaticHeuristics.hpp" #include "gc/shenandoah/shenandoahCollectionSet.hpp" -#include "gc/shenandoah/shenandoahFreeSet.hpp" #include "gc/shenandoah/shenandoahHeap.inline.hpp" #include "gc/shenandoah/shenandoahHeapRegion.inline.hpp" #include "logging/log.hpp" @@ -41,20 +40,19 @@ ShenandoahStaticHeuristics::ShenandoahStaticHeuristics(ShenandoahSpaceInfo* spac ShenandoahStaticHeuristics::~ShenandoahStaticHeuristics() {} bool ShenandoahStaticHeuristics::should_start_gc() { - size_t max_capacity = _space_info->max_capacity(); size_t capacity = ShenandoahHeap::heap()->soft_max_capacity(); - size_t available = _space_info->available(); + size_t available = _space_info->soft_mutator_available(); + size_t allocated = _space_info->bytes_allocated_since_gc_start(); - // Make sure the code below treats available without the soft tail. - size_t soft_tail = max_capacity - capacity; - available = (available > soft_tail) ? (available - soft_tail) : 0; + log_debug(gc, ergo)("should_start_gc calculation: available: " PROPERFMT ", soft_max_capacity: " PROPERFMT ", " + "allocated_since_gc_start: " PROPERFMT, + PROPERFMTARGS(available), PROPERFMTARGS(capacity), PROPERFMTARGS(allocated)); size_t threshold_available = capacity / 100 * ShenandoahMinFreeThreshold; if (available < threshold_available) { - log_trigger("Free (%zu%s) is below minimum threshold (%zu%s)", - byte_size_in_proper_unit(available), proper_unit_for_byte_size(available), - byte_size_in_proper_unit(threshold_available), proper_unit_for_byte_size(threshold_available)); + log_trigger("Free (Soft) (" PROPERFMT ") is below minimum threshold (" PROPERFMT ")", + PROPERFMTARGS(available), PROPERFMTARGS(threshold_available)); accept_trigger(); return true; } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp index eb05bf24028..c03e66e28da 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp @@ -2921,6 +2921,29 @@ void ShenandoahFreeSet::log_status_under_lock() { } } +void ShenandoahFreeSet::log_freeset_stats(ShenandoahFreeSetPartitionId partition_id, LogStream& ls) { + size_t max = 0; + size_t total_free = 0; + size_t total_used = 0; + + for (idx_t idx = _partitions.leftmost(partition_id); + idx <= _partitions.rightmost(partition_id); idx++) { + if (_partitions.in_free_set(partition_id, idx)) { + ShenandoahHeapRegion *r = _heap->get_region(idx); + size_t free = alloc_capacity(r); + max = MAX2(max, free); + total_free += free; + total_used += r->used(); + } + } + + ls.print(" %s freeset stats: Partition count: %zu, Reserved: " PROPERFMT ", Max free available in a single region: " PROPERFMT ";", + partition_name(partition_id), + _partitions.count(partition_id), + PROPERFMTARGS(total_free), PROPERFMTARGS(max) + ); +} + void ShenandoahFreeSet::log_status() { shenandoah_assert_heaplocked(); @@ -3040,20 +3063,18 @@ void ShenandoahFreeSet::log_status() { // retired, the sum of used and capacities within regions that are still in the Mutator free partition may not match // my internally tracked values of used() and free(). assert(free == total_free, "Free memory (%zu) should match calculated memory (%zu)", free, total_free); - ls.print("Free: %zu%s, Max: %zu%s regular, %zu%s humongous, ", - byte_size_in_proper_unit(total_free), proper_unit_for_byte_size(total_free), - byte_size_in_proper_unit(max), proper_unit_for_byte_size(max), - byte_size_in_proper_unit(max_humongous), proper_unit_for_byte_size(max_humongous) - ); + ls.print("Whole heap stats: Total free: " PROPERFMT ", Total used: " PROPERFMT ", Max free in a single region: " PROPERFMT + ", Max humongous: " PROPERFMT "; ", + PROPERFMTARGS(total_free), PROPERFMTARGS(total_used), PROPERFMTARGS(max), PROPERFMTARGS(max_humongous)); - ls.print("Frag: "); + ls.print("Frag stats: "); size_t frag_ext; if (total_free_ext > 0) { frag_ext = 100 - (100 * max_humongous / total_free_ext); } else { frag_ext = 0; } - ls.print("%zu%% external, ", frag_ext); + ls.print("External: %zu%%, ", frag_ext); size_t frag_int; if (_partitions.count(ShenandoahFreeSetPartitionId::Mutator) > 0) { @@ -3062,52 +3083,13 @@ void ShenandoahFreeSet::log_status() { } else { frag_int = 0; } - ls.print("%zu%% internal; ", frag_int); - ls.print("Used: %zu%s, Mutator Free: %zu", - byte_size_in_proper_unit(total_used), proper_unit_for_byte_size(total_used), - _partitions.count(ShenandoahFreeSetPartitionId::Mutator)); - } - - { - size_t max = 0; - size_t total_free = 0; - size_t total_used = 0; - - for (idx_t idx = _partitions.leftmost(ShenandoahFreeSetPartitionId::Collector); - idx <= _partitions.rightmost(ShenandoahFreeSetPartitionId::Collector); idx++) { - if (_partitions.in_free_set(ShenandoahFreeSetPartitionId::Collector, idx)) { - ShenandoahHeapRegion *r = _heap->get_region(idx); - size_t free = alloc_capacity(r); - max = MAX2(max, free); - total_free += free; - total_used += r->used(); - } - } - ls.print(" Collector Reserve: %zu%s, Max: %zu%s; Used: %zu%s", - byte_size_in_proper_unit(total_free), proper_unit_for_byte_size(total_free), - byte_size_in_proper_unit(max), proper_unit_for_byte_size(max), - byte_size_in_proper_unit(total_used), proper_unit_for_byte_size(total_used)); + ls.print("Internal: %zu%%; ", frag_int); } + log_freeset_stats(ShenandoahFreeSetPartitionId::Mutator, ls); + log_freeset_stats(ShenandoahFreeSetPartitionId::Collector, ls); if (_heap->mode()->is_generational()) { - size_t max = 0; - size_t total_free = 0; - size_t total_used = 0; - - for (idx_t idx = _partitions.leftmost(ShenandoahFreeSetPartitionId::OldCollector); - idx <= _partitions.rightmost(ShenandoahFreeSetPartitionId::OldCollector); idx++) { - if (_partitions.in_free_set(ShenandoahFreeSetPartitionId::OldCollector, idx)) { - ShenandoahHeapRegion *r = _heap->get_region(idx); - size_t free = alloc_capacity(r); - max = MAX2(max, free); - total_free += free; - total_used += r->used(); - } - } - ls.print_cr(" Old Collector Reserve: %zu%s, Max: %zu%s; Used: %zu%s", - byte_size_in_proper_unit(total_free), proper_unit_for_byte_size(total_free), - byte_size_in_proper_unit(max), proper_unit_for_byte_size(max), - byte_size_in_proper_unit(total_used), proper_unit_for_byte_size(total_used)); + log_freeset_stats(ShenandoahFreeSetPartitionId::OldCollector, ls); } } } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp index a9c5ebe49de..400eb8d25ee 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp @@ -629,6 +629,7 @@ private: void establish_old_collector_alloc_bias(); size_t get_usable_free_words(size_t free_bytes) const; + void log_freeset_stats(ShenandoahFreeSetPartitionId partition_id, LogStream& ls); // log status, assuming lock has already been acquired by the caller. void log_status(); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp index b9295654b6f..d74ee872cd1 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp @@ -938,8 +938,8 @@ size_t ShenandoahGeneration::available_with_reserve() const { return result; } -size_t ShenandoahGeneration::soft_available() const { - size_t result = available(ShenandoahHeap::heap()->soft_max_capacity()); +size_t ShenandoahGeneration::soft_mutator_available() const { + size_t result = available(ShenandoahHeap::heap()->soft_max_capacity() * (100.0 - ShenandoahEvacReserve) / 100); return result; } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.hpp b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.hpp index 6f393110666..06cf132f946 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.hpp @@ -126,7 +126,7 @@ private: // The soft max heap size may be adjusted lower than the max heap size to cause the trigger // to believe it has less memory available than is _really_ available. Lowering the soft // max heap size will cause the adaptive heuristic to run more frequent cycles. - size_t soft_available() const override; + size_t soft_mutator_available() const override; void log_status(const char* msg) const; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGlobalGeneration.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGlobalGeneration.cpp index c9972e2db81..a072fe2db06 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGlobalGeneration.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGlobalGeneration.cpp @@ -78,15 +78,6 @@ size_t ShenandoahGlobalGeneration::available() const { return MIN2(available, ShenandoahHeap::heap()->free_set()->available()); } -size_t ShenandoahGlobalGeneration::soft_available() const { - size_t available = this->available(); - - // Make sure the code below treats available without the soft tail. - assert(max_capacity() >= ShenandoahHeap::heap()->soft_max_capacity(), "Max capacity must be greater than soft max capacity."); - size_t soft_tail = max_capacity() - ShenandoahHeap::heap()->soft_max_capacity(); - return (available > soft_tail) ? (available - soft_tail) : 0; -} - void ShenandoahGlobalGeneration::set_concurrent_mark_in_progress(bool in_progress) { ShenandoahHeap* heap = ShenandoahHeap::heap(); if (in_progress && heap->mode()->is_generational()) { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGlobalGeneration.hpp b/src/hotspot/share/gc/shenandoah/shenandoahGlobalGeneration.hpp index 5ceba8ed50e..9f9e4818a95 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGlobalGeneration.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGlobalGeneration.hpp @@ -56,7 +56,6 @@ public: size_t max_capacity() const override; size_t available() const override; - size_t soft_available() const override; void set_concurrent_mark_in_progress(bool in_progress) override; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahYoungGeneration.cpp b/src/hotspot/share/gc/shenandoah/shenandoahYoungGeneration.cpp index 86be2fc60be..f00ce16136f 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahYoungGeneration.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahYoungGeneration.cpp @@ -138,8 +138,8 @@ size_t ShenandoahYoungGeneration::available() const { return MIN2(available, ShenandoahHeap::heap()->free_set()->available()); } -size_t ShenandoahYoungGeneration::soft_available() const { - size_t available = this->ShenandoahGeneration::soft_available(); +size_t ShenandoahYoungGeneration::soft_mutator_available() const { + size_t available = this->ShenandoahGeneration::soft_mutator_available(); return MIN2(available, ShenandoahHeap::heap()->free_set()->available()); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahYoungGeneration.hpp b/src/hotspot/share/gc/shenandoah/shenandoahYoungGeneration.hpp index 6b2794b12c3..930c5ff1747 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahYoungGeneration.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahYoungGeneration.hpp @@ -83,7 +83,7 @@ public: size_t max_capacity() const override; size_t available() const override; - size_t soft_available() const override; + size_t soft_mutator_available() const override; void prepare_gc() override; }; diff --git a/test/hotspot/jtreg/gc/shenandoah/TestSoftMaxHeapSizeAvailableCalc.java b/test/hotspot/jtreg/gc/shenandoah/TestSoftMaxHeapSizeAvailableCalc.java new file mode 100644 index 00000000000..e70f2f0849f --- /dev/null +++ b/test/hotspot/jtreg/gc/shenandoah/TestSoftMaxHeapSizeAvailableCalc.java @@ -0,0 +1,123 @@ +/* + * Copyright Amazon.com Inc. 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 id=satb-adaptive + * @requires vm.gc.Shenandoah + * @library /test/lib + * @bug 8372543 + * @summary When soft max heap size < Xmx, we had a bug reported in JBS-8372543 where available size was undercalculated. + * This caused excessive GC runs. + * + * @run main/othervm -XX:SoftMaxHeapSize=512m -Xmx2g -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions + * -XX:+UseShenandoahGC -Xlog:gc=info + * -XX:ShenandoahGCMode=satb + * -XX:+ShenandoahDegeneratedGC + * -XX:ShenandoahGCHeuristics=adaptive + * TestSoftMaxHeapSizeAvailableCalc + */ + +/** + * @test id=satb-static + * @requires vm.gc.Shenandoah + * @library /test/lib + * + * @run main/othervm -XX:SoftMaxHeapSize=512m -Xmx2g -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions + * -XX:+UseShenandoahGC -Xlog:gc=info + * -XX:ShenandoahGCMode=satb + * -XX:+ShenandoahDegeneratedGC + * -XX:ShenandoahGCHeuristics=static + * TestSoftMaxHeapSizeAvailableCalc + */ + +/** + * @test id=generational + * @requires vm.gc.Shenandoah + * @library /test/lib + * + * @run main/othervm -XX:SoftMaxHeapSize=512m -Xmx2g -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions + * -XX:+UseShenandoahGC -Xlog:gc=info + * -XX:ShenandoahGCMode=generational + * -XX:ShenandoahGCHeuristics=adaptive + * TestSoftMaxHeapSizeAvailableCalc + * + */ +import java.lang.management.ManagementFactory; + +import jdk.test.lib.Asserts; +import jdk.test.lib.Utils; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.dcmd.PidJcmdExecutor; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Random; + +import com.sun.management.GarbageCollectorMXBean; + +public class TestSoftMaxHeapSizeAvailableCalc { + public static void main(String[] args) throws Exception { + Allocate.test(); + } + + // This test runs an app that has a stable heap of ~300M and allocates temporary garbage at ~100M/s + // Soft max: 512M, ShenandoahMinFreeThreshold: 10 (default), ShenandoahEvacReserve: 5 (default) + // Soft max for mutator: 512M * (100.0 - 5) / 100 = 486.4M + // Threshold to trigger gc: 486.4M - 512 * 10 / 100.0 = 435.2M, just above (300 + 100)M. + // Expect gc count to be less than 1 / sec. + public static class Allocate { + static final List longLived = new ArrayList<>(); + + public static void test() throws Exception { + final int expectedMaxGcCount = Integer.getInteger("expectedMaxGcCount", 30); + List collectors = ManagementFactory.getGarbageCollectorMXBeans(); + java.lang.management.GarbageCollectorMXBean cycleCollector = null; + for (java.lang.management.GarbageCollectorMXBean bean : collectors) { + if (bean.getName().contains("Cycles")) { + cycleCollector = bean; + } + } + + // Allocate ~300MB of long-lived objects + for (int i = 0; i < 300; i++) { + longLived.add(new byte[1_000_000]); + } + + // allocate short-lived garbage to the heap + long end = System.currentTimeMillis() + 30_000; // 30 seconds + + while (System.currentTimeMillis() < end) { + byte[] garbage = new byte[1_000_000]; + garbage[0] = 1; // prevent optimization + + Thread.sleep(10); // Pace to generate garbage at speed of ~100M/s + } + + long gcCount = cycleCollector.getCollectionCount(); + Asserts.assertLessThan(gcCount, (long) expectedMaxGcCount, "GC was triggered too many times. Expected to be less than: " + expectedMaxGcCount + ", triggered: " + gcCount); + } + } +} From 78c2d57259ad829a2cfc1370efbb2a5913df4661 Mon Sep 17 00:00:00 2001 From: Axel Boldt-Christmas Date: Tue, 16 Dec 2025 07:38:26 +0000 Subject: [PATCH 309/706] 8373668: Add override keyword to *Klass classes Reviewed-by: jwaters, dholmes, kbarrett, tschatzl --- src/hotspot/share/oops/arrayKlass.hpp | 36 ++++----- src/hotspot/share/oops/instanceKlass.hpp | 78 +++++++++---------- .../share/oops/instanceMirrorKlass.hpp | 2 +- src/hotspot/share/oops/instanceRefKlass.hpp | 2 +- src/hotspot/share/oops/klass.hpp | 13 +--- src/hotspot/share/oops/objArrayKlass.hpp | 40 +++++----- src/hotspot/share/oops/typeArrayKlass.hpp | 28 +++---- 7 files changed, 97 insertions(+), 102 deletions(-) diff --git a/src/hotspot/share/oops/arrayKlass.hpp b/src/hotspot/share/oops/arrayKlass.hpp index 6ee783fb510..b9b100f18a8 100644 --- a/src/hotspot/share/oops/arrayKlass.hpp +++ b/src/hotspot/share/oops/arrayKlass.hpp @@ -51,15 +51,15 @@ class ArrayKlass: public Klass { public: // Testing operation - DEBUG_ONLY(bool is_array_klass_slow() const { return true; }) + DEBUG_ONLY(bool is_array_klass_slow() const override { return true; }) // Returns the ObjArrayKlass for n'th dimension. - ArrayKlass* array_klass(int n, TRAPS); - ArrayKlass* array_klass_or_null(int n); + ArrayKlass* array_klass(int n, TRAPS) override; + ArrayKlass* array_klass_or_null(int n) override; // Returns the array class with this class as element type. - ArrayKlass* array_klass(TRAPS); - ArrayKlass* array_klass_or_null(); + ArrayKlass* array_klass(TRAPS) override; + ArrayKlass* array_klass_or_null() override; // Instance variables int dimension() const { return _dimension; } @@ -79,7 +79,7 @@ class ArrayKlass: public Klass { // type of elements (T_OBJECT for both oop arrays and array-arrays) BasicType element_type() const { return layout_helper_element_type(layout_helper()); } - virtual InstanceKlass* java_super() const; + InstanceKlass* java_super() const override; // Allocation // Sizes points to the first dimension of the array, subsequent dimensions @@ -87,13 +87,13 @@ class ArrayKlass: public Klass { virtual oop multi_allocate(int rank, jint* sizes, TRAPS); // find field according to JVM spec 5.4.3.2, returns the klass in which the field is defined - Klass* find_field(Symbol* name, Symbol* sig, fieldDescriptor* fd) const; + Klass* find_field(Symbol* name, Symbol* sig, fieldDescriptor* fd) const override; // Lookup operations Method* uncached_lookup_method(const Symbol* name, const Symbol* signature, OverpassLookupMode overpass_mode, - PrivateLookupMode private_mode = PrivateLookupMode::find) const; + PrivateLookupMode private_mode = PrivateLookupMode::find) const override; static ArrayKlass* cast(Klass* k) { return const_cast(cast(const_cast(k))); @@ -105,38 +105,38 @@ class ArrayKlass: public Klass { } GrowableArray* compute_secondary_supers(int num_extra_slots, - Array* transitive_interfaces); + Array* transitive_interfaces) override; // Sizing static int static_size(int header_size); - virtual void metaspace_pointers_do(MetaspaceClosure* iter); + void metaspace_pointers_do(MetaspaceClosure* iter) override; // Return a handle. static void complete_create_array_klass(ArrayKlass* k, Klass* super_klass, ModuleEntry* module, TRAPS); // JVMTI support - jint jvmti_class_status() const; + jint jvmti_class_status() const override; #if INCLUDE_CDS // CDS support - remove and restore oops from metadata. Oops are not shared. - virtual void remove_unshareable_info(); - virtual void remove_java_mirror(); + void remove_unshareable_info() override; + void remove_java_mirror() override; void restore_unshareable_info(ClassLoaderData* loader_data, Handle protection_domain, TRAPS); void cds_print_value_on(outputStream* st) const; #endif void log_array_class_load(Klass* k); // Printing - void print_on(outputStream* st) const; - void print_value_on(outputStream* st) const; + void print_on(outputStream* st) const override; + void print_value_on(outputStream* st) const override; - void oop_print_on(oop obj, outputStream* st); + void oop_print_on(oop obj, outputStream* st) override; // Verification - void verify_on(outputStream* st); + void verify_on(outputStream* st) override; - void oop_verify_on(oop obj, outputStream* st); + void oop_verify_on(oop obj, outputStream* st) override; }; #endif // SHARE_OOPS_ARRAYKLASS_HPP diff --git a/src/hotspot/share/oops/instanceKlass.hpp b/src/hotspot/share/oops/instanceKlass.hpp index a03e6c05b54..23a59d26093 100644 --- a/src/hotspot/share/oops/instanceKlass.hpp +++ b/src/hotspot/share/oops/instanceKlass.hpp @@ -313,8 +313,8 @@ class InstanceKlass: public Klass { bool is_public() const { return _access_flags.is_public(); } bool is_final() const { return _access_flags.is_final(); } - bool is_interface() const { return _access_flags.is_interface(); } - bool is_abstract() const { return _access_flags.is_abstract(); } + bool is_interface() const override { return _access_flags.is_interface(); } + bool is_abstract() const override { return _access_flags.is_abstract(); } bool is_super() const { return _access_flags.is_super(); } bool is_synthetic() const { return _access_flags.is_synthetic(); } void set_is_synthetic() { _access_flags.set_is_synthetic(); } @@ -494,8 +494,8 @@ public: }; // package - PackageEntry* package() const { return _package_entry; } - ModuleEntry* module() const; + PackageEntry* package() const override { return _package_entry; } + ModuleEntry* module() const override; bool in_javabase_module() const; bool in_unnamed_package() const { return (_package_entry == nullptr); } void set_package(ClassLoaderData* loader_data, PackageEntry* pkg_entry, TRAPS); @@ -552,11 +552,11 @@ public: void set_is_marked_dependent(bool value) { _misc_flags.set_is_marked_dependent(value); } // initialization (virtuals from Klass) - bool should_be_initialized() const; // means that initialize should be called + bool should_be_initialized() const override; // means that initialize should be called void initialize_with_aot_initialized_mirror(TRAPS); void assert_no_clinit_will_run_for_aot_initialized_class() const NOT_DEBUG_RETURN; - void initialize(TRAPS); - void initialize_preemptable(TRAPS); + void initialize(TRAPS) override; + void initialize_preemptable(TRAPS) override; void link_class(TRAPS); bool link_class_or_fail(TRAPS); // returns false on failure void rewrite_class(TRAPS); @@ -578,7 +578,7 @@ public: // find field in direct superinterfaces, returns the interface in which the field is defined Klass* find_interface_field(Symbol* name, Symbol* sig, fieldDescriptor* fd) const; // find field according to JVM spec 5.4.3.2, returns the klass in which the field is defined - Klass* find_field(Symbol* name, Symbol* sig, fieldDescriptor* fd) const; + Klass* find_field(Symbol* name, Symbol* sig, fieldDescriptor* fd) const override; // find instance or static fields according to JVM spec 5.4.3.2, returns the klass in which the field is defined Klass* find_field(Symbol* name, Symbol* sig, bool is_static, fieldDescriptor* fd) const; @@ -637,7 +637,7 @@ public: Method* uncached_lookup_method(const Symbol* name, const Symbol* signature, OverpassLookupMode overpass_mode, - PrivateLookupMode private_mode = PrivateLookupMode::find) const; + PrivateLookupMode private_mode = PrivateLookupMode::find) const override; // lookup a method in all the interfaces that this class implements // (returns null if not found) @@ -660,7 +660,7 @@ public: void set_constants(ConstantPool* c) { _constants = c; } // protection domain - oop protection_domain() const; + oop protection_domain() const override; // signers objArrayOop signers() const; @@ -834,7 +834,7 @@ public: // Check whether reflection/jni/jvm code is allowed to instantiate this class; // if not, throw either an Error or an Exception. - virtual void check_valid_for_instantiation(bool throwError, TRAPS); + void check_valid_for_instantiation(bool throwError, TRAPS) override; // initialization void call_class_initializer(TRAPS); @@ -901,12 +901,12 @@ public: public: // virtual operations from Klass GrowableArray* compute_secondary_supers(int num_extra_slots, - Array* transitive_interfaces); - bool can_be_primary_super_slow() const; - size_t oop_size(oop obj) const { return size_helper(); } + Array* transitive_interfaces) override; + bool can_be_primary_super_slow() const override; + size_t oop_size(oop obj) const override { return size_helper(); } // slow because it's a virtual call and used for verifying the layout_helper. // Using the layout_helper bits, we can call is_instance_klass without a virtual call. - DEBUG_ONLY(bool is_instance_klass_slow() const { return true; }) + DEBUG_ONLY(bool is_instance_klass_slow() const override { return true; }) // Iterators void do_local_static_fields(FieldClosure* cl); @@ -932,7 +932,7 @@ public: return (Klass::super() == nullptr) ? nullptr : InstanceKlass::cast(Klass::super()); } - virtual InstanceKlass* java_super() const { + InstanceKlass* java_super() const override { return InstanceKlass::super(); } @@ -949,10 +949,10 @@ public: (is_interface ? (int)sizeof(Klass*)/wordSize : 0)); } - int size() const { return size(vtable_length(), - itable_length(), - nonstatic_oop_map_size(), - is_interface()); + int size() const override { return size(vtable_length(), + itable_length(), + nonstatic_oop_map_size(), + is_interface()); } @@ -1008,15 +1008,15 @@ public: void static deallocate_record_components(ClassLoaderData* loader_data, Array* record_component); - virtual bool on_stack() const; + bool on_stack() const override; // callbacks for actions during class unloading static void unload_class(InstanceKlass* ik); - virtual void release_C_heap_structures(bool release_sub_metadata = true); + void release_C_heap_structures(bool release_sub_metadata = true) override; // Naming - const char* signature_name() const; + const char* signature_name() const override; // Oop fields (and metadata) iterators // @@ -1095,12 +1095,12 @@ public: oop init_lock() const; // Returns the array class for the n'th dimension - virtual ArrayKlass* array_klass(int n, TRAPS); - virtual ArrayKlass* array_klass_or_null(int n); + ArrayKlass* array_klass(int n, TRAPS) override; + ArrayKlass* array_klass_or_null(int n) override; // Returns the array class with this class as element type - virtual ArrayKlass* array_klass(TRAPS); - virtual ArrayKlass* array_klass_or_null(); + ArrayKlass* array_klass(TRAPS) override; + ArrayKlass* array_klass_or_null() override; static void clean_initialization_error_table(); private: @@ -1139,9 +1139,9 @@ public: #if INCLUDE_CDS // CDS support - remove and restore oops from metadata. Oops are not shared. - virtual void remove_unshareable_info(); + void remove_unshareable_info() override; void remove_unshareable_flags(); - virtual void remove_java_mirror(); + void remove_java_mirror() override; void restore_unshareable_info(ClassLoaderData* loader_data, Handle protection_domain, PackageEntry* pkg_entry, TRAPS); void init_shared_package_entry(); bool can_be_verified_at_dumptime() const; @@ -1154,22 +1154,22 @@ public: _misc_flags.set_has_init_deps_processed(true); } - u2 compute_modifier_flags() const; + u2 compute_modifier_flags() const override; public: // JVMTI support - jint jvmti_class_status() const; + jint jvmti_class_status() const override; - virtual void metaspace_pointers_do(MetaspaceClosure* iter); + void metaspace_pointers_do(MetaspaceClosure* iter) override; public: // Printing - void print_on(outputStream* st) const; - void print_value_on(outputStream* st) const; + void print_on(outputStream* st) const override; + void print_value_on(outputStream* st) const override; - void oop_print_value_on(oop obj, outputStream* st); + void oop_print_value_on(oop obj, outputStream* st) override; - void oop_print_on (oop obj, outputStream* st); + void oop_print_on (oop obj, outputStream* st) override; #ifndef PRODUCT void print_dependent_nmethods(bool verbose = false); @@ -1177,12 +1177,12 @@ public: bool verify_itable_index(int index); #endif - const char* internal_name() const; + const char* internal_name() const override; // Verification - void verify_on(outputStream* st); + void verify_on(outputStream* st) override; - void oop_verify_on(oop obj, outputStream* st); + void oop_verify_on(oop obj, outputStream* st) override; // Logging void print_class_load_logging(ClassLoaderData* loader_data, diff --git a/src/hotspot/share/oops/instanceMirrorKlass.hpp b/src/hotspot/share/oops/instanceMirrorKlass.hpp index 4546f904eca..a89e573503d 100644 --- a/src/hotspot/share/oops/instanceMirrorKlass.hpp +++ b/src/hotspot/share/oops/instanceMirrorKlass.hpp @@ -67,7 +67,7 @@ class InstanceMirrorKlass: public InstanceKlass { } // Returns the size of the instance including the extra static fields. - virtual size_t oop_size(oop obj) const; + size_t oop_size(oop obj) const override; // Static field offset is an offset into the Heap, should be converted by // based on UseCompressedOop for traversal diff --git a/src/hotspot/share/oops/instanceRefKlass.hpp b/src/hotspot/share/oops/instanceRefKlass.hpp index c372b83a267..57126156dd8 100644 --- a/src/hotspot/share/oops/instanceRefKlass.hpp +++ b/src/hotspot/share/oops/instanceRefKlass.hpp @@ -126,7 +126,7 @@ class InstanceRefKlass: public InstanceKlass { public: // Verification - void oop_verify_on(oop obj, outputStream* st); + void oop_verify_on(oop obj, outputStream* st) override; }; #endif // SHARE_OOPS_INSTANCEREFKLASS_HPP diff --git a/src/hotspot/share/oops/klass.hpp b/src/hotspot/share/oops/klass.hpp index 25fb900e7d6..b6974762209 100644 --- a/src/hotspot/share/oops/klass.hpp +++ b/src/hotspot/share/oops/klass.hpp @@ -215,7 +215,7 @@ protected: enum class StaticLookupMode { find, skip }; enum class PrivateLookupMode { find, skip }; - virtual bool is_klass() const { return true; } + bool is_klass() const override { return true; } // super() cannot be InstanceKlass* -- Java arrays are covariant, and _super is used // to implement that. NB: the _super of "[Ljava/lang/Integer;" is "[Ljava/lang/Number;" @@ -649,9 +649,6 @@ public: // actual oop size of obj in memory in word size. virtual size_t oop_size(oop obj) const = 0; - // Size of klass in word size. - virtual int size() const = 0; - // Returns the Java name for a class (Resource allocated) // For arrays, this returns the name of the element with a leading '['. // For classes, this returns the name with the package separators @@ -728,8 +725,8 @@ public: JFR_ONLY(DEFINE_TRACE_ID_METHODS;) - virtual void metaspace_pointers_do(MetaspaceClosure* iter); - virtual MetaspaceObj::Type type() const { return ClassType; } + void metaspace_pointers_do(MetaspaceClosure* iter) override; + MetaspaceObj::Type type() const override { return ClassType; } inline bool is_loader_alive() const; inline bool is_loader_present_and_alive() const; @@ -764,15 +761,13 @@ public: virtual jint jvmti_class_status() const; // Printing - virtual void print_on(outputStream* st) const; + void print_on(outputStream* st) const override; virtual void oop_print_value_on(oop obj, outputStream* st); virtual void oop_print_on (oop obj, outputStream* st); void print_secondary_supers_on(outputStream* st) const; - virtual const char* internal_name() const = 0; - // Verification virtual void verify_on(outputStream* st); void verify() { verify_on(tty); } diff --git a/src/hotspot/share/oops/objArrayKlass.hpp b/src/hotspot/share/oops/objArrayKlass.hpp index 1a4f7f657d2..12db56351ed 100644 --- a/src/hotspot/share/oops/objArrayKlass.hpp +++ b/src/hotspot/share/oops/objArrayKlass.hpp @@ -72,29 +72,29 @@ class ObjArrayKlass : public ArrayKlass { void set_bottom_klass(Klass* k) { _bottom_klass = k; } Klass** bottom_klass_addr() { return &_bottom_klass; } - ModuleEntry* module() const; - PackageEntry* package() const; + ModuleEntry* module() const override; + PackageEntry* package() const override; // Dispatched operation - bool can_be_primary_super_slow() const; + bool can_be_primary_super_slow() const override; GrowableArray* compute_secondary_supers(int num_extra_slots, - Array* transitive_interfaces); - DEBUG_ONLY(bool is_objArray_klass_slow() const { return true; }) - size_t oop_size(oop obj) const; + Array* transitive_interfaces) override; + DEBUG_ONLY(bool is_objArray_klass_slow() const override { return true; }) + size_t oop_size(oop obj) const override; // Allocation static ObjArrayKlass* allocate_objArray_klass(ClassLoaderData* loader_data, int n, Klass* element_klass, TRAPS); - oop multi_allocate(int rank, jint* sizes, TRAPS); + oop multi_allocate(int rank, jint* sizes, TRAPS) override; // Copying - void copy_array(arrayOop s, int src_pos, arrayOop d, int dst_pos, int length, TRAPS); + void copy_array(arrayOop s, int src_pos, arrayOop d, int dst_pos, int length, TRAPS) override; // Compute protection domain - oop protection_domain() const { return bottom_klass()->protection_domain(); } + oop protection_domain() const override { return bottom_klass()->protection_domain(); } - virtual void metaspace_pointers_do(MetaspaceClosure* iter); + virtual void metaspace_pointers_do(MetaspaceClosure* iter) override; private: // Either oop or narrowOop depending on UseCompressedOops. @@ -114,10 +114,10 @@ class ObjArrayKlass : public ArrayKlass { // Sizing static int header_size() { return sizeof(ObjArrayKlass)/wordSize; } - int size() const { return ArrayKlass::static_size(header_size()); } + int size() const override { return ArrayKlass::static_size(header_size()); } // Initialization (virtual from Klass) - void initialize(TRAPS); + void initialize(TRAPS) override; // Oop fields (and metadata) iterators // @@ -150,24 +150,24 @@ class ObjArrayKlass : public ArrayKlass { inline void oop_oop_iterate_elements_bounded(objArrayOop a, OopClosureType* closure, void* low, void* high); public: - u2 compute_modifier_flags() const; + u2 compute_modifier_flags() const override; public: // Printing - void print_on(outputStream* st) const; - void print_value_on(outputStream* st) const; + void print_on(outputStream* st) const override; + void print_value_on(outputStream* st) const override; - void oop_print_value_on(oop obj, outputStream* st); + void oop_print_value_on(oop obj, outputStream* st) override; #ifndef PRODUCT - void oop_print_on (oop obj, outputStream* st); + void oop_print_on (oop obj, outputStream* st) override; #endif //PRODUCT - const char* internal_name() const; + const char* internal_name() const override; // Verification - void verify_on(outputStream* st); + void verify_on(outputStream* st) override; - void oop_verify_on(oop obj, outputStream* st); + void oop_verify_on(oop obj, outputStream* st) override; }; #endif // SHARE_OOPS_OBJARRAYKLASS_HPP diff --git a/src/hotspot/share/oops/typeArrayKlass.hpp b/src/hotspot/share/oops/typeArrayKlass.hpp index 22600702fe2..87a41a6d4b3 100644 --- a/src/hotspot/share/oops/typeArrayKlass.hpp +++ b/src/hotspot/share/oops/typeArrayKlass.hpp @@ -56,10 +56,10 @@ class TypeArrayKlass : public ArrayKlass { jint max_length() { return _max_length; } void set_max_length(jint m) { _max_length = m; } - u2 compute_modifier_flags() const; + u2 compute_modifier_flags() const override; // testers - DEBUG_ONLY(bool is_typeArray_klass_slow() const { return true; }) + DEBUG_ONLY(bool is_typeArray_klass_slow() const override { return true; }) // klass allocation static TypeArrayKlass* create_klass(BasicType type, const char* name_str, @@ -68,15 +68,15 @@ class TypeArrayKlass : public ArrayKlass { return create_klass(type, external_name(type), THREAD); } - size_t oop_size(oop obj) const; + size_t oop_size(oop obj) const override; // Allocation - oop multi_allocate(int rank, jint* sizes, TRAPS); + oop multi_allocate(int rank, jint* sizes, TRAPS) override; - oop protection_domain() const { return nullptr; } + oop protection_domain() const override { return nullptr; } // Copying - void copy_array(arrayOop s, int src_pos, arrayOop d, int dst_pos, int length, TRAPS); + void copy_array(arrayOop s, int src_pos, arrayOop d, int dst_pos, int length, TRAPS) override; // Oop iterators. Since there are no oops in TypeArrayKlasses, // these functions only return the size of the object. @@ -113,23 +113,23 @@ class TypeArrayKlass : public ArrayKlass { // Sizing static int header_size() { return sizeof(TypeArrayKlass)/wordSize; } - int size() const { return ArrayKlass::static_size(header_size()); } + int size() const override { return ArrayKlass::static_size(header_size()); } // Initialization (virtual from Klass) - void initialize(TRAPS); + void initialize(TRAPS) override; public: // Printing - void oop_print_on(oop obj, outputStream* st); + void oop_print_on(oop obj, outputStream* st) override; void oop_print_elements_on(typeArrayOop ta, outputStream* st); - void print_on(outputStream* st) const; - void print_value_on(outputStream* st) const; + void print_on(outputStream* st) const override; + void print_value_on(outputStream* st) const override; public: - const char* internal_name() const; + const char* internal_name() const override; - ModuleEntry* module() const; - PackageEntry* package() const; + ModuleEntry* module() const override; + PackageEntry* package() const override; }; #endif // SHARE_OOPS_TYPEARRAYKLASS_HPP From 8402891889c29894555eca6449ba63f7b7458124 Mon Sep 17 00:00:00 2001 From: Emanuel Peter Date: Tue, 16 Dec 2025 09:34:42 +0000 Subject: [PATCH 310/706] 8373355: C2: CompileCommand PrintIdealPhase should also print nodes that are not "reachable from below" Reviewed-by: rcastanedalo, mchevalier, bmaillard --- src/hotspot/share/opto/compile.cpp | 4 +- .../compiler/c2/irTests/ModDNodeTests.java | 94 ++++++++++++++----- .../compiler/c2/irTests/ModFNodeTests.java | 94 ++++++++++++++----- .../compiler/lib/ir_framework/IRNode.java | 10 -- .../tests/TestIRFindFromAbove.java | 63 +++++++++++++ 5 files changed, 210 insertions(+), 55 deletions(-) create mode 100644 test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestIRFindFromAbove.java diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index 16f5be50805..cea2b09e142 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -595,7 +595,9 @@ void Compile::print_ideal_ir(const char* phase_name) { if (_output == nullptr) { ss.print_cr("AFTER: %s", phase_name); // Print out all nodes in ascending order of index. - root()->dump_bfs(MaxNodeLimit, nullptr, "+S$", &ss); + // It is important that we traverse both inputs and outputs of nodes, + // so that we reach all nodes that are connected to Root. + root()->dump_bfs(MaxNodeLimit, nullptr, "-+S$", &ss); } else { // Dump the node blockwise if we have a scheduling _output->print_scheduling(&ss); diff --git a/test/hotspot/jtreg/compiler/c2/irTests/ModDNodeTests.java b/test/hotspot/jtreg/compiler/c2/irTests/ModDNodeTests.java index 7eed798871e..6b20b782923 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/ModDNodeTests.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/ModDNodeTests.java @@ -63,17 +63,29 @@ public class ModDNodeTests { Asserts.assertEQ(unusedResultAfterLoopOpt3(1.1d, 2.2d), 0.d); } + // Note: we used to check for ConD nodes in the IR. But that is a bit brittle: + // Constant nodes can appear during IR transformations, and then lose their outputs. + // During IGNV, the constants stay in the graph even if they lose the inputs. But + // CCP cleans them out because they are not in the useful set. So for now, we do not + // rely on any constant counting, just on counting the operation nodes. + @Test - @IR(failOn = {"drem"}, phase = CompilePhase.BEFORE_MATCHING) - @IR(counts = {IRNode.CON_D, "1"}) + @IR(counts = {IRNode.MOD_D, "2"}, + phase = CompilePhase.AFTER_PARSING) + @IR(counts = {".*CallLeaf.*drem.*", "0"}, + phase = CompilePhase.BEFORE_MATCHING) public double constant() { // All constants available during parsing return q % 72.0d % 30.0d; } @Test - @IR(failOn = {"drem"}, phase = CompilePhase.BEFORE_MATCHING) - @IR(counts = {IRNode.CON_D, "1"}) + @IR(counts = {IRNode.MOD_D, "1"}, + phase = CompilePhase.AFTER_PARSING) + @IR(counts = {IRNode.MOD_D, "1"}, + phase = CompilePhase.PHASEIDEALLOOP1) // Only constant fold after some loop opts + @IR(counts = {".*CallLeaf.*drem.*", "0"}, + phase = CompilePhase.BEFORE_MATCHING) public double alsoConstant() { // Make sure value is only available after second loop opts round double val = 0; @@ -86,8 +98,12 @@ public class ModDNodeTests { } @Test - @IR(failOn = {"drem"}, phase = CompilePhase.BEFORE_MATCHING) - @IR(counts = {IRNode.CON_D, "1"}) + @IR(counts = {IRNode.MOD_D, "2"}, + phase = CompilePhase.AFTER_PARSING) + @IR(counts = {IRNode.MOD_D, "2"}, + phase = CompilePhase.PHASEIDEALLOOP1) // Only constant fold after some loop opts + @IR(counts = {".*CallLeaf.*drem.*", "0"}, + phase = CompilePhase.BEFORE_MATCHING) public double nanLeftConstant() { // Make sure value is only available after second loop opts round double val = 134.18d; @@ -100,8 +116,12 @@ public class ModDNodeTests { } @Test - @IR(failOn = {"drem"}, phase = CompilePhase.BEFORE_MATCHING) - @IR(counts = {IRNode.CON_D, "1"}) + @IR(counts = {IRNode.MOD_D, "2"}, + phase = CompilePhase.AFTER_PARSING) + @IR(counts = {IRNode.MOD_D, "2"}, + phase = CompilePhase.PHASEIDEALLOOP1) // Only constant fold after some loop opts + @IR(counts = {".*CallLeaf.*drem.*", "0"}, + phase = CompilePhase.BEFORE_MATCHING) public double nanRightConstant() { // Make sure value is only available after second loop opts round double val = 134.18d; @@ -114,29 +134,41 @@ public class ModDNodeTests { } @Test - @IR(counts = {"drem", "1"}, phase = CompilePhase.BEFORE_MATCHING) - @IR(counts = {IRNode.CON_D, "1"}) + @IR(counts = {IRNode.MOD_D, "1"}, + phase = CompilePhase.AFTER_PARSING) + @IR(counts = {".*CallLeaf.*drem.*", "1"}, + phase = CompilePhase.BEFORE_MATCHING) // no constant folding public double notConstant(double x) { return x % 32.0d; } @Test - @IR(counts = {"drem", "2"}, phase = CompilePhase.BEFORE_MATCHING) - @IR(counts = {IRNode.CON_D, "1"}) + @IR(counts = {IRNode.MOD_D, "2"}, + phase = CompilePhase.AFTER_PARSING) + @IR(counts = {".*CallLeaf.*drem.*", "2"}, + phase = CompilePhase.BEFORE_MATCHING) // no constant folding public double veryNotConstant(double x, double y) { return x % 32.0d % y; } @Test - @IR(failOn = IRNode.MOD_D, phase = CompilePhase.ITER_GVN1) - @IR(counts = {IRNode.MOD_D, "1"}, phase = CompilePhase.AFTER_PARSING) + @IR(counts = {IRNode.MOD_D, "1"}, + phase = CompilePhase.AFTER_PARSING) + @IR(counts = {IRNode.MOD_D, "0"}, + phase = CompilePhase.ITER_GVN1) // IGVN removes unused nodes + @IR(counts = {".*CallLeaf.*drem.*", "0"}, + phase = CompilePhase.BEFORE_MATCHING) public void unusedResult(double x, double y) { double unused = x % y; } @Test - @IR(failOn = IRNode.MOD_D, phase = CompilePhase.ITER_GVN1) - @IR(counts = {IRNode.MOD_D, "1"}, phase = CompilePhase.AFTER_PARSING) + @IR(counts = {IRNode.MOD_D, "1"}, + phase = CompilePhase.AFTER_PARSING) + @IR(counts = {IRNode.MOD_D, "0"}, + phase = CompilePhase.ITER_GVN1) // IGVN removes unused nodes + @IR(counts = {".*CallLeaf.*drem.*", "0"}, + phase = CompilePhase.BEFORE_MATCHING) public void repeatedlyUnused(double x, double y) { double unused = 1.d; for (int i = 0; i < 100_000; i++) { @@ -149,8 +181,14 @@ public class ModDNodeTests { // and thus a different execution path. In unusedResultAfterLoopOpt1 the modulo is // used in the traps of the parse predicates. In unusedResultAfterLoopOpt2, it is not. @Test - @IR(counts = {IRNode.MOD_D, "1"}, phase = CompilePhase.ITER_GVN2) - @IR(failOn = IRNode.MOD_D, phase = CompilePhase.BEFORE_MACRO_EXPANSION) + @IR(counts = {IRNode.MOD_D, "1"}, + phase = CompilePhase.AFTER_PARSING) + @IR(counts = {IRNode.MOD_D, "1"}, + phase = CompilePhase.ITER_GVN2) + @IR(counts = {IRNode.MOD_D, "0"}, + phase = CompilePhase.BEFORE_MACRO_EXPANSION) + @IR(counts = {".*CallLeaf.*drem.*", "0"}, + phase = CompilePhase.BEFORE_MATCHING) public double unusedResultAfterLoopOpt1(double x, double y) { double unused = x % y; @@ -168,8 +206,14 @@ public class ModDNodeTests { } @Test - @IR(counts = {IRNode.MOD_D, "1"}, phase = CompilePhase.AFTER_CLOOPS) - @IR(failOn = IRNode.MOD_D, phase = CompilePhase.PHASEIDEALLOOP1) + @IR(counts = {IRNode.MOD_D, "1"}, + phase = CompilePhase.AFTER_PARSING) + @IR(counts = {IRNode.MOD_D, "1"}, + phase = CompilePhase.AFTER_CLOOPS) + @IR(counts = {IRNode.MOD_D, "0"}, + phase = CompilePhase.PHASEIDEALLOOP1) + @IR(counts = {".*CallLeaf.*drem.*", "0"}, + phase = CompilePhase.BEFORE_MATCHING) public double unusedResultAfterLoopOpt2(double x, double y) { int a = 77; int b = 0; @@ -187,8 +231,14 @@ public class ModDNodeTests { } @Test - @IR(counts = {IRNode.MOD_D, "2"}, phase = CompilePhase.AFTER_CLOOPS) - @IR(failOn = IRNode.MOD_D, phase = CompilePhase.PHASEIDEALLOOP1) + @IR(counts = {IRNode.MOD_D, "3"}, + phase = CompilePhase.AFTER_PARSING) + @IR(counts = {IRNode.MOD_D, "2"}, + phase = CompilePhase.AFTER_CLOOPS) // drop the useless one + @IR(counts = {IRNode.MOD_D, "0"}, + phase = CompilePhase.PHASEIDEALLOOP1) // drop the rest + @IR(counts = {".*CallLeaf.*drem.*", "0"}, + phase = CompilePhase.BEFORE_MATCHING) public double unusedResultAfterLoopOpt3(double x, double y) { double unused = x % y; diff --git a/test/hotspot/jtreg/compiler/c2/irTests/ModFNodeTests.java b/test/hotspot/jtreg/compiler/c2/irTests/ModFNodeTests.java index 886efe57124..2f69578c2f0 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/ModFNodeTests.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/ModFNodeTests.java @@ -63,17 +63,29 @@ public class ModFNodeTests { Asserts.assertEQ(unusedResultAfterLoopOpt3(1.1f, 2.2f), 0.f); } + // Note: we used to check for ConF nodes in the IR. But that is a bit brittle: + // Constant nodes can appear during IR transformations, and then lose their outputs. + // During IGNV, the constants stay in the graph even if they lose the inputs. But + // CCP cleans them out because they are not in the useful set. So for now, we do not + // rely on any constant counting, just on counting the operation nodes. + @Test - @IR(failOn = {"frem"}, phase = CompilePhase.BEFORE_MATCHING) - @IR(counts = {IRNode.CON_F, "1"}) + @IR(counts = {IRNode.MOD_F, "2"}, + phase = CompilePhase.AFTER_PARSING) + @IR(counts = {".*CallLeaf.*frem.*", "0"}, + phase = CompilePhase.BEFORE_MATCHING) public float constant() { // All constants available during parsing return q % 72.0f % 30.0f; } @Test - @IR(failOn = {"frem"}, phase = CompilePhase.BEFORE_MATCHING) - @IR(counts = {IRNode.CON_F, "1"}) + @IR(counts = {IRNode.MOD_F, "1"}, + phase = CompilePhase.AFTER_PARSING) + @IR(counts = {IRNode.MOD_F, "1"}, + phase = CompilePhase.PHASEIDEALLOOP1) // Only constant fold after some loop opts + @IR(counts = {".*CallLeaf.*frem.*", "0"}, + phase = CompilePhase.BEFORE_MATCHING) public float alsoConstant() { // Make sure value is only available after second loop opts round float val = 0; @@ -86,8 +98,12 @@ public class ModFNodeTests { } @Test - @IR(failOn = {"frem"}, phase = CompilePhase.BEFORE_MATCHING) - @IR(counts = {IRNode.CON_F, "1"}) + @IR(counts = {IRNode.MOD_F, "2"}, + phase = CompilePhase.AFTER_PARSING) + @IR(counts = {IRNode.MOD_F, "2"}, + phase = CompilePhase.PHASEIDEALLOOP1) // Only constant fold after some loop opts + @IR(counts = {".*CallLeaf.*frem.*", "0"}, + phase = CompilePhase.BEFORE_MATCHING) public float nanLeftConstant() { // Make sure value is only available after second loop opts round float val = 134.18f; @@ -100,8 +116,12 @@ public class ModFNodeTests { } @Test - @IR(failOn = {"frem"}, phase = CompilePhase.BEFORE_MATCHING) - @IR(counts = {IRNode.CON_F, "1"}) + @IR(counts = {IRNode.MOD_F, "2"}, + phase = CompilePhase.AFTER_PARSING) + @IR(counts = {IRNode.MOD_F, "2"}, + phase = CompilePhase.PHASEIDEALLOOP1) // Only constant fold after some loop opts + @IR(counts = {".*CallLeaf.*frem.*", "0"}, + phase = CompilePhase.BEFORE_MATCHING) public float nanRightConstant() { // Make sure value is only available after second loop opts round float val = 134.18f; @@ -114,29 +134,41 @@ public class ModFNodeTests { } @Test - @IR(counts = {"frem", "1"}, phase = CompilePhase.BEFORE_MATCHING) - @IR(counts = {IRNode.CON_F, "1"}) + @IR(counts = {IRNode.MOD_F, "1"}, + phase = CompilePhase.AFTER_PARSING) + @IR(counts = {".*CallLeaf.*frem.*", "1"}, + phase = CompilePhase.BEFORE_MATCHING) // no constant folding public float notConstant(float x) { return x % 32.0f; } @Test - @IR(counts = {"frem", "2"}, phase = CompilePhase.BEFORE_MATCHING) - @IR(counts = {IRNode.CON_F, "1"}) + @IR(counts = {IRNode.MOD_F, "2"}, + phase = CompilePhase.AFTER_PARSING) + @IR(counts = {".*CallLeaf.*frem.*", "2"}, + phase = CompilePhase.BEFORE_MATCHING) // no constant folding public float veryNotConstant(float x, float y) { return x % 32.0f % y; } @Test - @IR(failOn = IRNode.MOD_F, phase = CompilePhase.ITER_GVN1) - @IR(counts = {IRNode.MOD_F, "1"}, phase = CompilePhase.AFTER_PARSING) + @IR(counts = {IRNode.MOD_F, "1"}, + phase = CompilePhase.AFTER_PARSING) + @IR(counts = {IRNode.MOD_F, "0"}, + phase = CompilePhase.ITER_GVN1) // IGVN removes unused nodes + @IR(counts = {".*CallLeaf.*frem.*", "0"}, + phase = CompilePhase.BEFORE_MATCHING) public void unusedResult(float x, float y) { float unused = x % y; } @Test - @IR(failOn = IRNode.MOD_F, phase = CompilePhase.ITER_GVN1) - @IR(counts = {IRNode.MOD_F, "1"}, phase = CompilePhase.AFTER_PARSING) + @IR(counts = {IRNode.MOD_F, "1"}, + phase = CompilePhase.AFTER_PARSING) + @IR(counts = {IRNode.MOD_F, "0"}, + phase = CompilePhase.ITER_GVN1) // IGVN removes unused nodes + @IR(counts = {".*CallLeaf.*frem.*", "0"}, + phase = CompilePhase.BEFORE_MATCHING) public void repeatedlyUnused(float x, float y) { float unused = 1.f; for (int i = 0; i < 100_000; i++) { @@ -149,8 +181,14 @@ public class ModFNodeTests { // and thus a different execution path. In unusedResultAfterLoopOpt1 the modulo is // used in the traps of the parse predicates. In unusedResultAfterLoopOpt2, it is not. @Test - @IR(counts = {IRNode.MOD_F, "1"}, phase = CompilePhase.ITER_GVN2) - @IR(failOn = IRNode.MOD_F, phase = CompilePhase.BEFORE_MACRO_EXPANSION) + @IR(counts = {IRNode.MOD_F, "1"}, + phase = CompilePhase.AFTER_PARSING) + @IR(counts = {IRNode.MOD_F, "1"}, + phase = CompilePhase.ITER_GVN2) + @IR(counts = {IRNode.MOD_F, "0"}, + phase = CompilePhase.BEFORE_MACRO_EXPANSION) + @IR(counts = {".*CallLeaf.*frem.*", "0"}, + phase = CompilePhase.BEFORE_MATCHING) public float unusedResultAfterLoopOpt1(float x, float y) { float unused = x % y; @@ -168,8 +206,14 @@ public class ModFNodeTests { } @Test - @IR(counts = {IRNode.MOD_F, "1"}, phase = CompilePhase.AFTER_CLOOPS) - @IR(failOn = IRNode.MOD_F, phase = CompilePhase.PHASEIDEALLOOP1) + @IR(counts = {IRNode.MOD_F, "1"}, + phase = CompilePhase.AFTER_PARSING) + @IR(counts = {IRNode.MOD_F, "1"}, + phase = CompilePhase.AFTER_CLOOPS) + @IR(counts = {IRNode.MOD_F, "0"}, + phase = CompilePhase.PHASEIDEALLOOP1) + @IR(counts = {".*CallLeaf.*frem.*", "0"}, + phase = CompilePhase.BEFORE_MATCHING) public float unusedResultAfterLoopOpt2(float x, float y) { int a = 77; int b = 0; @@ -187,8 +231,14 @@ public class ModFNodeTests { } @Test - @IR(counts = {IRNode.MOD_F, "2"}, phase = CompilePhase.AFTER_CLOOPS) - @IR(failOn = IRNode.MOD_F, phase = CompilePhase.PHASEIDEALLOOP1) + @IR(counts = {IRNode.MOD_F, "3"}, + phase = CompilePhase.AFTER_PARSING) + @IR(counts = {IRNode.MOD_F, "2"}, + phase = CompilePhase.AFTER_CLOOPS) // drop the useless one + @IR(counts = {IRNode.MOD_F, "0"}, + phase = CompilePhase.PHASEIDEALLOOP1) // drop the rest + @IR(counts = {".*CallLeaf.*frem.*", "0"}, + phase = CompilePhase.BEFORE_MATCHING) public float unusedResultAfterLoopOpt3(float x, float y) { float unused = x % y; diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java index d5799e5aa05..3fd8e2eceb4 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java @@ -690,16 +690,6 @@ public class IRNode { beforeMatchingNameRegex(CON_L, "ConL"); } - public static final String CON_D = PREFIX + "CON_D" + POSTFIX; - static { - beforeMatchingNameRegex(CON_D, "ConD"); - } - - public static final String CON_F = PREFIX + "CON_F" + POSTFIX; - static { - beforeMatchingNameRegex(CON_F, "ConF"); - } - public static final String COUNTED_LOOP = PREFIX + "COUNTED_LOOP" + POSTFIX; static { String regex = START + "CountedLoop\\b" + MID + END; diff --git a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestIRFindFromAbove.java b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestIRFindFromAbove.java new file mode 100644 index 00000000000..23e46428460 --- /dev/null +++ b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestIRFindFromAbove.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2025, 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 ir_framework.tests; + +import compiler.lib.ir_framework.*; + +/* + * @test + * @bug 8373355 + * @summary Test that IR matching happens on the whole graph, not just nodes + * that can be found by traversing up from the Root. + * @library /test/lib / + * @run main ${test.main.class} + */ + +public class TestIRFindFromAbove { + public static boolean flag = false; + public static int fld = 0; + + public static void main(String[] args) { + TestFramework.run(); + } + + @Test + @Warmup(0) + // Simulate Xcomp with no warmup: ensure the flag branch is not an unstable if + // but that we compile the infinite loop. + @IR(counts = {IRNode.LOAD_I, "1", IRNode.STORE_I, "1", ".*NeverBranch.*", "0"}, + phase = CompilePhase.ITER_GVN1) + @IR(counts = {IRNode.LOAD_I, "1", IRNode.STORE_I, "1", ".*NeverBranch.*", "1"}, + phase = CompilePhase.PHASEIDEALLOOP1) + public static void test() { + if (flag) { + // This loop has no exit. So it is at first not connected down to Root. + while (true) { + // During PHASEIDEALLOOP1, we insert a NeverBranch here, with a fake + // exit, that connects the loop down to Root. + fld++; // LoadI and StoreI + } + } + } +} From 43d4456181fcd759e3f1de7ca4f6d74827a3c644 Mon Sep 17 00:00:00 2001 From: Maurizio Cimadamore Date: Tue, 16 Dec 2025 10:01:13 +0000 Subject: [PATCH 311/706] 8373570: Javac stack overflow on method-local class with nested record referring to enclosing type Reviewed-by: vromero --- .../com/sun/tools/javac/comp/Resolve.java | 5 +- .../javac/SuperInit/NewLocalNotInInner.java | 72 +++++++++++++++++++ .../javac/SuperInit/NewLocalNotInInner.out | 6 ++ 3 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 test/langtools/tools/javac/SuperInit/NewLocalNotInInner.java create mode 100644 test/langtools/tools/javac/SuperInit/NewLocalNotInInner.out diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java index 07f2a742bcb..d88180bb15c 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java @@ -3843,12 +3843,15 @@ public class Resolve { Env env1 = env; boolean staticOnly = false; while (env1.outer != null) { + // If the local class is defined inside a static method, and the instance creation expression + // occurs in that same method, the creation occurs (technically) inside a static context, but that's ok. if (env1.info.scope.owner == owner) { return (staticOnly) ? new BadLocalClassCreation(c) : owner; + } else if (isStatic(env1) || env1.enclClass.sym.isStatic()) { + staticOnly = true; } - if (isStatic(env1)) staticOnly = true; env1 = env1.outer; } return owner.kind == MTH ? diff --git a/test/langtools/tools/javac/SuperInit/NewLocalNotInInner.java b/test/langtools/tools/javac/SuperInit/NewLocalNotInInner.java new file mode 100644 index 00000000000..8a69bc37667 --- /dev/null +++ b/test/langtools/tools/javac/SuperInit/NewLocalNotInInner.java @@ -0,0 +1,72 @@ +/* + * @test /nodynamiccopyright/ + * @bug 8373570 + * @summary Javac stack overflow on method-local class with nested record referring to enclosing type + * @compile/fail/ref=NewLocalNotInInner.out -XDrawDiagnostics NewLocalNotInInner.java + */ +class NewLocalNotInInner { + void m() { + class Local { + static class Foo { + void m() { + new Local(); // error + } + } + } + } + + void m_anon() { + class Local { + static class Foo { + void m() { + new Local() { }; // error + } + } + } + } + + void m_record() { + class Local { + record Foo() { + void m() { + new Local(); // error + } + } + } + } + + void m_intf() { + class Local { + interface Foo { + default void m() { + new Local(); // error + } + } + } + } + + void sup() { + class Local { + static class Foo { + void m() { + class Sub extends Local { }; // error + new Sub(); + } + } + } + } + + static void staticLocal() { + class Local { } + new Local(); // ok + } + + static void staticLocalFromAnon() { + class Local { } + new Object() { + Local local() { + return new Local(); // ok + } + }; + } +} diff --git a/test/langtools/tools/javac/SuperInit/NewLocalNotInInner.out b/test/langtools/tools/javac/SuperInit/NewLocalNotInInner.out new file mode 100644 index 00000000000..dd816f2ab0e --- /dev/null +++ b/test/langtools/tools/javac/SuperInit/NewLocalNotInInner.out @@ -0,0 +1,6 @@ +NewLocalNotInInner.java:12:21: compiler.err.local.cant.be.inst.static: kindname.class, Local +NewLocalNotInInner.java:22:21: compiler.err.local.cant.be.inst.static: kindname.class, Local +NewLocalNotInInner.java:32:21: compiler.err.local.cant.be.inst.static: kindname.class, Local +NewLocalNotInInner.java:42:21: compiler.err.local.cant.be.inst.static: kindname.class, Local +NewLocalNotInInner.java:52:21: compiler.err.local.cant.be.inst.static: kindname.class, Local +5 errors From 41d28c1838bcd7a69f78c9799b449af2a33c11c3 Mon Sep 17 00:00:00 2001 From: Jaikiran Pai Date: Tue, 16 Dec 2025 10:08:08 +0000 Subject: [PATCH 312/706] 8373561: Replace usages of -verify java launcher option with -Xverify:all JVM option Reviewed-by: serb, prr, dholmes, jlahoda --- test/hotspot/jtreg/runtime/verifier/TestANewArray.java | 6 +++--- test/hotspot/jtreg/runtime/verifier/TraceClassRes.java | 2 +- .../verifier/stackMapTableTests/StackMapTableTest.java | 4 ++-- test/jdk/javax/swing/JFileChooser/6520101/bug6520101.java | 4 ++-- .../langtools/tools/javac/VarDeclarationWithAssignment.java | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/test/hotspot/jtreg/runtime/verifier/TestANewArray.java b/test/hotspot/jtreg/runtime/verifier/TestANewArray.java index e1b0dcf764c..f7b133868d4 100644 --- a/test/hotspot/jtreg/runtime/verifier/TestANewArray.java +++ b/test/hotspot/jtreg/runtime/verifier/TestANewArray.java @@ -69,7 +69,7 @@ public class TestANewArray { byte[] classFile_254 = dumpClassFile(cfv, test_Dimension_254, array_Dimension_254); writeClassFileFromByteArray(classFile_254); System.err.println("Running with cfv: " + cfv + ", test_Dimension_254"); - ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder("-verify", "-cp", ".", classCName); + ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder("-Xverify:all", "-cp", ".", classCName); OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldNotContain("java.lang.VerifyError"); output.shouldHaveExitValue(0); @@ -78,7 +78,7 @@ public class TestANewArray { byte[] classFile_255 = dumpClassFile(cfv, test_Dimension_255, array_Dimension_255); writeClassFileFromByteArray(classFile_255); System.err.println("Running with cfv: " + cfv + ", test_Dimension_255"); - pb = ProcessTools.createTestJavaProcessBuilder("-verify", "-cp", ".", classCName); + pb = ProcessTools.createTestJavaProcessBuilder("-Xverify:all", "-cp", ".", classCName); output = new OutputAnalyzer(pb.start()); // If anewarray has an operand with 255 array dimensions then VerifyError should // be thrown because the resulting array would have 256 dimensions. @@ -95,7 +95,7 @@ public class TestANewArray { byte[] classFile_264 = dumpClassFile(cfv, test_Dimension_264, array_Dimension_264); writeClassFileFromByteArray(classFile_264); System.err.println("Running with cfv: " + cfv + ", test_Dimension_264"); - pb = ProcessTools.createTestJavaProcessBuilder("-verify", "-cp", ".", classCName); + pb = ProcessTools.createTestJavaProcessBuilder("-Xverify:all", "-cp", ".", classCName); output = new OutputAnalyzer(pb.start()); output.shouldContain("java.lang.ClassFormatError"); output.shouldHaveExitValue(1); diff --git a/test/hotspot/jtreg/runtime/verifier/TraceClassRes.java b/test/hotspot/jtreg/runtime/verifier/TraceClassRes.java index ddb5e68e1d3..e9be98fea17 100644 --- a/test/hotspot/jtreg/runtime/verifier/TraceClassRes.java +++ b/test/hotspot/jtreg/runtime/verifier/TraceClassRes.java @@ -39,7 +39,7 @@ public class TraceClassRes { public static void main(String[] args) throws Exception { ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( - "-Xlog:class+resolve=debug", "-verify", "-Xshare:off", "-version"); + "-Xlog:class+resolve=debug", "-Xverify:all", "-Xshare:off", "-version"); OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldContain("[class,resolve] java.lang.ClassLoader java.lang.Throwable ClassLoader.java (verification)"); diff --git a/test/hotspot/jtreg/runtime/verifier/stackMapTableTests/StackMapTableTest.java b/test/hotspot/jtreg/runtime/verifier/stackMapTableTests/StackMapTableTest.java index f7f2ca1e881..08ddad6464f 100644 --- a/test/hotspot/jtreg/runtime/verifier/stackMapTableTests/StackMapTableTest.java +++ b/test/hotspot/jtreg/runtime/verifier/stackMapTableTests/StackMapTableTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, 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,7 +28,7 @@ * @summary Test that the JVM does not assert when printing a stack map table * containing a stack map with a bad verification type. * @compile badStackMapTable.jcod - * @run main/othervm -verify StackMapTableTest + * @run main/othervm -Xverify:all StackMapTableTest */ public class StackMapTableTest { diff --git a/test/jdk/javax/swing/JFileChooser/6520101/bug6520101.java b/test/jdk/javax/swing/JFileChooser/6520101/bug6520101.java index f6671872ba8..131ccc0e348 100644 --- a/test/jdk/javax/swing/JFileChooser/6520101/bug6520101.java +++ b/test/jdk/javax/swing/JFileChooser/6520101/bug6520101.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2025, 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,7 +27,7 @@ * @bug 6520101 * @summary JFileChooser throws OOM in 1.4.2, 5.0u4 and 1.6.0 * @author Praveen Gupta - * @run main/othervm/timeout=600 -Xmx8m -verify bug6520101 + * @run main/othervm/timeout=600 -Xmx8m -Xverify:all bug6520101 */ import javax.swing.*; diff --git a/test/langtools/tools/javac/VarDeclarationWithAssignment.java b/test/langtools/tools/javac/VarDeclarationWithAssignment.java index 7ee81cbc0e2..171c49274e0 100644 --- a/test/langtools/tools/javac/VarDeclarationWithAssignment.java +++ b/test/langtools/tools/javac/VarDeclarationWithAssignment.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, 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,7 +29,7 @@ * @author turnidge * * @compile VarDeclarationWithAssignment.java - * @run main/othervm -verify VarDeclarationWithAssignment + * @run main/othervm -Xverify:all VarDeclarationWithAssignment */ public From 53ebcdbd029a1c78f8429574b78cecce70c11af2 Mon Sep 17 00:00:00 2001 From: Serguei Spitsyn Date: Tue, 16 Dec 2025 10:28:27 +0000 Subject: [PATCH 313/706] 8373627: assert(!is_vthread_transition_disabler()) failed: no suspend allowed for vthread transition disablers Reviewed-by: pchilanomate, dholmes --- src/hotspot/share/runtime/mountUnmountDisabler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/runtime/mountUnmountDisabler.cpp b/src/hotspot/share/runtime/mountUnmountDisabler.cpp index 5bf00323f10..261bbfb9c18 100644 --- a/src/hotspot/share/runtime/mountUnmountDisabler.cpp +++ b/src/hotspot/share/runtime/mountUnmountDisabler.cpp @@ -367,7 +367,7 @@ MountUnmountDisabler::enable_transition_for_all() { OrderAccess::release(); MonitorLocker ml(VThreadTransition_lock); - if (exclusive_operation_ongoing()) { + if (_is_exclusive) { set_exclusive_operation_ongoing(false); } dec_active_disablers(); From a61394b1da40cfbb617fec35553da2d3c3e27d37 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Tue, 16 Dec 2025 13:18:59 +0000 Subject: [PATCH 314/706] 8373789: No PCH release build failure after JDK-8372543 Reviewed-by: tschatzl --- src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp index 400eb8d25ee..95f9fbe6856 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp @@ -29,6 +29,7 @@ #include "gc/shenandoah/shenandoahHeap.hpp" #include "gc/shenandoah/shenandoahHeapRegionSet.hpp" #include "gc/shenandoah/shenandoahSimpleBitMap.hpp" +#include "logging/logStream.hpp" // Each ShenandoahHeapRegion is associated with a ShenandoahFreeSetPartitionId. enum class ShenandoahFreeSetPartitionId : uint8_t { From 89e77512fd44b6a0299ab36db15142e7544899f3 Mon Sep 17 00:00:00 2001 From: Emanuel Peter Date: Tue, 16 Dec 2025 13:33:02 +0000 Subject: [PATCH 315/706] 8370922: Template Framework Library: Float16 type and operations Reviewed-by: galder, thartmann, bmaillard --- .../jtreg/compiler/igvn/ExpressionFuzzer.java | 39 ++++-- .../library/CodeGenerationDataNameType.java | 22 +++ .../library/Float16Type.java | 62 +++++++++ .../library/Operations.java | 94 +++++++++++-- .../library/PrimitiveType.java | 1 + .../jtreg/compiler/lib/verify/Verify.java | 36 +++++ .../examples/TestExpressions.java | 17 ++- .../verify/tests/TestVerify.java | 4 +- .../verify/tests/TestVerifyFloat16.java | 129 ++++++++++++++++++ 9 files changed, 376 insertions(+), 28 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/lib/template_framework/library/Float16Type.java create mode 100644 test/hotspot/jtreg/testlibrary_tests/verify/tests/TestVerifyFloat16.java diff --git a/test/hotspot/jtreg/compiler/igvn/ExpressionFuzzer.java b/test/hotspot/jtreg/compiler/igvn/ExpressionFuzzer.java index 570c59f0da2..875ef57c865 100644 --- a/test/hotspot/jtreg/compiler/igvn/ExpressionFuzzer.java +++ b/test/hotspot/jtreg/compiler/igvn/ExpressionFuzzer.java @@ -23,10 +23,11 @@ /* * @test - * @bug 8359412 + * @bug 8359412 8370922 * @key randomness * @summary Use the template framework library to generate random expressions. * @modules java.base/jdk.internal.misc + * @modules jdk.incubator.vector * @library /test/lib / * @compile ../lib/verify/Verify.java * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:CompileTaskTimeout=10000 compiler.igvn.ExpressionFuzzer @@ -55,6 +56,7 @@ import compiler.lib.template_framework.library.Operations; import compiler.lib.template_framework.library.PrimitiveType; import compiler.lib.template_framework.library.TestFrameworkClass; import static compiler.lib.template_framework.library.CodeGenerationDataNameType.PRIMITIVE_TYPES; +import static compiler.lib.template_framework.library.CodeGenerationDataNameType.SCALAR_NUMERIC_TYPES; // We generate random Expressions from primitive type operators. // @@ -84,10 +86,14 @@ public class ExpressionFuzzer { comp.addJavaSourceCode("compiler.igvn.templated.ExpressionFuzzerInnerTest", generate(comp)); // Compile the source file. - comp.compile(); + comp.compile("--add-modules=jdk.incubator.vector"); // compiler.igvn.templated.InnterTest.main(new String[] {}); - comp.invoke("compiler.igvn.templated.ExpressionFuzzerInnerTest", "main", new Object[] {new String[] {}}); + comp.invoke("compiler.igvn.templated.ExpressionFuzzerInnerTest", "main", new Object[] {new String[] { + "--add-modules=jdk.incubator.vector", + "--add-opens", "jdk.incubator.vector/jdk.incubator.vector=ALL-UNNAMED", + "--add-opens", "java.base/java.lang=ALL-UNNAMED" + }}); } // Generate a Java source file as String @@ -189,10 +195,10 @@ public class ExpressionFuzzer { case "byte", "short", "char", "int", "long" -> List.of("val", Collections.nCopies(20, integralCmpTemplate.asToken(expression.returnType))); // Float/Double have no range, just return the value: - case "float", "double" -> "val"; + case "float", "double", "Float16" -> "val"; // Check if the boolean constant folded: case "boolean" -> "val, val == true, val == false"; - default -> throw new RuntimeException("should only be primitive types"); + default -> throw new RuntimeException("type not supported yet: " + expression.returnType.name()); } , "};\n", """ @@ -224,7 +230,7 @@ public class ExpressionFuzzer { // Booleans do have an int-range, but restricting it would just make it constant, which // is not very useful: we would like to keep it variable here. We already mix in variable // arguments and constants in the testTemplate. - case "boolean", "float", "double" -> "return v;\n"; + case "boolean", "float", "double", "Float16" -> "return v;\n"; case "byte", "short", "char", "int", "long" -> List.of( // Sometimes constrain the signed range // v = min(max(v, CON1), CON2) @@ -241,7 +247,7 @@ public class ExpressionFuzzer { : List.of(), // FUTURE: we could also constrain the unsigned bounds. "return v;\n"); - default -> throw new RuntimeException("should only be primitive types"); + default -> throw new RuntimeException("type not supported yet: " + type.name()); }, """ } @@ -325,6 +331,7 @@ public class ExpressionFuzzer { // Generate expressions with the primitive types. for (PrimitiveType type : PRIMITIVE_TYPES) { + // Prmitive expressions are most important, so let's create many expressions per output type. for (int i = 0; i < 10; i++) { // The depth determines roughly how many operations are going to be used in the expression. int depth = RANDOM.nextInt(1, 20); @@ -333,6 +340,21 @@ public class ExpressionFuzzer { } } + // Generate expressions with any scalar numeric types. + for (CodeGenerationDataNameType type : SCALAR_NUMERIC_TYPES) { + // The extended set of scalar numeric expressions (incl. special types such as Float16) are relevant + // but don't currently warrant the same number amount of testing time, so we only create 2 cases + // per type. Note: this still produces a lot of expressions, given that we have a lot of output + // types, and even if the output type is "float", we can still use other types in the expression, + // such as "float -> Float16 -> float". We can consider adjusting this arbitrary count in the future. + for (int i = 0; i < 2; i++) { + // The depth determines roughly how many operations are going to be used in the expression. + int depth = RANDOM.nextInt(1, 20); + Expression expression = Expression.nestRandomly(type, Operations.SCALAR_NUMERIC_OPERATIONS, depth); + tests.add(testTemplate.asToken(expression)); + } + } + // Create the test class, which runs all tests. return TestFrameworkClass.render( // package and class name. @@ -341,7 +363,8 @@ public class ExpressionFuzzer { Set.of("compiler.lib.verify.*", "java.util.Random", "jdk.test.lib.Utils", - "compiler.lib.generators.*"), + "compiler.lib.generators.*", + "jdk.incubator.vector.Float16"), // classpath, so the Test VM has access to the compiled class files. comp.getEscapedClassPathOfCompiledClasses(), // The list of tests. diff --git a/test/hotspot/jtreg/compiler/lib/template_framework/library/CodeGenerationDataNameType.java b/test/hotspot/jtreg/compiler/lib/template_framework/library/CodeGenerationDataNameType.java index 56f7afcbaeb..b461e3e857f 100644 --- a/test/hotspot/jtreg/compiler/lib/template_framework/library/CodeGenerationDataNameType.java +++ b/test/hotspot/jtreg/compiler/lib/template_framework/library/CodeGenerationDataNameType.java @@ -100,6 +100,13 @@ public interface CodeGenerationDataNameType extends DataName.Type { */ static PrimitiveType booleans() { return PrimitiveType.BOOLEANS; } + /** + * The Float16 type. + * + * @return The Float16 type. + */ + static CodeGenerationDataNameType float16() { return Float16Type.FLOAT16; } + /** * List of all {@link PrimitiveType}s. */ @@ -154,4 +161,19 @@ public interface CodeGenerationDataNameType extends DataName.Type { floats(), doubles() ); + + /** + * List of all scalar numeric types. + */ + List SCALAR_NUMERIC_TYPES = List.of( + bytes(), + chars(), + shorts(), + ints(), + longs(), + floats(), + doubles(), + booleans(), + float16() + ); } diff --git a/test/hotspot/jtreg/compiler/lib/template_framework/library/Float16Type.java b/test/hotspot/jtreg/compiler/lib/template_framework/library/Float16Type.java new file mode 100644 index 00000000000..e591fe4e045 --- /dev/null +++ b/test/hotspot/jtreg/compiler/lib/template_framework/library/Float16Type.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2025, 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 compiler.lib.template_framework.library; + +import compiler.lib.generators.Generators; +import compiler.lib.generators.Generator; + +import compiler.lib.template_framework.DataName; + +/** + * The {@link Float16Type} models Java's {@link Float16} type. + */ +final class Float16Type implements CodeGenerationDataNameType { + private static final Generator GEN_FLOAT16 = Generators.G.float16s(); + + // We only need one static instance of the class. + static final Float16Type FLOAT16 = new Float16Type(); + + // Private constructor so nobody can create duplicate instances. + private Float16Type() {} + + @Override + public boolean isSubtypeOf(DataName.Type other) { + return other instanceof Float16Type; + } + + @Override + public String name() { + return "Float16"; + } + + @Override + public String toString() { + return name(); + } + + @Override + public Object con() { + return "Float16.shortBitsToFloat16((short)" + GEN_FLOAT16.next() + ")"; + } +} diff --git a/test/hotspot/jtreg/compiler/lib/template_framework/library/Operations.java b/test/hotspot/jtreg/compiler/lib/template_framework/library/Operations.java index 53acf943b20..7d353a8c610 100644 --- a/test/hotspot/jtreg/compiler/lib/template_framework/library/Operations.java +++ b/test/hotspot/jtreg/compiler/lib/template_framework/library/Operations.java @@ -23,9 +23,12 @@ package compiler.lib.template_framework.library; -import java.util.List; import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; import static compiler.lib.template_framework.library.PrimitiveType.BYTES; import static compiler.lib.template_framework.library.PrimitiveType.SHORTS; @@ -35,6 +38,7 @@ import static compiler.lib.template_framework.library.PrimitiveType.LONGS; import static compiler.lib.template_framework.library.PrimitiveType.FLOATS; import static compiler.lib.template_framework.library.PrimitiveType.DOUBLES; import static compiler.lib.template_framework.library.PrimitiveType.BOOLEANS; +import static compiler.lib.template_framework.library.Float16Type.FLOAT16; /** * This class provides various lists of {@link Expression}s, that represent Java operators or library @@ -45,18 +49,39 @@ public final class Operations { // private constructor to avoid instantiation. private Operations() {} + private static Expression.Info WITH_ARITHMETIC_EXCEPTION = new Expression.Info().withExceptions(Set.of("ArithmeticException")); + private static Expression.Info WITH_NONDETERMINISTIC_RESULT = new Expression.Info().withNondeterministicResult(); + + /** * Provides a lits of operations on {@link PrimitiveType}s, such as arithmetic, logical, * and cast operations. */ public static final List PRIMITIVE_OPERATIONS = generatePrimitiveOperations(); + public static final List FLOAT16_OPERATIONS = generateFloat16Operations(); + + public static final List SCALAR_NUMERIC_OPERATIONS = concat( + PRIMITIVE_OPERATIONS, + FLOAT16_OPERATIONS + ); + + @SafeVarargs + private static List concat(List... lists) { + return Arrays.stream(lists) + .flatMap(List::stream) + .collect(Collectors.toList()); + } + + private static void addComparisonOperations(List ops, String operatorName, CodeGenerationDataNameType type) { + for (String mask : List.of("==", "!=", "<", ">", "<=", ">=")) { + ops.add(Expression.make(BOOLEANS, "(" + operatorName + "(", type, ", ", type, ")" + mask + "0)")); + } + } + private static List generatePrimitiveOperations() { List ops = new ArrayList<>(); - Expression.Info withArithmeticException = new Expression.Info().withExceptions(Set.of("ArithmeticException")); - Expression.Info withNondeterministicResult = new Expression.Info().withNondeterministicResult(); - // Cast between all primitive types. Except for Boolean, we cannot cast from and to. CodeGenerationDataNameType.INTEGRAL_AND_FLOATING_TYPES.stream().forEach(src -> { CodeGenerationDataNameType.INTEGRAL_AND_FLOATING_TYPES.stream().forEach(dst -> { @@ -75,8 +100,8 @@ public final class Operations { ops.add(Expression.make(type, "(", type, " + ", type, ")")); ops.add(Expression.make(type, "(", type, " - ", type, ")")); ops.add(Expression.make(type, "(", type, " * ", type, ")")); - ops.add(Expression.make(type, "(", type, " / ", type, ")", withArithmeticException)); - ops.add(Expression.make(type, "(", type, " % ", type, ")", withArithmeticException)); + ops.add(Expression.make(type, "(", type, " / ", type, ")", WITH_ARITHMETIC_EXCEPTION)); + ops.add(Expression.make(type, "(", type, " % ", type, ")", WITH_ARITHMETIC_EXCEPTION)); // Bitwise Operators (non short-circuit) ops.add(Expression.make(type, "(~(", type, "))")); @@ -94,6 +119,8 @@ public final class Operations { ops.add(Expression.make(BOOLEANS, "(", type, " < ", type, ")")); ops.add(Expression.make(BOOLEANS, "(", type, " >= ", type, ")")); ops.add(Expression.make(BOOLEANS, "(", type, " <= ", type, ")")); + addComparisonOperations(ops, type.boxedTypeName() + ".compare", type); + addComparisonOperations(ops, type.boxedTypeName() + ".compareUnsigned", type); // ugt, uge, ule, ult }); CodeGenerationDataNameType.FLOATING_TYPES.stream().forEach(type -> { @@ -112,6 +139,7 @@ public final class Operations { ops.add(Expression.make(BOOLEANS, "(", type, " < ", type, ")")); ops.add(Expression.make(BOOLEANS, "(", type, " >= ", type, ")")); ops.add(Expression.make(BOOLEANS, "(", type, " <= ", type, ")")); + addComparisonOperations(ops, type.boxedTypeName() + ".compare", type); }); // ------------ byte ------------- @@ -152,7 +180,7 @@ public final class Operations { ops.add(Expression.make(INTS, "Integer.compare(", INTS, ", ", INTS, ")")); ops.add(Expression.make(INTS, "Integer.compareUnsigned(", INTS, ", ", INTS, ")")); ops.add(Expression.make(INTS, "Integer.compress(", INTS, ", ", INTS, ")")); - ops.add(Expression.make(INTS, "Integer.divideUnsigned(", INTS, ", ", INTS, ")", withArithmeticException)); + ops.add(Expression.make(INTS, "Integer.divideUnsigned(", INTS, ", ", INTS, ")", WITH_ARITHMETIC_EXCEPTION)); ops.add(Expression.make(INTS, "Integer.expand(", INTS, ", ", INTS, ")")); ops.add(Expression.make(INTS, "Integer.highestOneBit(", INTS, ")")); ops.add(Expression.make(INTS, "Integer.lowestOneBit(", INTS, ")")); @@ -160,7 +188,7 @@ public final class Operations { ops.add(Expression.make(INTS, "Integer.min(", INTS, ", ", INTS, ")")); ops.add(Expression.make(INTS, "Integer.numberOfLeadingZeros(", INTS, ")")); ops.add(Expression.make(INTS, "Integer.numberOfTrailingZeros(", INTS, ")")); - ops.add(Expression.make(INTS, "Integer.remainderUnsigned(", INTS, ", ", INTS, ")", withArithmeticException)); + ops.add(Expression.make(INTS, "Integer.remainderUnsigned(", INTS, ", ", INTS, ")", WITH_ARITHMETIC_EXCEPTION)); ops.add(Expression.make(INTS, "Integer.reverse(", INTS, ")")); ops.add(Expression.make(INTS, "Integer.reverseBytes(", INTS, ")")); ops.add(Expression.make(INTS, "Integer.rotateLeft(", INTS, ", ", INTS, ")")); @@ -178,7 +206,7 @@ public final class Operations { ops.add(Expression.make(INTS, "Long.compare(", LONGS, ", ", LONGS, ")")); ops.add(Expression.make(INTS, "Long.compareUnsigned(", LONGS, ", ", LONGS, ")")); ops.add(Expression.make(LONGS, "Long.compress(", LONGS, ", ", LONGS, ")")); - ops.add(Expression.make(LONGS, "Long.divideUnsigned(", LONGS, ", ", LONGS, ")", withArithmeticException)); + ops.add(Expression.make(LONGS, "Long.divideUnsigned(", LONGS, ", ", LONGS, ")", WITH_ARITHMETIC_EXCEPTION)); ops.add(Expression.make(LONGS, "Long.expand(", LONGS, ", ", LONGS, ")")); ops.add(Expression.make(LONGS, "Long.highestOneBit(", LONGS, ")")); ops.add(Expression.make(LONGS, "Long.lowestOneBit(", LONGS, ")")); @@ -186,7 +214,7 @@ public final class Operations { ops.add(Expression.make(LONGS, "Long.min(", LONGS, ", ", LONGS, ")")); ops.add(Expression.make(INTS, "Long.numberOfLeadingZeros(", LONGS, ")")); ops.add(Expression.make(INTS, "Long.numberOfTrailingZeros(", LONGS, ")")); - ops.add(Expression.make(LONGS, "Long.remainderUnsigned(", LONGS, ", ", LONGS, ")", withArithmeticException)); + ops.add(Expression.make(LONGS, "Long.remainderUnsigned(", LONGS, ", ", LONGS, ")", WITH_ARITHMETIC_EXCEPTION)); ops.add(Expression.make(LONGS, "Long.reverse(", LONGS, ")")); ops.add(Expression.make(LONGS, "Long.reverseBytes(", LONGS, ")")); ops.add(Expression.make(LONGS, "Long.rotateLeft(", LONGS, ", ", INTS, ")")); @@ -201,7 +229,7 @@ public final class Operations { // ------------ Float ------------- ops.add(Expression.make(INTS, "Float.compare(", FLOATS, ", ", FLOATS, ")")); ops.add(Expression.make(INTS, "Float.floatToIntBits(", FLOATS, ")")); - ops.add(Expression.make(INTS, "Float.floatToRawIntBits(", FLOATS, ")", withNondeterministicResult)); + ops.add(Expression.make(INTS, "Float.floatToRawIntBits(", FLOATS, ")", WITH_NONDETERMINISTIC_RESULT)); // Note: there are multiple NaN values with different bit representations. ops.add(Expression.make(FLOATS, "Float.float16ToFloat(", SHORTS, ")")); ops.add(Expression.make(FLOATS, "Float.intBitsToFloat(", INTS, ")")); @@ -220,7 +248,7 @@ public final class Operations { ops.add(Expression.make(INTS, "Double.compare(", DOUBLES, ", ", DOUBLES, ")")); ops.add(Expression.make(LONGS, "Double.doubleToLongBits(", DOUBLES, ")")); // Note: there are multiple NaN values with different bit representations. - ops.add(Expression.make(LONGS, "Double.doubleToRawLongBits(", DOUBLES, ")", withNondeterministicResult)); + ops.add(Expression.make(LONGS, "Double.doubleToRawLongBits(", DOUBLES, ")", WITH_NONDETERMINISTIC_RESULT)); ops.add(Expression.make(DOUBLES, "Double.longBitsToDouble(", LONGS, ")")); ops.add(Expression.make(BOOLEANS, "Double.isFinite(", DOUBLES, ")")); ops.add(Expression.make(BOOLEANS, "Double.isInfinite(", DOUBLES, ")")); @@ -250,4 +278,46 @@ public final class Operations { // Make sure the list is not modifiable. return List.copyOf(ops); } + + private static List generateFloat16Operations() { + List ops = new ArrayList<>(); + + // Casts. + CodeGenerationDataNameType.INTEGRAL_AND_FLOATING_TYPES.stream().forEach(type -> { + if (type == CHARS) { return; } + ops.add(Expression.make(FLOAT16, "Float16.valueOf(", type, ")")); + ops.add(Expression.make(type, "", FLOAT16, "." + type.name() + "Value()")); + }); + + ops.add(Expression.make(FLOAT16, "Float16.abs(", FLOAT16, ")")); + ops.add(Expression.make(FLOAT16, "Float16.add(", FLOAT16, ",", FLOAT16, ")")); + ops.add(Expression.make(INTS, "Float16.compare(", FLOAT16, ",", FLOAT16, ")")); + addComparisonOperations(ops, "Float16.compare", FLOAT16); + ops.add(Expression.make(INTS, "(", FLOAT16, ").compareTo(", FLOAT16, ")")); + ops.add(Expression.make(FLOAT16, "Float16.copySign(", FLOAT16, ",", FLOAT16, ")")); + ops.add(Expression.make(FLOAT16, "Float16.divide(", FLOAT16, ",", FLOAT16, ")")); + ops.add(Expression.make(BOOLEANS, "", FLOAT16, ".equals(", FLOAT16, ")")); + ops.add(Expression.make(SHORTS, "Float16.float16ToRawShortBits(", FLOAT16, ")")); + ops.add(Expression.make(SHORTS, "Float16.float16ToShortBits(", FLOAT16, ")")); + ops.add(Expression.make(FLOAT16, "Float16.fma(", FLOAT16, ",", FLOAT16, ", ", FLOAT16, ")")); + ops.add(Expression.make(INTS, "Float16.getExponent(", FLOAT16, ")")); + ops.add(Expression.make(BOOLEANS, "Float16.isFinite(", FLOAT16, ")")); + ops.add(Expression.make(BOOLEANS, "Float16.isInfinite(", FLOAT16, ")")); + ops.add(Expression.make(BOOLEANS, "Float16.isNaN(", FLOAT16, ")")); + ops.add(Expression.make(FLOAT16, "Float16.max(", FLOAT16, ",", FLOAT16, ")")); + ops.add(Expression.make(FLOAT16, "Float16.min(", FLOAT16, ",", FLOAT16, ")")); + ops.add(Expression.make(FLOAT16, "Float16.multiply(", FLOAT16, ",", FLOAT16, ")")); + ops.add(Expression.make(FLOAT16, "Float16.negate(", FLOAT16, ")")); + ops.add(Expression.make(FLOAT16, "Float16.nextDown(", FLOAT16, ")")); + ops.add(Expression.make(FLOAT16, "Float16.nextUp(", FLOAT16, ")")); + ops.add(Expression.make(FLOAT16, "Float16.scalb(", FLOAT16, ", ", INTS, ")")); + ops.add(Expression.make(FLOAT16, "Float16.shortBitsToFloat16(", SHORTS, ")")); + ops.add(Expression.make(FLOAT16, "Float16.signum(", FLOAT16, ")")); + ops.add(Expression.make(FLOAT16, "Float16.sqrt(", FLOAT16, ")")); + ops.add(Expression.make(FLOAT16, "Float16.subtract(", FLOAT16, ",", FLOAT16, ")")); + ops.add(Expression.make(FLOAT16, "Float16.ulp(", FLOAT16, ")")); + + // Make sure the list is not modifiable. + return List.copyOf(ops); + } } diff --git a/test/hotspot/jtreg/compiler/lib/template_framework/library/PrimitiveType.java b/test/hotspot/jtreg/compiler/lib/template_framework/library/PrimitiveType.java index c0db3d51545..b789da45d44 100644 --- a/test/hotspot/jtreg/compiler/lib/template_framework/library/PrimitiveType.java +++ b/test/hotspot/jtreg/compiler/lib/template_framework/library/PrimitiveType.java @@ -93,6 +93,7 @@ public final class PrimitiveType implements CodeGenerationDataNameType { return name(); } + @Override public Object con() { return switch (kind) { case BYTE -> "(byte)" + GEN_BYTE.next(); diff --git a/test/hotspot/jtreg/compiler/lib/verify/Verify.java b/test/hotspot/jtreg/compiler/lib/verify/Verify.java index 7b5e554b0e3..c79ad2c55a0 100644 --- a/test/hotspot/jtreg/compiler/lib/verify/Verify.java +++ b/test/hotspot/jtreg/compiler/lib/verify/Verify.java @@ -150,6 +150,8 @@ public final class Verify { default -> { if (isVectorAPIClass(ca)) { checkEQForVectorAPIClass(a, b, field, aParent, bParent); + } else if (isFloat16Class(ca)) { + checkEQForFloat16Class(a, b, field, aParent, bParent); } else { checkEQArbitraryClasses(a, b); } @@ -456,6 +458,40 @@ public final class Verify { checkEQdispatch(va, vb, field + ".toArray", aParent, bParent); } + private static boolean isFloat16Class(Class c) { + return c.getName().equals("jdk.incubator.vector.Float16"); + } + + /** + * We do not want to import jdk.incubator.vector.Float16 explicitly, because it would mean we would + * also have to add "--add-modules=jdk.incubator.vector" to the command-line of every test that uses + * the Verify class. So we hack this via reflection. + * + * An additional challenge is the boxing and NaNs, see also isFloatEQ. + */ + private void checkEQForFloat16Class(Object a, Object b, String field, Object aParent, Object bParent) { + Class ca = a.getClass(); + short bitsA; + short bitsB; + try { + Method m = isFloatCheckWithRawBits ? ca.getMethod("float16ToRawShortBits", ca) + : ca.getMethod("float16ToShortBits", ca); + m.setAccessible(true); + bitsA = (short)m.invoke(null, a); + bitsB = (short)m.invoke(null, b); + } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { + throw new RuntimeException("Could not invoke float16ToRawShortBits on " + ca.getName(), e); + } + + if (bitsA != bitsB) { + System.err.println("ERROR: Equality matching failed: value mismatch. check raw: " + isFloatCheckWithRawBits); + System.err.println(" Values: " + a + " vs " + b); + System.err.println(" Bits: " + bitsA + " vs " + bitsB); + print(a, b, field, aParent, bParent); + throw new VerifyException("Value mismatch: " + a + " vs " + b); + } + } + private void checkEQArbitraryClasses(Object a, Object b) { Class c = a.getClass(); while (c != Object.class) { diff --git a/test/hotspot/jtreg/testlibrary_tests/template_framework/examples/TestExpressions.java b/test/hotspot/jtreg/testlibrary_tests/template_framework/examples/TestExpressions.java index 6a0a2d3786a..4bec633553b 100644 --- a/test/hotspot/jtreg/testlibrary_tests/template_framework/examples/TestExpressions.java +++ b/test/hotspot/jtreg/testlibrary_tests/template_framework/examples/TestExpressions.java @@ -23,12 +23,13 @@ /* * @test - * @bug 8359412 + * @bug 8359412 8370922 * @summary Demonstrate the use of Expressions from the Template Library. * @modules java.base/jdk.internal.misc + * @modules jdk.incubator.vector * @library /test/lib / * @compile ../../../compiler/lib/verify/Verify.java - * @run main template_framework.examples.TestExpressions + * @run main ${test.main.class} */ package template_framework.examples; @@ -55,10 +56,14 @@ public class TestExpressions { comp.addJavaSourceCode("p.xyz.InnerTest", generate(comp)); // Compile the source file. - comp.compile(); + comp.compile("--add-modules=jdk.incubator.vector"); // p.xyz.InnterTest.main(new String[] {}); - comp.invoke("p.xyz.InnerTest", "main", new Object[] {new String[] {}}); + comp.invoke("p.xyz.InnerTest", "main", new Object[] {new String[] { + "--add-modules=jdk.incubator.vector", + "--add-opens", "jdk.incubator.vector/jdk.incubator.vector=ALL-UNNAMED", + "--add-opens", "java.base/java.lang=ALL-UNNAMED" + }}); } // Generate a Java source file as String @@ -121,7 +126,7 @@ public class TestExpressions { ); }); - for (Expression operation : Operations.PRIMITIVE_OPERATIONS) { + for (Expression operation : Operations.SCALAR_NUMERIC_OPERATIONS) { tests.add(withConstantsTemplate.asToken(operation)); } @@ -130,7 +135,7 @@ public class TestExpressions { // package and class name. "p.xyz", "InnerTest", // Set of imports. - Set.of("compiler.lib.verify.*"), + Set.of("compiler.lib.verify.*", "jdk.incubator.vector.Float16"), // classpath, so the Test VM has access to the compiled class files. comp.getEscapedClassPathOfCompiledClasses(), // The list of tests. diff --git a/test/hotspot/jtreg/testlibrary_tests/verify/tests/TestVerify.java b/test/hotspot/jtreg/testlibrary_tests/verify/tests/TestVerify.java index 34cff79dd6e..519331b17fd 100644 --- a/test/hotspot/jtreg/testlibrary_tests/verify/tests/TestVerify.java +++ b/test/hotspot/jtreg/testlibrary_tests/verify/tests/TestVerify.java @@ -23,10 +23,10 @@ /* * @test - * @summary Test functionality of IntGenerator implementations. + * @summary Test basic functionality of Verify implementations. * @modules java.base/jdk.internal.misc * @library /test/lib / - * @run driver verify.tests.TestVerify + * @run driver ${test.main.class} */ package verify.tests; diff --git a/test/hotspot/jtreg/testlibrary_tests/verify/tests/TestVerifyFloat16.java b/test/hotspot/jtreg/testlibrary_tests/verify/tests/TestVerifyFloat16.java new file mode 100644 index 00000000000..8d1d763a250 --- /dev/null +++ b/test/hotspot/jtreg/testlibrary_tests/verify/tests/TestVerifyFloat16.java @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2025, 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 randomness + * @summary Test functionality of Verify implementations for Float16. + * @modules jdk.incubator.vector + * @library /test/lib / + * @run driver ${test.main.class} + */ + +package verify.tests; + +import java.lang.foreign.*; +import java.util.Random; +import jdk.test.lib.Utils; + +import jdk.incubator.vector.Float16; + +import compiler.lib.verify.*; + +public class TestVerifyFloat16 { + private static final Random RANDOM = Utils.getRandomInstance(); + + public static void main(String[] args) { + testArrayFloat16(); + testRawFloat16(); + testFloat16Random(); + } + + public static void testArrayFloat16() { + Float16[] a = new Float16[1000]; + Float16[] b = new Float16[1001]; + Float16[] c = new Float16[1000]; + + Verify.checkEQ(a, a); + Verify.checkEQ(b, b); + Verify.checkEQ(a, c); + Verify.checkEQ(c, a); + + // Size mismatch + checkNE(a, b); + + c[RANDOM.nextInt(c.length)] = Float16.valueOf(1f); + + // Value mismatch + checkNE(a, c); + } + + public static void testRawFloat16() { + Float16 nan1 = Float16.shortBitsToFloat16((short)0xFFFF); + Float16 nan2 = Float16.shortBitsToFloat16((short)0x7FFF); + if (!Float16.isNaN(nan1)) { throw new RuntimeException("must be NaN"); } + if (!Float16.isNaN(nan2)) { throw new RuntimeException("must be NaN"); } + if (Float16.float16ToRawShortBits(nan1) != (short)0xFFFF) { throw new RuntimeException("wrong bits"); } + if (Float16.float16ToRawShortBits(nan2) != (short)0x7FFF) { throw new RuntimeException("wrong bits"); } + + Float16[] arr1 = new Float16[]{nan1}; + Float16[] arr2 = new Float16[]{nan2}; + + Verify.checkEQ(nan1, Float16.NaN); + Verify.checkEQ(nan1, nan1); + Verify.checkEQWithRawBits(nan1, nan1); + Verify.checkEQ(nan1, nan2); + + Verify.checkEQ(arr1, arr1); + Verify.checkEQWithRawBits(arr1, arr1); + Verify.checkEQ(arr1, arr2); + + checkNEWithRawBits(nan1, nan2); + + checkNEWithRawBits(arr1, arr2); + } + + public static void testFloat16Random() { + // Testing all 2^16 * 2^16 = 2^32 would take a bit long, so we randomly sample instead. + for (int i = 0; i < 10_000; i++) { + short bitsA = (short)RANDOM.nextInt(); + short bitsB = (short)RANDOM.nextInt(); + Float16 a = Float16.shortBitsToFloat16(bitsA); + Float16 b = Float16.shortBitsToFloat16(bitsB); + if (bitsA == bitsB) { + Verify.checkEQWithRawBits(a, b); + } else { + checkNEWithRawBits(a, b); + } + if (a.equals(b)) { + Verify.checkEQ(a, b); + } else { + checkNE(a, b); + } + } + } + + public static void checkNE(Object a, Object b) { + try { + Verify.checkEQ(a, b); + throw new RuntimeException("Should have thrown: " + a + " vs " + b); + } catch (VerifyException e) {} + } + + public static void checkNEWithRawBits(Object a, Object b) { + try { + Verify.checkEQWithRawBits(a, b); + throw new RuntimeException("Should have thrown: " + a + " vs " + b); + } catch (VerifyException e) {} + } +} From 76e79dbb3eca5589aae6852c8f55adf0759c714e Mon Sep 17 00:00:00 2001 From: Marc Chevalier Date: Tue, 16 Dec 2025 14:32:23 +0000 Subject: [PATCH 316/706] 8371716: C2: Phi node fails Value()'s verification when speculative types clash Co-authored-by: Roland Westrelin Reviewed-by: roland, epeter --- src/hotspot/share/opto/cfgnode.cpp | 64 ++++++++ src/hotspot/share/opto/cfgnode.hpp | 1 + .../igvn/ClashingSpeculativeTypePhiNode.java | 153 ++++++++++++++++++ 3 files changed, 218 insertions(+) create mode 100644 test/hotspot/jtreg/compiler/igvn/ClashingSpeculativeTypePhiNode.java diff --git a/src/hotspot/share/opto/cfgnode.cpp b/src/hotspot/share/opto/cfgnode.cpp index 07657dd0883..776a2d4c90b 100644 --- a/src/hotspot/share/opto/cfgnode.cpp +++ b/src/hotspot/share/opto/cfgnode.cpp @@ -1351,11 +1351,75 @@ const Type* PhiNode::Value(PhaseGVN* phase) const { } #endif //ASSERT + // In rare cases, during an IGVN call to `PhiNode::Value`, `_type` and `t` have incompatible opinion on speculative type, + // resulting into a too small intersection (such as AnyNull), which is removed in cleanup_speculative. + // From that `ft` has no speculative type (ft->speculative() == nullptr). + // After the end of the current `PhiNode::Value` call, `ft` (that is returned) is being store into `_type` + // (see PhaseIterGVN::transform_old -> raise_bottom_type -> set_type). + // + // It is possible that verification happens immediately after, without any change to the current node, or any of its inputs. + // In the verification invocation of `PhiNode::Value`, `t` would be the same as the IGVN `t` (union of input types, that are unchanged), + // but the new `_type` is the value returned by the IGVN invocation of `PhiNode::Value`, the former `ft`, that has no speculative type. + // Thus, the result of `t->filter_speculative(_type)`, the new `ft`, gets the speculative type of `t`, which is not empty. Since the + // result of the verification invocation of `PhiNode::Value` has some speculative type, it is not the same as the previously returned type + // (that had no speculative type), making verification fail. + // + // In such a case, doing the filtering one time more allows to reach a fixpoint. + if (ft->speculative() == nullptr && t->speculative() != nullptr) { + ft = t->filter_speculative(ft); + } + verify_type_stability(phase, t, ft); + // Deal with conversion problems found in data loops. ft = phase->saturate_and_maybe_push_to_igvn_worklist(this, ft); return ft; } +#ifdef ASSERT +// Makes sure that a newly computed type is stable when filtered against the incoming types. +// Otherwise, we may have IGVN verification failures. See PhiNode::Value, and the second +// filtering (enforcing stability), for details. +void PhiNode::verify_type_stability(const PhaseGVN* const phase, const Type* const union_of_input_types, const Type* const new_type) const { + const Type* doubly_filtered_type = union_of_input_types->filter_speculative(new_type); + if (Type::equals(new_type, doubly_filtered_type)) { + return; + } + + stringStream ss; + + ss.print_cr("At node:"); + this->dump("\n", false, &ss); + + const Node* region = in(Region); + for (uint i = 1; i < req(); ++i) { + ss.print("in(%d): ", i); + if (region->in(i) != nullptr && phase->type(region->in(i)) == Type::CONTROL) { + const Type* ti = phase->type(in(i)); + ti->dump_on(&ss); + } + ss.print_cr(""); + } + + ss.print("t: "); + union_of_input_types->dump_on(&ss); + ss.print_cr(""); + + ss.print("_type: "); + _type->dump_on(&ss); + ss.print_cr(""); + + ss.print("Filter once: "); + new_type->dump_on(&ss); + ss.print_cr(""); + ss.print("Filter twice: "); + doubly_filtered_type->dump_on(&ss); + ss.print_cr(""); + tty->print("%s", ss.base()); + tty->flush(); + assert(false, "computed type would not pass verification"); +} +#endif + // Does this Phi represent a simple well-shaped diamond merge? Return the // index of the true path or 0 otherwise. int PhiNode::is_diamond_phi() const { diff --git a/src/hotspot/share/opto/cfgnode.hpp b/src/hotspot/share/opto/cfgnode.hpp index f3ccf23703f..ef799f4c39a 100644 --- a/src/hotspot/share/opto/cfgnode.hpp +++ b/src/hotspot/share/opto/cfgnode.hpp @@ -182,6 +182,7 @@ class PhiNode : public TypeNode { bool is_split_through_mergemem_terminating() const; + void verify_type_stability(const PhaseGVN* phase, const Type* union_of_input_types, const Type* new_type) const NOT_DEBUG_RETURN; bool wait_for_cast_input_igvn(const PhaseIterGVN* igvn) const; public: diff --git a/test/hotspot/jtreg/compiler/igvn/ClashingSpeculativeTypePhiNode.java b/test/hotspot/jtreg/compiler/igvn/ClashingSpeculativeTypePhiNode.java new file mode 100644 index 00000000000..7d8f9e8d409 --- /dev/null +++ b/test/hotspot/jtreg/compiler/igvn/ClashingSpeculativeTypePhiNode.java @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2025, Red Hat, Inc. + * Copyright (c) 2025, 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 8371716 + * @summary Ranges can be proven to be disjoint but not orderable (thanks to unsigned range) + * Comparing such values in such range with != should always be true. + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions + * -XX:-TieredCompilation + * -XX:-UseOnStackReplacement + * -XX:-BackgroundCompilation + * -XX:CompileOnly=${test.main.class}::test1 + * -XX:CompileCommand=quiet + * -XX:TypeProfileLevel=222 + * -XX:+AlwaysIncrementalInline + * -XX:VerifyIterativeGVN=10 + * -XX:CompileCommand=dontinline,${test.main.class}::notInlined1 + * ${test.main.class} + * + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions + * -XX:+UnlockDiagnosticVMOptions + * -XX:-TieredCompilation + * -XX:-UseOnStackReplacement + * -XX:-BackgroundCompilation + * -XX:CompileOnly=${test.main.class}::test2 + * -XX:CompileOnly=${test.main.class}::inlined3 + * -XX:CompileCommand=quiet + * -XX:TypeProfileLevel=200 + * -XX:+AlwaysIncrementalInline + * -XX:VerifyIterativeGVN=10 + * -XX:CompileCommand=dontinline,${test.main.class}::notInlined1 + * -XX:+StressIncrementalInlining + * ${test.main.class} + * + * @run main ${test.main.class} + */ + +package compiler.igvn; + +public class ClashingSpeculativeTypePhiNode { + public static void main(String[] args) { + main1(); + main2(); + } + + // 1st case + + static void main1() { + for (int i = 0; i < 20_000; i++) { + test1(false); // returns null + inlined1(true, true); // returns C1 + inlined2(false); // returns C2 + } + } + + private static Object test1(boolean flag1) { + return inlined1(flag1, false); + // When inlined1 is inlined + // return Phi(flag1, inlined2(flag2), null) + // inlined2 is speculatively returning C1, known from the calls `inlined1(true, true)` in main1 + // Phi node gets speculative type C1 + // When inline2 is inlined + // return Phi[C1](flag1, Phi(false, new C1(), notInlined1()), null) + // => Phi[C1](flag1, notInlined1(), null) + // notInlined1 is speculatively returning C2, known from `inline2(false)` in main1 + // return Phi[C1](flag1, notInlined1()[C2], null) + // Clashing speculative type between Phi's _type (C1) and union of inputs (C2). + } + + private static Object inlined1(boolean flag1, boolean flag2) { + if (flag1) { + return inlined2(flag2); // C1 + } + return null; + } + + private static Object inlined2(boolean flag2) { + if (flag2) { + return new C1(); + } + return notInlined1(); // C2 + } + + private static Object notInlined1() { + return new C2(); + } + + // 2nd case + + static void main2() { + for (int i = 0; i < 20_000; i++) { + inlined3(new C1()); + } + for (int i = 0; i < 20_000; i++) { + test2(true, new C2()); + test2(false, new C2()); + } + } + + + private static Object test2(boolean flag1, Object o) { + o = inlined4(o); + if (flag1) { + return inlined3(o); + } + return null; + // We profile only parameters. Param o is speculated to be C2. + // return Phi(flag1, inline3(inline4(o[C2])), null) + // We inline inline3 + // return Phi(flag1, inline4(o[C2])[C1], null) + // As input of inline3, inline4(o) is speculated to be C1. The Phi has C1 as speculative type in _type + // return Phi[C1](flag1, o[C2], null) + // Since o is speculated to be C2 as parameter of test2, we get a clash. + } + + private static Object inlined3(Object o) { + return o; // C1 + } + + private static Object inlined4(Object o) { + return o; + } + + static class C1 { + + } + + static class C2 { + + } +} From 81e375768837e1ae6c34c1d0a8eff06b4e1d2889 Mon Sep 17 00:00:00 2001 From: Justin Lu Date: Tue, 16 Dec 2025 18:11:37 +0000 Subject: [PATCH 317/706] 8373566: Performance regression with java.text.MessageFormat subformat patterns Reviewed-by: liach, rriggs, naoto --- .../classes/java/text/MessageFormat.java | 69 +++++++++---------- .../java/text/MessageFormatterBench.java | 15 ++++ 2 files changed, 48 insertions(+), 36 deletions(-) diff --git a/src/java.base/share/classes/java/text/MessageFormat.java b/src/java.base/share/classes/java/text/MessageFormat.java index 5477d0f881a..1a850ebaa42 100644 --- a/src/java.base/share/classes/java/text/MessageFormat.java +++ b/src/java.base/share/classes/java/text/MessageFormat.java @@ -1713,12 +1713,7 @@ public class MessageFormat extends Format { throw new IllegalArgumentException("unknown format type: " + type); } // Get the style if recognized, otherwise treat style as a SubformatPattern - FormatStyle fStyle; - try { - fStyle = FormatStyle.fromString(style); - } catch (IllegalArgumentException iae) { - fStyle = FormatStyle.SUBFORMATPATTERN; - } + FormatStyle fStyle = FormatStyle.fromString(style); return switch (fType) { case NUMBER -> switch (fStyle) { case DEFAULT -> NumberFormat.getInstance(locale); @@ -1976,41 +1971,43 @@ public class MessageFormat extends Format { } // Corresponding to the FormatStyle pattern + // WARNING: fromString is dependent on ordinal positioning and Enum names. private enum FormatStyle { - DEFAULT(""), - SHORT("short"), - MEDIUM("medium"), - LONG("long"), - FULL("full"), - INTEGER("integer"), - CURRENCY("currency"), - PERCENT("percent"), - COMPACT_SHORT("compact_short"), - COMPACT_LONG("compact_long"), - OR("or"), - UNIT("unit"), - SUBFORMATPATTERN(null); + // Special styles + DEFAULT, + SUBFORMATPATTERN, + // Pre-defined styles + SHORT, + MEDIUM, + LONG, + FULL, + INTEGER, + CURRENCY, + PERCENT, + COMPACT_SHORT, + COMPACT_LONG, + OR, + UNIT; - private final String text; - - // Differs from FormatType in that the text String is - // not guaranteed to match the Enum name, thus a text field is used - FormatStyle(String text) { - this.text = text; - } - - // This method returns a FormatStyle (excluding SUBFORMATPATTERN) - // that matches the passed String. If no FormatStyle is found, - // an IllegalArgumentException is thrown + // Returns a FormatStyle corresponding to the input text. + // DEFAULT is the empty String. + // Pre-defined styles are lower case versions of their enum name + // (but compared case-insensitive for historical compatibility). + // SUBFORMATPATTERN is anything else. private static FormatStyle fromString(String text) { - for (FormatStyle style : values()) { - // Also check trimmed case-insensitive for historical reasons - if (style != FormatStyle.SUBFORMATPATTERN && - text.trim().compareToIgnoreCase(style.text) == 0) { - return style; + var style = text.trim(); + if (style.isEmpty()) { + return FormatStyle.DEFAULT; + } + var styles = values(); + // Match starting at the pre-defined styles -> [SHORT:] + for (int i = SHORT.ordinal(); i < styles.length; i++) { + var fStyle = styles[i]; + if (style.compareToIgnoreCase(fStyle.name()) == 0) { + return fStyle; } } - throw new IllegalArgumentException(); + return FormatStyle.SUBFORMATPATTERN; } } diff --git a/test/micro/org/openjdk/bench/java/text/MessageFormatterBench.java b/test/micro/org/openjdk/bench/java/text/MessageFormatterBench.java index 5d3399cb46d..191634ad299 100644 --- a/test/micro/org/openjdk/bench/java/text/MessageFormatterBench.java +++ b/test/micro/org/openjdk/bench/java/text/MessageFormatterBench.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2025, 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. * @@ -51,6 +52,8 @@ import java.util.concurrent.TimeUnit; public class MessageFormatterBench { private Object[][] values; + private String choicePattern; + private String numberPattern; @Setup public void setup() { @@ -60,6 +63,8 @@ public class MessageFormatterBench { new Object[]{Double.valueOf(123.89), "MyDisk3"}, new Object[]{Long.valueOf(1234567), "MyDisk4"}, }; + choicePattern = "{0,choice,0#|1#{1}|2#{1} ({2})}"; + numberPattern = "{0,number,000}"; } private MessageFormat messageFormat = new MessageFormat("There is {0} GB of free space on the {1}.", Locale.ENGLISH); @@ -72,6 +77,16 @@ public class MessageFormatterBench { } } + @Benchmark + public MessageFormat testSubformatChoice() { + return new MessageFormat(choicePattern); + } + + @Benchmark + public MessageFormat testSubformatNumber() { + return new MessageFormat(numberPattern); + } + public static void main(String... args) throws Exception { Options opts = new OptionsBuilder().include(MessageFormatterBench.class.getSimpleName()).shouldDoGC(true).build(); new Runner(opts).run(); From b0b42e7eb14dbe04c9c00e8d1fda139a502f2120 Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Tue, 16 Dec 2025 18:19:40 +0000 Subject: [PATCH 318/706] 8373615: Improve HotSpot debug functions findclass() and findmethod Reviewed-by: matsaave, asmehra --- src/hotspot/share/classfile/classPrinter.cpp | 159 ++++++++++++++---- src/hotspot/share/classfile/classPrinter.hpp | 4 +- .../gtest/runtime/test_classPrinter.cpp | 61 ++++++- 3 files changed, 178 insertions(+), 46 deletions(-) diff --git a/src/hotspot/share/classfile/classPrinter.cpp b/src/hotspot/share/classfile/classPrinter.cpp index c4b6a024242..3ed0a5e9840 100644 --- a/src/hotspot/share/classfile/classPrinter.cpp +++ b/src/hotspot/share/classfile/classPrinter.cpp @@ -28,9 +28,10 @@ #include "memory/iterator.hpp" #include "memory/resourceArea.hpp" #include "oops/instanceKlass.hpp" -#include "oops/klass.hpp" +#include "oops/klass.inline.hpp" #include "oops/method.hpp" #include "oops/symbol.hpp" +#include "utilities/growableArray.hpp" #include "utilities/ostream.hpp" class ClassPrinter::KlassPrintClosure : public LockedClassesDo { @@ -42,16 +43,15 @@ class ClassPrinter::KlassPrintClosure : public LockedClassesDo { outputStream* _st; int _num; bool _has_printed_methods; + GrowableArray _klasses; + public: KlassPrintClosure(const char* class_name_pattern, const char* method_name_pattern, const char* method_signature_pattern, bool always_print_class_name, int flags, outputStream* st) - : _class_name_pattern(class_name_pattern), - _method_name_pattern(method_name_pattern), - _method_signature_pattern(method_signature_pattern), - _always_print_class_name(always_print_class_name), + : _always_print_class_name(always_print_class_name), _flags(flags), _st(st), _num(0), _has_printed_methods(false) { if (has_mode(_flags, PRINT_METHOD_HANDLE)) { @@ -66,70 +66,150 @@ public: if (has_mode(_flags, PRINT_BYTECODE)) { _flags |= (PRINT_METHOD_NAME); } + + if (has_mode(_flags, PRINT_CLASS_DETAILS)) { + _always_print_class_name = true; + } + + _class_name_pattern = copy_pattern(class_name_pattern); + _method_name_pattern = copy_pattern(method_name_pattern); + _method_signature_pattern = copy_pattern(method_signature_pattern); + } + + static const char* copy_pattern(const char* pattern) { + if (pattern == nullptr) { + return nullptr; + } + char* copy = ResourceArea::strdup(pattern); + for (char* p = copy; *p; p++) { + if (*p == '.') { + *p = '/'; + } + } + return copy; } virtual void do_klass(Klass* k) { if (!k->is_instance_klass()) { return; } - print_instance_klass(InstanceKlass::cast(k)); + InstanceKlass* ik = InstanceKlass::cast(k); + if (ik->is_loaded() && ik->name()->is_star_match(_class_name_pattern)) { + _klasses.append(ik); + } } + void print() { + _klasses.sort(compare_klasses_alphabetically); + for (int i = 0; i < _klasses.length(); i++) { + print_instance_klass(_klasses.at(i)); + } + } + + static bool match(const char* pattern, Symbol* sym) { return (pattern == nullptr || sym->is_star_match(pattern)); } + static int compare_klasses_alphabetically(InstanceKlass** a, InstanceKlass** b) { + return compare_symbols_alphabetically((*a)->name(), (*b)->name()); + } + + static int compare_methods_alphabetically(const void* a, const void* b) { + Method* ma = *(Method**)a; + Method* mb = *(Method**)b; + int n = compare_symbols_alphabetically(ma->name(), mb->name()); + if (n == 0) { + n = compare_symbols_alphabetically(ma->signature(), mb->signature()); + } + return n; + } + + static int compare_symbols_alphabetically(Symbol* a, Symbol *b) { + if (a == b) { + return 0; + } + if (a != nullptr && b == nullptr) { + return 1; + } + if (a == nullptr && b != nullptr) { + return -1; + } + + return strcmp(a->as_C_string(), b->as_C_string()); + } + void print_klass_name(InstanceKlass* ik) { - _st->print("[%3d] " INTPTR_FORMAT " class %s ", _num++, p2i(ik), ik->name()->as_C_string()); + _st->print("[%3d] " INTPTR_FORMAT " class: %s mirror: " INTPTR_FORMAT " ", _num++, + p2i(ik), ik->name()->as_C_string(), p2i(ik->java_mirror())); ik->class_loader_data()->print_value_on(_st); _st->cr(); } void print_instance_klass(InstanceKlass* ik) { - if (ik->is_loaded() && ik->name()->is_star_match(_class_name_pattern)) { - ResourceMark rm; - if (_has_printed_methods) { - // We have printed some methods in the previous class. - // Print a new line to separate the two classes - _st->cr(); + ResourceMark rm; + if (_has_printed_methods) { + // We have printed some methods in the previous class. + // Print a new line to separate the two classes + _st->cr(); + } + _has_printed_methods = false; + if (_always_print_class_name) { + print_klass_name(ik); + } + + if (has_mode(_flags, ClassPrinter::PRINT_CLASS_DETAILS)) { + _st->print("InstanceKlass: "); + ik->print_on(_st); + oop mirror = ik->java_mirror(); + if (mirror != nullptr) { + _st->print("\nJava mirror oop for %s: ", ik->name()->as_C_string()); + mirror->print_on(_st); } - _has_printed_methods = false; - if (_always_print_class_name) { - print_klass_name(ik); + } + + if (has_mode(_flags, ClassPrinter::PRINT_METHOD_NAME)) { + bool print_codes = has_mode(_flags, ClassPrinter::PRINT_BYTECODE); + int len = ik->methods()->length(); + int num_methods_printed = 0; + + Method** sorted_methods = NEW_RESOURCE_ARRAY(Method*, len); + for (int index = 0; index < len; index++) { + sorted_methods[index] = ik->methods()->at(index); } - if (has_mode(_flags, ClassPrinter::PRINT_METHOD_NAME)) { - bool print_codes = has_mode(_flags, ClassPrinter::PRINT_BYTECODE); - int len = ik->methods()->length(); - int num_methods_printed = 0; + qsort(sorted_methods, len, sizeof(Method*), compare_methods_alphabetically); - for (int index = 0; index < len; index++) { - Method* m = ik->methods()->at(index); - if (match(_method_name_pattern, m->name()) && - match(_method_signature_pattern, m->signature())) { - if (print_codes && num_methods_printed++ > 0) { - _st->cr(); - } - - if (_has_printed_methods == false) { - if (!_always_print_class_name) { - print_klass_name(ik); - } - _has_printed_methods = true; - } - print_method(m); + for (int index = 0; index < len; index++) { + Method* m = sorted_methods[index]; + if (match(_method_name_pattern, m->name()) && + match(_method_signature_pattern, m->signature())) { + if (print_codes && num_methods_printed++ > 0) { + _st->cr(); } + + if (_has_printed_methods == false) { + if (!_always_print_class_name) { + print_klass_name(ik); + } + _has_printed_methods = true; + } + print_method(m); } } } } void print_method(Method* m) { - bool print_codes = has_mode(_flags, ClassPrinter::PRINT_BYTECODE); _st->print_cr(INTPTR_FORMAT " %smethod %s : %s", p2i(m), m->is_static() ? "static " : "", m->name()->as_C_string(), m->signature()->as_C_string()); - if (print_codes) { + + if (has_mode(_flags, ClassPrinter::PRINT_METHOD_DETAILS)) { + m->print_on(_st); + } + + if (has_mode(_flags, ClassPrinter::PRINT_BYTECODE)) { m->print_codes_on(_st, _flags); } } @@ -142,12 +222,16 @@ void ClassPrinter::print_flags_help(outputStream* os) { os->print_cr(" 0x%02x - print the address of bytecodes", PRINT_BYTECODE_ADDR); os->print_cr(" 0x%02x - print info for invokedynamic", PRINT_DYNAMIC); os->print_cr(" 0x%02x - print info for invokehandle", PRINT_METHOD_HANDLE); + os->print_cr(" 0x%02x - print details of the C++ and Java objects that represent classes", PRINT_CLASS_DETAILS); + os->print_cr(" 0x%02x - print details of the C++ objects that represent methods", PRINT_METHOD_DETAILS); os->cr(); } void ClassPrinter::print_classes(const char* class_name_pattern, int flags, outputStream* os) { + ResourceMark rm; KlassPrintClosure closure(class_name_pattern, nullptr, nullptr, true, flags, os); ClassLoaderDataGraph::classes_do(&closure); + closure.print(); } void ClassPrinter::print_methods(const char* class_name_pattern, @@ -174,4 +258,5 @@ void ClassPrinter::print_methods(const char* class_name_pattern, KlassPrintClosure closure(class_name_pattern, method_name_pattern, method_signature_pattern, false, flags | PRINT_METHOD_NAME, os); ClassLoaderDataGraph::classes_do(&closure); + closure.print(); } diff --git a/src/hotspot/share/classfile/classPrinter.hpp b/src/hotspot/share/classfile/classPrinter.hpp index 0fff372c302..470e82ddc0e 100644 --- a/src/hotspot/share/classfile/classPrinter.hpp +++ b/src/hotspot/share/classfile/classPrinter.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, 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 @@ -52,6 +52,8 @@ public: PRINT_BYTECODE_ADDR = 1 << 2, PRINT_DYNAMIC = 1 << 3, // extra information for invokedynamic (and dynamic constant ...) PRINT_METHOD_HANDLE = 1 << 4, // extra information for invokehandle + PRINT_CLASS_DETAILS = 1 << 5, // print details of the C++ and Java objects that represent classes + PRINT_METHOD_DETAILS = 1 << 6, // print details of the C++ objects that represent methods }; static bool has_mode(int flags, Mode mode) { return (flags & static_cast(mode)) != 0; diff --git a/test/hotspot/gtest/runtime/test_classPrinter.cpp b/test/hotspot/gtest/runtime/test_classPrinter.cpp index b13713d7232..9b6d47f09bc 100644 --- a/test/hotspot/gtest/runtime/test_classPrinter.cpp +++ b/test/hotspot/gtest/runtime/test_classPrinter.cpp @@ -28,6 +28,7 @@ #include "utilities/ostream.hpp" #include "unittest.hpp" +using testing::ContainsRegex; using testing::HasSubstr; TEST_VM(ClassPrinter, print_classes) { @@ -35,13 +36,31 @@ TEST_VM(ClassPrinter, print_classes) { ThreadInVMfromNative invm(THREAD); ResourceMark rm; - stringStream ss; - ClassPrinter::print_classes("java/lang/Object", 0x03, &ss); - const char* output = ss.freeze(); + stringStream s1; + ClassPrinter::print_classes("java/lang/Object", 0x03, &s1); + const char* o1 = s1.freeze(); - ASSERT_THAT(output, HasSubstr("class java/lang/Object loader data:")) << "must find java/lang/Object"; - ASSERT_THAT(output, HasSubstr("method wait : (J)V")) << "must find java/lang/Object::wait"; - ASSERT_THAT(output, HasSubstr("method finalize : ()V\n 0 return")) << "must find java/lang/Object::finalize and disasm"; + ASSERT_THAT(o1, HasSubstr("class: java/lang/Object mirror:")) << "must find java/lang/Object"; + ASSERT_THAT(o1, HasSubstr("method wait : (J)V")) << "must find java/lang/Object::wait"; + ASSERT_THAT(o1, HasSubstr("method finalize : ()V\n 0 return")) << "must find java/lang/Object::finalize and disasm"; + + // "." should also work as separator in class name + stringStream s2; + ClassPrinter::print_classes("java.lang.Object", 0x03, &s2); + const char* o2 = s2.freeze(); + ASSERT_THAT(o2, HasSubstr("class: java/lang/Object mirror:")) << "must find java/lang/Object"; + + // 0x20 is PRINT_CLASS_DETAILS + stringStream s3; + ClassPrinter::print_classes("java.lang.Integer", 0x20, &s3); + const char* o3 = s3.freeze(); + ASSERT_THAT(o3, HasSubstr("class: java/lang/Integer mirror:")) << "must find java/lang/Integer"; + ASSERT_THAT(o3, HasSubstr("InstanceKlass: java.lang.Integer {0x")) << "must print InstanceKlass"; + ASSERT_THAT(o3, HasSubstr("Java mirror oop for java/lang/Integer:")) << "must print mirror oop"; +#if GTEST_USES_POSIX_RE + // Complex regex not available on Windows + ASSERT_THAT(o3, ContainsRegex("public static final 'MIN_VALUE' 'I'.* -2147483648 [(]0x80000000[)]")) << "must print static fields"; +#endif } TEST_VM(ClassPrinter, print_methods) { @@ -52,7 +71,7 @@ TEST_VM(ClassPrinter, print_methods) { stringStream s1; ClassPrinter::print_methods("*ang/Object*", "wait", 0x1, &s1); const char* o1 = s1.freeze(); - ASSERT_THAT(o1, HasSubstr("class java/lang/Object loader data:")) << "must find java/lang/Object"; + ASSERT_THAT(o1, HasSubstr("class: java/lang/Object mirror:")) << "must find java/lang/Object"; ASSERT_THAT(o1, HasSubstr("method wait : (J)V")) << "must find java/lang/Object::wait(long)"; ASSERT_THAT(o1, HasSubstr("method wait : ()V")) << "must find java/lang/Object::wait()"; ASSERT_THAT(o1, Not(HasSubstr("method finalize : ()V"))) << "must not find java/lang/Object::finalize"; @@ -60,8 +79,34 @@ TEST_VM(ClassPrinter, print_methods) { stringStream s2; ClassPrinter::print_methods("j*ang/Object*", "wait:(*J*)V", 0x1, &s2); const char* o2 = s2.freeze(); - ASSERT_THAT(o2, HasSubstr("class java/lang/Object loader data:")) << "must find java/lang/Object"; + ASSERT_THAT(o2, HasSubstr("class: java/lang/Object mirror:")) << "must find java/lang/Object"; ASSERT_THAT(o2, HasSubstr("method wait : (J)V")) << "must find java/lang/Object::wait(long)"; ASSERT_THAT(o2, HasSubstr("method wait : (JI)V")) << "must find java/lang/Object::wait(long,int)"; ASSERT_THAT(o2, Not(HasSubstr("method wait : ()V"))) << "must not find java/lang/Object::wait()"; + + // 0x02 is PRINT_BYTECODE + // 0x04 is PRINT_BYTECODE_ADDRESS + // 0x40 is PRINT_METHOD_DETAILS + stringStream s3; + ClassPrinter::print_methods("java.lang.Object", "wait:()V", 0x46, &s3); + const char* o3 = s3.freeze(); + ASSERT_THAT(o3, HasSubstr("method wait : ()V")) << "must find java/lang/Object::wait()"; + +#ifndef PRODUCT + // PRINT_METHOD_DETAILS -- available only in debug builds + ASSERT_THAT(o3, HasSubstr("{method}")) << "must print Method metadata"; +#if GTEST_USES_POSIX_RE + // Complex regex not available on Windows + ASSERT_THAT(o3, ContainsRegex("method holder:.*'java/lang/Object'")) << "must print Method metadata details"; + ASSERT_THAT(o3, ContainsRegex("name: *'wait'")) << "must print Method metadata details"; +#endif +#endif + +#if GTEST_USES_POSIX_RE + // Bytecodes: we should have at least one 'return' bytecide for Object.wait() + // The print out should look like this: + // 0x000000004adf73ad 5 return + ASSERT_THAT(o3, ContainsRegex("0x[0-9a-f]+ +[0-9]+ +return")) << "must print return bytecode"; +#endif + } From a0dd66f92d7f8400b9800847e36d036315628afb Mon Sep 17 00:00:00 2001 From: Saint Wesonga Date: Tue, 16 Dec 2025 18:36:28 +0000 Subject: [PATCH 319/706] 8373630: r18_tls should not be modified on Windows AArch64 Reviewed-by: pchilanomate, aph --- .../cpu/aarch64/c1_Runtime1_aarch64.cpp | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp index 350b6f68196..449ad4f8a4c 100644 --- a/src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp @@ -310,7 +310,18 @@ static void restore_live_registers(StubAssembler* sasm, bool restore_fpu_registe __ add(sp, sp, 32 * wordSize); } +#ifdef R18_RESERVED + /* + Do not modify r18_tls when restoring registers if it is a reserved register. On Windows, + for example, r18_tls is used to store the pointer to the current thread's TEB (where TLS + variables are stored). Therefore, modifying r18_tls would corrupt the TEB pointer. + */ + __ pop(RegSet::range(r0, r17), sp); + __ ldp(zr, r19, Address(__ post(sp, 2 * wordSize))); + __ pop(RegSet::range(r20, r29), sp); +#else __ pop(RegSet::range(r0, r29), sp); +#endif } static void restore_live_registers_except_r0(StubAssembler* sasm, bool restore_fpu_registers = true) { @@ -323,8 +334,20 @@ static void restore_live_registers_except_r0(StubAssembler* sasm, bool restore_f __ add(sp, sp, 32 * wordSize); } +#ifdef R18_RESERVED + /* + Do not modify r18_tls when restoring registers if it is a reserved register. On Windows, + for example, r18_tls is used to store the pointer to the current thread's TEB (where TLS + variables are stored). Therefore, modifying r18_tls would corrupt the TEB pointer. + */ + __ ldp(zr, r1, Address(__ post(sp, 2 * wordSize))); + __ pop(RegSet::range(r2, r17), sp); + __ ldp(zr, r19, Address(__ post(sp, 2 * wordSize))); + __ pop(RegSet::range(r20, r29), sp); +#else __ ldp(zr, r1, Address(__ post(sp, 16))); __ pop(RegSet::range(r2, r29), sp); +#endif } From 817e3dfde9eaa467ea0dca9b70282e914cdde093 Mon Sep 17 00:00:00 2001 From: Mark Powers Date: Tue, 16 Dec 2025 18:38:11 +0000 Subject: [PATCH 320/706] 8350711: [JMH] test Signatures.RSASSAPSS failed for 2 threads config Reviewed-by: hchao, valeriep --- .../bench/java/security/Signatures.java | 197 ++++++++++++------ 1 file changed, 129 insertions(+), 68 deletions(-) diff --git a/test/micro/org/openjdk/bench/java/security/Signatures.java b/test/micro/org/openjdk/bench/java/security/Signatures.java index 1216e253663..b72a4077045 100644 --- a/test/micro/org/openjdk/bench/java/security/Signatures.java +++ b/test/micro/org/openjdk/bench/java/security/Signatures.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (C) 2022, Tencent. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -31,84 +32,142 @@ import java.util.concurrent.TimeUnit; @BenchmarkMode(Mode.Throughput) @OutputTimeUnit(TimeUnit.SECONDS) -@State(Scope.Thread) @Warmup(iterations = 5, time = 1) @Measurement(iterations = 5, time = 1) @Fork(jvmArgs = {"-Xms1024m", "-Xmx1024m", "-Xmn768m", "-XX:+UseParallelGC"}, value = 3) public class Signatures { - private static Signature signer; - @Param({"64", "512", "2048", "16384"}) - private static int messageLength; - - @Param({"secp256r1", "secp384r1", "secp521r1"}) - private String algorithm; - - private static byte[] message; - - @Setup - public void setup() throws Exception { - message = new byte[messageLength]; - (new Random(System.nanoTime())).nextBytes(message); - - String signName = switch (algorithm) { - case "secp256r1" -> "SHA256withECDSA"; - case "secp384r1" -> "SHA384withECDSA"; - case "secp521r1" -> "SHA512withECDSA"; - default -> throw new RuntimeException(); - }; - - AlgorithmParameters params = - AlgorithmParameters.getInstance("EC", "SunEC"); - params.init(new ECGenParameterSpec(algorithm)); - ECGenParameterSpec ecParams = - params.getParameterSpec(ECGenParameterSpec.class); - - KeyPairGenerator kpg = - KeyPairGenerator.getInstance("EC", "SunEC"); - kpg.initialize(ecParams); - KeyPair kp = kpg.generateKeyPair(); - - signer = Signature.getInstance(signName, "SunEC"); - signer.initSign(kp.getPrivate()); + @State(Scope.Benchmark) + public static class test01 { + @Param({"64", "512", "2048", "16384"}) + private int messageLength; + @Param({"secp256r1", "secp384r1", "secp521r1"}) + private String algorithm; + } + @State(Scope.Benchmark) + public static class test02 { + @Param({"64", "512", "2048", "16384"}) + private int messageLength; + @Param({"Ed25519", "Ed448"}) + private String algorithm; + } + @State(Scope.Benchmark) + public static class test03 { + @Param({"64", "512", "2048", "16384"}) + private int messageLength; + @Param({"SHA256withDSA", "SHA384withDSA", "SHA512withDSA"}) + private String algorithm; + } + @State(Scope.Benchmark) + public static class test04 { + @Param({"64", "512", "2048", "16384"}) + private int messageLength; + @Param({"SHA256withRSA", "SHA384withRSA", "SHA512withRSA"}) + private String algorithm; + } + @State(Scope.Benchmark) + public static class test05 { + @Param({"64", "512", "2048", "16384"}) + private int messageLength; + @Param({"SHA256", "SHA384", "SHA512"}) + private String algorithm; } @Benchmark - public byte[] sign() throws SignatureException { - signer.update(message); - return signer.sign(); + public byte[] ECDSA(s1 state) throws Exception { + state.signer.update(state.message); + return state.signer.sign(); } - public static class EdDSA extends Signatures { - @Param({"Ed25519", "Ed448"}) - private String algorithm; + @Benchmark + public byte[] EdDSA(s2 state) throws Exception { + state.signer.update(state.message); + return state.signer.sign(); + } + + @Benchmark + public byte[] DSA(s3 state) throws Exception { + state.signer.update(state.message); + return state.signer.sign(); + } + + @Benchmark + public byte[] RSA(s4 state) throws Exception { + state.signer.update(state.message); + return state.signer.sign(); + } + + @Benchmark + public byte[] RSASSAPSS(s5 state) throws Exception { + state.signer.update(state.message); + return state.signer.sign(); + } + + @State(Scope.Thread) + public static class s1 { + private Signature signer; + private byte[] message; @Setup - public void setup() throws Exception { - message = new byte[messageLength]; + public void setup(test01 test) throws Exception { + message = new byte[test.messageLength]; (new Random(System.nanoTime())).nextBytes(message); + String signName = switch (test.algorithm) { + case "secp256r1" -> "SHA256withECDSA"; + case "secp384r1" -> "SHA384withECDSA"; + case "secp521r1" -> "SHA512withECDSA"; + default -> throw new RuntimeException(); + }; + + AlgorithmParameters params = + AlgorithmParameters.getInstance("EC", "SunEC"); + params.init(new ECGenParameterSpec(test.algorithm)); + ECGenParameterSpec ecParams = + params.getParameterSpec(ECGenParameterSpec.class); + KeyPairGenerator kpg = - KeyPairGenerator.getInstance(algorithm, "SunEC"); - NamedParameterSpec spec = new NamedParameterSpec(algorithm); - kpg.initialize(spec); + KeyPairGenerator.getInstance("EC", "SunEC"); + kpg.initialize(ecParams); KeyPair kp = kpg.generateKeyPair(); - signer = Signature.getInstance(algorithm, "SunEC"); + signer = Signature.getInstance(signName, "SunEC"); signer.initSign(kp.getPrivate()); } } - public static class DSA extends Signatures { - @Param({"SHA256withDSA", "SHA384withDSA", "SHA512withDSA"}) - private String algorithm; + @State(Scope.Thread) + public static class s2 { + private Signature signer; + private byte[] message; @Setup - public void setup() throws Exception { - message = new byte[messageLength]; + public void setup(test02 test) throws Exception { + message = new byte[test.messageLength]; (new Random(System.nanoTime())).nextBytes(message); - int keyLength = switch (algorithm) { + KeyPairGenerator kpg = + KeyPairGenerator.getInstance(test.algorithm, "SunEC"); + NamedParameterSpec spec = new NamedParameterSpec(test.algorithm); + kpg.initialize(spec); + KeyPair kp = kpg.generateKeyPair(); + + signer = Signature.getInstance(test.algorithm, "SunEC"); + signer.initSign(kp.getPrivate()); + } + } + + @State(Scope.Thread) + public static class s3 { + private Signature signer; + private byte[] message; + + @Setup + public void setup(test03 test) throws Exception { + message = new byte[test.messageLength]; + (new Random(System.nanoTime())).nextBytes(message); + + int keyLength = switch (test.algorithm) { case "SHA256withDSA" -> 2048; case "SHA384withDSA" -> 3072; case "SHA512withDSA" -> 3072; @@ -119,21 +178,22 @@ public class Signatures { kpg.initialize(keyLength); KeyPair kp = kpg.generateKeyPair(); - signer = Signature.getInstance(algorithm); + signer = Signature.getInstance(test.algorithm); signer.initSign(kp.getPrivate()); } } - public static class RSA extends Signatures { - @Param({"SHA256withRSA", "SHA384withRSA", "SHA512withRSA"}) - private String algorithm; + @State(Scope.Thread) + public static class s4 { + private Signature signer; + private byte[] message; @Setup - public void setup() throws Exception { - message = new byte[messageLength]; + public void setup(test04 test) throws Exception { + message = new byte[test.messageLength]; (new Random(System.nanoTime())).nextBytes(message); - int keyLength = switch (algorithm) { + int keyLength = switch (test.algorithm) { case "SHA256withRSA" -> 2048; case "SHA384withRSA" -> 3072; case "SHA512withRSA" -> 4096; @@ -144,28 +204,29 @@ public class Signatures { kpg.initialize(keyLength); KeyPair kp = kpg.generateKeyPair(); - signer = Signature.getInstance(algorithm); + signer = Signature.getInstance(test.algorithm); signer.initSign(kp.getPrivate()); } } - public static class RSASSAPSS extends Signatures { - @Param({"SHA256", "SHA384", "SHA512"}) - private String algorithm; + @State(Scope.Thread) + public static class s5 { + private Signature signer; + private byte[] message; @Setup - public void setup() throws Exception { - message = new byte[messageLength]; + public void setup(test05 test) throws Exception { + message = new byte[test.messageLength]; (new Random(System.nanoTime())).nextBytes(message); - int keyLength = switch (algorithm) { + int keyLength = switch (test.algorithm) { case "SHA256" -> 2048; case "SHA384" -> 3072; case "SHA512" -> 4096; default -> throw new RuntimeException(); }; - PSSParameterSpec spec = switch (algorithm) { + PSSParameterSpec spec = switch (test.algorithm) { case "SHA256" -> new PSSParameterSpec( "SHA-256", "MGF1", From 1e357e9e976bfb0abc9d4e14bfb1572693622af8 Mon Sep 17 00:00:00 2001 From: Roger Riggs Date: Tue, 16 Dec 2025 20:23:58 +0000 Subject: [PATCH 321/706] 8373623: Refactor Serialization tests for Records to JUnit Reviewed-by: jlu --- .../records/AbsentStreamValuesTest.java | 48 +++++----- .../records/BadCanonicalCtrTest.java | 30 +++--- .../io/Serializable/records/BadValues.java | 17 ++-- .../Serializable/records/BasicRecordSer.java | 56 ++++++----- .../records/ConstructorAccessTest.java | 19 ++-- .../io/Serializable/records/CycleTest.java | 33 +++---- .../records/DifferentStreamFieldsTest.java | 95 ++++++++++--------- .../records/ProhibitedMethods.java | 46 +++++---- .../Serializable/records/ReadResolveTest.java | 22 +++-- .../Serializable/records/RecordClassTest.java | 36 +++---- .../records/SerialPersistentFieldsTest.java | 28 +++--- .../records/SerialVersionUIDTest.java | 37 ++++---- .../Serializable/records/StreamRefTest.java | 23 ++--- .../records/ThrowingConstructorTest.java | 33 ++++--- .../io/Serializable/records/UnsharedTest.java | 29 +++--- .../records/WriteReplaceTest.java | 24 +++-- .../records/migration/AbstractTest.java | 9 +- .../records/migration/AssignableFromTest.java | 25 ++--- .../records/migration/DefaultValuesTest.java | 23 +++-- .../migration/SuperStreamFieldsTest.java | 34 ++++--- 20 files changed, 367 insertions(+), 300 deletions(-) diff --git a/test/jdk/java/io/Serializable/records/AbsentStreamValuesTest.java b/test/jdk/java/io/Serializable/records/AbsentStreamValuesTest.java index 0f72b9f8f67..02cb35601a9 100644 --- a/test/jdk/java/io/Serializable/records/AbsentStreamValuesTest.java +++ b/test/jdk/java/io/Serializable/records/AbsentStreamValuesTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, 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,7 +25,7 @@ * @test * @bug 8246774 * @summary Checks that the appropriate default value is given to the canonical ctr - * @run testng AbsentStreamValuesTest + * @run junit AbsentStreamValuesTest */ import java.io.ByteArrayInputStream; @@ -34,16 +34,20 @@ import java.io.DataOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.Serializable; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import static java.io.ObjectStreamConstants.*; import static java.lang.System.out; -import static org.testng.Assert.*; + +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; /** * Basic test to check that default primitive / reference values are presented * to the record's canonical constructor, for fields not in the stream. */ +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class AbsentStreamValuesTest { record R01(boolean x) implements Serializable { } @@ -61,7 +65,6 @@ public class AbsentStreamValuesTest { record R13(R12 x) implements Serializable { } record R14(R13[] x) implements Serializable { } - @DataProvider(name = "recordTypeAndExpectedValue") public Object[][] recordTypeAndExpectedValue() { return new Object[][] { new Object[] { R01.class, false }, @@ -81,7 +84,8 @@ public class AbsentStreamValuesTest { }; } - @Test(dataProvider = "recordTypeAndExpectedValue") + @ParameterizedTest + @MethodSource("recordTypeAndExpectedValue") public void testWithDifferentTypes(Class clazz, Object expectedXValue) throws Exception { @@ -92,7 +96,7 @@ public class AbsentStreamValuesTest { Object obj = deserialize(bytes); out.println("deserialized: " + obj); Object actualXValue = clazz.getDeclaredMethod("x").invoke(obj); - assertEquals(actualXValue, expectedXValue); + assertEquals(expectedXValue, actualXValue); } // --- all together @@ -107,18 +111,18 @@ public class AbsentStreamValuesTest { R15 obj = (R15)deserialize(bytes); out.println("deserialized: " + obj); - assertEquals(obj.a, false); - assertEquals(obj.b, 0); - assertEquals(obj.c, 0); - assertEquals(obj.d, '\u0000'); - assertEquals(obj.e, 0); - assertEquals(obj.f, 0l); - assertEquals(obj.g, 0f); - assertEquals(obj.h, 0d); - assertEquals(obj.i, null); - assertEquals(obj.j, null); - assertEquals(obj.k, null); - assertEquals(obj.l, null); + assertEquals(false, obj.a); + assertEquals(0, obj.b); + assertEquals(0, obj.c); + assertEquals('\u0000', obj.d); + assertEquals(0, obj.e); + assertEquals(0l, obj.f); + assertEquals(0f, obj.g); + assertEquals(0d, obj.h); + assertEquals(null, obj.i); + assertEquals(null, obj.j); + assertEquals(null, obj.k); + assertEquals(null, obj.l); } // --- generic type @@ -132,8 +136,8 @@ public class AbsentStreamValuesTest { R16 obj = (R16)deserialize(bytes); out.println("deserialized: " + obj); - assertEquals(obj.t, null); - assertEquals(obj.u, null); + assertEquals(null, obj.t); + assertEquals(null, obj.u); } // --- infra diff --git a/test/jdk/java/io/Serializable/records/BadCanonicalCtrTest.java b/test/jdk/java/io/Serializable/records/BadCanonicalCtrTest.java index 44959eaea87..528a006fc87 100644 --- a/test/jdk/java/io/Serializable/records/BadCanonicalCtrTest.java +++ b/test/jdk/java/io/Serializable/records/BadCanonicalCtrTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, 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,7 +27,7 @@ * @summary InvalidClassException is thrown when the canonical constructor * cannot be found during deserialization. * @library /test/lib - * @run testng BadCanonicalCtrTest + * @run junit BadCanonicalCtrTest */ import java.io.ByteArrayInputStream; @@ -44,22 +44,25 @@ import java.lang.constant.MethodTypeDesc; import jdk.test.lib.compiler.InMemoryJavaCompiler; import jdk.test.lib.ByteCodeLoader; -import org.testng.annotations.BeforeTest; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import static java.lang.System.out; import static java.lang.classfile.ClassFile.ACC_PUBLIC; import static java.lang.constant.ConstantDescs.CD_Object; import static java.lang.constant.ConstantDescs.CD_void; import static java.lang.constant.ConstantDescs.INIT_NAME; import static java.lang.constant.ConstantDescs.MTD_void; -import static org.testng.Assert.assertTrue; -import static org.testng.Assert.expectThrows; + +import org.junit.jupiter.api.Assertions; +import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; /** * Checks that an InvalidClassException is thrown when the canonical * constructor cannot be found during deserialization. */ +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class BadCanonicalCtrTest { // ClassLoader for creating instances of the records to test with. @@ -76,7 +79,7 @@ public class BadCanonicalCtrTest { * the initial bytecode for the record classes using javac, then removes or * modifies the generated canonical constructor. */ - @BeforeTest + @BeforeAll public void setup() { { byte[] byteCode = InMemoryJavaCompiler.compile("R1", @@ -133,7 +136,6 @@ public class BadCanonicalCtrTest { return c.getConstructor(long.class).newInstance(l); } - @DataProvider(name = "recordInstances") public Object[][] recordInstances() throws Exception { return new Object[][] { new Object[] { newR1() }, @@ -148,13 +150,14 @@ public class BadCanonicalCtrTest { * Tests that InvalidClassException is thrown when no constructor is * present. */ - @Test(dataProvider = "recordInstances") + @ParameterizedTest + @MethodSource("recordInstances") public void missingConstructorTest(Object objToSerialize) throws Exception { out.println("\n---"); out.println("serializing : " + objToSerialize); byte[] bytes = serialize(objToSerialize); out.println("deserializing"); - InvalidClassException ice = expectThrows(ICE, () -> deserialize(bytes, missingCtrClassLoader)); + InvalidClassException ice = Assertions.assertThrows(ICE, () -> deserialize(bytes, missingCtrClassLoader)); out.println("caught expected ICE: " + ice); assertTrue(ice.getMessage().contains("record canonical constructor not found")); } @@ -164,13 +167,14 @@ public class BadCanonicalCtrTest { * constructor is not present. ( a non-canonical constructor is * present ). */ - @Test(dataProvider = "recordInstances") + @ParameterizedTest + @MethodSource("recordInstances") public void nonCanonicalConstructorTest(Object objToSerialize) throws Exception { out.println("\n---"); out.println("serializing : " + objToSerialize); byte[] bytes = serialize(objToSerialize); out.println("deserializing"); - InvalidClassException ice = expectThrows(ICE, () -> deserialize(bytes, nonCanonicalCtrClassLoader)); + InvalidClassException ice = Assertions.assertThrows(ICE, () -> deserialize(bytes, nonCanonicalCtrClassLoader)); out.println("caught expected ICE: " + ice); assertTrue(ice.getMessage().contains("record canonical constructor not found")); } diff --git a/test/jdk/java/io/Serializable/records/BadValues.java b/test/jdk/java/io/Serializable/records/BadValues.java index 4e3dbaa200f..9d5e0c7be82 100644 --- a/test/jdk/java/io/Serializable/records/BadValues.java +++ b/test/jdk/java/io/Serializable/records/BadValues.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, 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,7 +24,7 @@ /* * @test * @summary Basic test for ClassNotFoundException - * @run testng BadValues + * @run junit BadValues */ import java.io.ByteArrayInputStream; @@ -32,10 +32,11 @@ import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.IOException; import java.io.ObjectInputStream; -import org.testng.annotations.Test; import static java.io.ObjectStreamConstants.*; import static java.lang.System.out; -import static org.testng.Assert.*; + +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; /** * Not directly related to records but provokes surrounding code, and ensures @@ -73,7 +74,7 @@ public class BadValues { public void testNotFoundSer() throws Exception { out.println("\n---"); byte[] bytes = byteStreamFor("XxYyZz", 0L, (byte)SC_SERIALIZABLE); - Throwable t = expectThrows(CNFE, () -> deserialize(bytes)); + Throwable t = assertThrows(CNFE, () -> deserialize(bytes)); out.println("caught expected CNFE: " + t); } @@ -81,7 +82,7 @@ public class BadValues { public void testNotFoundSerWr() throws Exception { out.println("\n---"); byte[] bytes = byteStreamFor("XxYyZz", 0L, (byte)(SC_SERIALIZABLE | SC_WRITE_METHOD)); - Throwable t = expectThrows(CNFE, () -> deserialize(bytes)); + Throwable t = assertThrows(CNFE, () -> deserialize(bytes)); out.println("caught expected CNFE: " + t); } @@ -89,7 +90,7 @@ public class BadValues { public void testNotFoundExt() throws Exception { out.println("\n---"); byte[] bytes = byteStreamFor("AaBbCc", 0L, (byte)SC_EXTERNALIZABLE); - Throwable t = expectThrows(CNFE, () -> deserialize(bytes)); + Throwable t = assertThrows(CNFE, () -> deserialize(bytes)); out.println("caught expected CNFE: " + t); } @@ -97,7 +98,7 @@ public class BadValues { public void testNotFoundExtWr() throws Exception { out.println("\n---"); byte[] bytes = byteStreamFor("AaBbCc", 0L, (byte)(SC_SERIALIZABLE | SC_WRITE_METHOD)); - Throwable t = expectThrows(CNFE, () -> deserialize(bytes)); + Throwable t = assertThrows(CNFE, () -> deserialize(bytes)); out.println("caught expected CNFE: " + t); } diff --git a/test/jdk/java/io/Serializable/records/BasicRecordSer.java b/test/jdk/java/io/Serializable/records/BasicRecordSer.java index 94a79e85b38..b05d6bd9550 100644 --- a/test/jdk/java/io/Serializable/records/BasicRecordSer.java +++ b/test/jdk/java/io/Serializable/records/BasicRecordSer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, 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,7 +25,7 @@ * @test * @bug 8246774 * @summary Basic test that serializes and deserializes a number of records - * @run testng BasicRecordSer + * @run junit BasicRecordSer */ import java.io.ByteArrayInputStream; @@ -39,19 +39,24 @@ import java.io.ObjectOutput; import java.io.ObjectOutputStream; import java.io.Serializable; import java.math.BigInteger; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import static java.lang.String.format; import static java.lang.System.out; import static java.net.InetAddress.getLoopbackAddress; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; -import static org.testng.Assert.expectThrows; -import static org.testng.Assert.fail; + +import org.junit.jupiter.api.Assertions; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; /** * Basic test that serializes and deserializes a number of simple records. */ +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class BasicRecordSer { // a mix of a few record and non-record classes @@ -101,7 +106,6 @@ public class BasicRecordSer { record Wubble (Wobble wobble, Wibble wibble, String s) implements ThrowingExternalizable { } - @DataProvider(name = "serializable") public Object[][] serializable() { Foo foo = new Foo(23); return new Object[][] { @@ -121,14 +125,20 @@ public class BasicRecordSer { } /** Tests serializing and deserializing a number of records. */ - @Test(dataProvider = "serializable") + @ParameterizedTest + @MethodSource("serializable") public void testSerializable(Object objToSerialize) throws Exception { out.println("\n---"); out.println("serializing : " + objToSerialize); var objDeserialized = serializeDeserialize(objToSerialize); out.println("deserialized: " + objDeserialized); - assertEquals(objToSerialize, objDeserialized); - assertEquals(objDeserialized, objToSerialize); + if (objToSerialize.getClass().isArray()) { + assertArrayEquals((Object[]) objDeserialized, (Object[]) objToSerialize); + assertArrayEquals((Object[]) objToSerialize, (Object[]) objDeserialized); + } else { + assertEquals(objDeserialized, objToSerialize); + assertEquals(objToSerialize, objDeserialized); + } } /** Tests serializing and deserializing of local records. */ @@ -154,8 +164,8 @@ public class BasicRecordSer { out.println("serializing : " + objToSerialize); Foo[] objDeserialized = (Foo[])serializeDeserialize(objToSerialize); out.println("deserialized: " + objDeserialized); - assertEquals(objToSerialize, objDeserialized); - assertEquals(objDeserialized, objToSerialize); + Assertions.assertArrayEquals(objDeserialized, objToSerialize); + Assertions.assertArrayEquals(objToSerialize, objDeserialized); for (Foo f : objDeserialized) assertTrue(objDeserialized[0] == f); @@ -171,8 +181,8 @@ public class BasicRecordSer { out.println("serializing : " + objToSerialize); Wobble[] objDeserialized = (Wobble[])serializeDeserialize(objToSerialize); out.println("deserialized: " + objDeserialized); - assertEquals(objToSerialize, objDeserialized); - assertEquals(objDeserialized, objToSerialize); + Assertions.assertArrayEquals(objDeserialized, objToSerialize); + Assertions.assertArrayEquals(objToSerialize, objDeserialized); for (Wobble w : objDeserialized) { assertTrue(objDeserialized[0] == w); @@ -192,7 +202,6 @@ public class BasicRecordSer { final NotSer notSer = new NotSer(7); } - @DataProvider(name = "notSerializable") public Object[][] notSerializable() { return new Object[][] { new Object[] { new NotSerEmpty() }, @@ -209,11 +218,12 @@ public class BasicRecordSer { static final Class NSE = NotSerializableException.class; /** Tests that non-Serializable record objects throw NotSerializableException. */ - @Test(dataProvider = "notSerializable") + @ParameterizedTest + @MethodSource("notSerializable") public void testNotSerializable(Object objToSerialize) throws Exception { out.println("\n---"); out.println("serializing : " + objToSerialize); - NotSerializableException expected = expectThrows(NSE, () -> serialize(objToSerialize)); + NotSerializableException expected = Assertions.assertThrows(NSE, () -> serialize(objToSerialize)); out.println("caught expected NSE:" + expected); } @@ -235,9 +245,9 @@ public class BasicRecordSer { out.println("serializing : " + objToSerialize); var objDeserialized = serializeDeserialize(objToSerialize); out.println("deserialized: " + objDeserialized); - assertEquals(objToSerialize, objDeserialized); assertEquals(objDeserialized, objToSerialize); - assertEquals(e_ctrInvocationCount, 1); + assertEquals(objToSerialize, objDeserialized); + assertEquals(1, e_ctrInvocationCount); } // --- @@ -258,9 +268,9 @@ public class BasicRecordSer { var objToSerialize = new G(); g_ctrInvocationCount = 0; // reset out.println("serializing : " + objToSerialize); - NotSerializableException expected = expectThrows(NSE, () -> serialize(objToSerialize)); + NotSerializableException expected = Assertions.assertThrows(NSE, () -> serialize(objToSerialize)); out.println("caught expected NSE:" + expected); - assertEquals(g_ctrInvocationCount, 0); + assertEquals(0, g_ctrInvocationCount); } // --- infra diff --git a/test/jdk/java/io/Serializable/records/ConstructorAccessTest.java b/test/jdk/java/io/Serializable/records/ConstructorAccessTest.java index 5057fcc7cbb..c84c7c9519e 100644 --- a/test/jdk/java/io/Serializable/records/ConstructorAccessTest.java +++ b/test/jdk/java/io/Serializable/records/ConstructorAccessTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, 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,7 @@ * @bug 8246774 * @summary Ensures that the serialization implementation can *always* access * the record constructor - * @run testng ConstructorAccessTest + * @run junit ConstructorAccessTest */ import java.io.ByteArrayInputStream; @@ -38,16 +38,19 @@ import java.io.ObjectOutput; import java.io.ObjectOutputStream; import java.io.Externalizable; import java.io.Serializable; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import static java.lang.System.out; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.fail; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.fail; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; /*implicit*/ record Aux1 (int x) implements Serializable { } /*implicit*/ record Aux2 (int x) implements Serializable { } +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class ConstructorAccessTest { public record A (int x) implements Serializable { } @@ -75,7 +78,6 @@ public class ConstructorAccessTest { private record H (double d) implements ThrowingExternalizable { } - @DataProvider(name = "recordInstances") public Object[][] recordInstances() { return new Object[][] { new Object[] { new A(34) }, @@ -91,7 +93,8 @@ public class ConstructorAccessTest { }; } - @Test(dataProvider = "recordInstances") + @ParameterizedTest + @MethodSource("recordInstances") public void roundTrip(Object objToSerialize) throws Exception { out.println("\n---"); out.println("serializing : " + objToSerialize); diff --git a/test/jdk/java/io/Serializable/records/CycleTest.java b/test/jdk/java/io/Serializable/records/CycleTest.java index 53d1247e808..7b323a78af8 100644 --- a/test/jdk/java/io/Serializable/records/CycleTest.java +++ b/test/jdk/java/io/Serializable/records/CycleTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, 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,7 +25,7 @@ * @test * @bug 8246774 * @summary Ensures basic behavior of cycles from record components - * @run testng CycleTest + * @run junit CycleTest */ import java.io.ByteArrayInputStream; @@ -34,10 +34,11 @@ import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; -import org.testng.annotations.Test; import static java.lang.System.out; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.Test; public class CycleTest { @@ -61,10 +62,10 @@ public class CycleTest { out.println("serializing : " + r); R deserializedObj = serializeDeserialize(r); out.println("deserialized: " + deserializedObj); - assertEquals(deserializedObj.x(), 1); // sanity - assertEquals(deserializedObj.y(), 2); // sanity + assertEquals(1, deserializedObj.x()); // sanity + assertEquals(2, deserializedObj.y()); // sanity assertTrue(deserializedObj.c() instanceof C); // sanity - assertEquals(deserializedObj.c().obj, null); // cycle, expect null + assertEquals(null, deserializedObj.c().obj); // cycle, expect null } /** @@ -84,8 +85,8 @@ public class CycleTest { out.println("deserialized: " + deserializedObj); assertTrue(deserializedObj instanceof C); // sanity assertTrue(deserializedObj.obj != null); // expect non-null, r - assertEquals(((R)deserializedObj.obj).x(), 3); // sanity - assertEquals(((R)deserializedObj.obj).y(), 4); // sanity + assertEquals(3, ((R)deserializedObj.obj).x()); // sanity + assertEquals(4, ((R)deserializedObj.obj).y()); // sanity } record R2 (int x, int y, C c1, C c2) implements Serializable { } @@ -105,8 +106,8 @@ public class CycleTest { out.println("serializing : " + r); R2 deserializedObj = serializeDeserialize(r); out.println("deserialized: " + deserializedObj); - assertEquals(deserializedObj.x(), 5); // sanity - assertEquals(deserializedObj.y(), 6); // sanity + assertEquals(5, deserializedObj.x()); // sanity + assertEquals(6, deserializedObj.y()); // sanity c1 = deserializedObj.c1(); c2 = deserializedObj.c2(); @@ -132,11 +133,11 @@ public class CycleTest { R3 deserializedObj = serializeDeserialize(r3); out.println("deserialized: " + deserializedObj); assertTrue(deserializedObj.r() != null); - assertEquals(deserializedObj.l(), 9); // sanity - assertEquals(deserializedObj.r().x(), 7); // sanity - assertEquals(deserializedObj.r().y(), 8); // sanity + assertEquals(9, deserializedObj.l()); // sanity + assertEquals(7, deserializedObj.r().x()); // sanity + assertEquals(8, deserializedObj.r().y()); // sanity assertTrue(deserializedObj.r().c() instanceof C); // sanity - assertEquals(deserializedObj.r().c().obj, null); // cycle, expect null + assertEquals(null, deserializedObj.r().c().obj); // cycle, expect null } // --- infra diff --git a/test/jdk/java/io/Serializable/records/DifferentStreamFieldsTest.java b/test/jdk/java/io/Serializable/records/DifferentStreamFieldsTest.java index 02175c53bb8..2960cc4f723 100644 --- a/test/jdk/java/io/Serializable/records/DifferentStreamFieldsTest.java +++ b/test/jdk/java/io/Serializable/records/DifferentStreamFieldsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, 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,7 @@ * @bug 8246774 * @summary Checks that the appropriate value is given to the canonical ctr * @library /test/lib - * @run testng DifferentStreamFieldsTest + * @run junit DifferentStreamFieldsTest */ import java.io.ByteArrayInputStream; @@ -38,14 +38,19 @@ import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import jdk.test.lib.serial.SerialObjectBuilder; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import static java.lang.System.out; -import static org.testng.Assert.assertEquals; + +import org.junit.jupiter.api.Assertions; +import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; /** * Checks that the appropriate value is given to the canonical ctr. */ +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class DifferentStreamFieldsTest { record R01(boolean x) implements Serializable {} @@ -76,7 +81,6 @@ public class DifferentStreamFieldsTest { record R14(R13[]x) implements Serializable {} - @DataProvider(name = "recordTypeAndExpectedValue") public Object[][] recordTypeAndExpectedValue() { return new Object[][]{ new Object[]{R01.class, false}, @@ -96,7 +100,8 @@ public class DifferentStreamFieldsTest { }; } - @Test(dataProvider = "recordTypeAndExpectedValue") + @ParameterizedTest + @MethodSource("recordTypeAndExpectedValue") public void testWithDifferentTypes(Class clazz, Object expectedXValue) throws Exception { out.println("\n---"); @@ -108,7 +113,7 @@ public class DifferentStreamFieldsTest { Object obj = deserialize(bytes); out.println("deserialized: " + obj); Object actualXValue = clazz.getDeclaredMethod("x").invoke(obj); - assertEquals(actualXValue, expectedXValue); + assertEquals(expectedXValue, actualXValue); bytes = SerialObjectBuilder .newBuilder(clazz.getName()) @@ -118,7 +123,7 @@ public class DifferentStreamFieldsTest { obj = deserialize(bytes); out.println("deserialized: " + obj); actualXValue = clazz.getDeclaredMethod("x").invoke(obj); - assertEquals(actualXValue, expectedXValue); + assertEquals(expectedXValue, actualXValue); } // --- all together @@ -137,18 +142,18 @@ public class DifferentStreamFieldsTest { R15 obj = deserialize(bytes); out.println("deserialized: " + obj); - assertEquals(obj.a, false); - assertEquals(obj.b, 0); - assertEquals(obj.c, 0); - assertEquals(obj.d, '\u0000'); - assertEquals(obj.e, 0); - assertEquals(obj.f, 0l); - assertEquals(obj.g, 0f); - assertEquals(obj.h, 0d); - assertEquals(obj.i, null); - assertEquals(obj.j, null); - assertEquals(obj.k, null); - assertEquals(obj.l, null); + assertEquals(false, obj.a); + assertEquals(0, obj.b); + assertEquals(0, obj.c); + assertEquals('\u0000', obj.d); + assertEquals(0, obj.e); + assertEquals(0l, obj.f); + assertEquals(0f, obj.g); + assertEquals(0d, obj.h); + assertEquals(null, obj.i); + assertEquals(null, obj.j); + assertEquals(null, obj.k); + assertEquals(null, obj.l); } @Test @@ -166,9 +171,9 @@ public class DifferentStreamFieldsTest { .build(); var deser1 = deserialize(OOSBytes); - assertEquals(deser1, r); + assertEquals(r, deser1); var deser2 = deserialize(builderBytes); - assertEquals(deser2, deser1); + assertEquals(deser1, deser2); } { record R(int x, int y) implements Serializable {} @@ -176,7 +181,7 @@ public class DifferentStreamFieldsTest { var r = new R(7, 8); byte[] OOSBytes = serialize(r); var deser1 = deserialize(OOSBytes); - assertEquals(deser1, r); + assertEquals(r, deser1); byte[] builderBytes = SerialObjectBuilder .newBuilder(R.class.getName()) @@ -185,7 +190,7 @@ public class DifferentStreamFieldsTest { .build(); var deser2 = deserialize(builderBytes); - assertEquals(deser2, deser1); + assertEquals(deser1, deser2); builderBytes = SerialObjectBuilder .newBuilder(R.class.getName()) @@ -193,7 +198,7 @@ public class DifferentStreamFieldsTest { .addPrimitiveField("x", int.class, 7) .build(); deser2 = deserialize(builderBytes); - assertEquals(deser2, deser1); + assertEquals(deser1, deser2); builderBytes = SerialObjectBuilder .newBuilder(R.class.getName()) @@ -203,12 +208,12 @@ public class DifferentStreamFieldsTest { .addPrimitiveField("z", int.class, 9) // additional fields .build(); deser2 = deserialize(builderBytes); - assertEquals(deser2, deser1); + assertEquals(deser1, deser2); r = new R(0, 0); OOSBytes = serialize(r); deser1 = deserialize(OOSBytes); - assertEquals(deser1, r); + assertEquals(r, deser1); builderBytes = SerialObjectBuilder .newBuilder(R.class.getName()) @@ -216,13 +221,13 @@ public class DifferentStreamFieldsTest { .addPrimitiveField("x", int.class, 0) .build(); deser2 = deserialize(builderBytes); - assertEquals(deser2, deser1); + assertEquals(deser1, deser2); builderBytes = SerialObjectBuilder .newBuilder(R.class.getName()) // no field values .build(); deser2 = deserialize(builderBytes); - assertEquals(deser2, deser1); + assertEquals(deser1, deser2); } } @@ -234,7 +239,7 @@ public class DifferentStreamFieldsTest { var r = new Str("Hello", "World!"); var deser1 = deserialize(serialize(r)); - assertEquals(deser1, r); + assertEquals(r, deser1); byte[] builderBytes = SerialObjectBuilder .newBuilder(Str.class.getName()) @@ -243,7 +248,7 @@ public class DifferentStreamFieldsTest { .build(); var deser2 = deserialize(builderBytes); - assertEquals(deser2, deser1); + assertEquals(deser1, deser2); builderBytes = SerialObjectBuilder .newBuilder(Str.class.getName()) @@ -254,7 +259,7 @@ public class DifferentStreamFieldsTest { .build(); var deser3 = deserialize(builderBytes); - assertEquals(deser3, deser1); + assertEquals(deser1, deser3); } @Test @@ -264,8 +269,8 @@ public class DifferentStreamFieldsTest { record IntArray(int[]ints, long[]longs) implements Serializable {} IntArray r = new IntArray(new int[]{5, 4, 3, 2, 1}, new long[]{9L}); IntArray deser1 = deserialize(serialize(r)); - assertEquals(deser1.ints(), r.ints()); - assertEquals(deser1.longs(), r.longs()); + Assertions.assertArrayEquals(r.ints(), deser1.ints()); + Assertions.assertArrayEquals(r.longs(), deser1.longs()); byte[] builderBytes = SerialObjectBuilder .newBuilder(IntArray.class.getName()) @@ -274,14 +279,14 @@ public class DifferentStreamFieldsTest { .build(); IntArray deser2 = deserialize(builderBytes); - assertEquals(deser2.ints(), deser1.ints()); - assertEquals(deser2.longs(), deser1.longs()); + Assertions.assertArrayEquals(deser1.ints(), deser2.ints()); + Assertions.assertArrayEquals(deser1.longs(), deser2.longs()); } { record StrArray(String[]stringArray) implements Serializable {} StrArray r = new StrArray(new String[]{"foo", "bar"}); StrArray deser1 = deserialize(serialize(r)); - assertEquals(deser1.stringArray(), r.stringArray()); + Assertions.assertArrayEquals(r.stringArray(), deser1.stringArray()); byte[] builderBytes = SerialObjectBuilder .newBuilder(StrArray.class.getName()) @@ -289,7 +294,7 @@ public class DifferentStreamFieldsTest { .build(); StrArray deser2 = deserialize(builderBytes); - assertEquals(deser2.stringArray(), deser1.stringArray()); + Assertions.assertArrayEquals(deser1.stringArray(), deser2.stringArray()); } } @@ -302,7 +307,7 @@ public class DifferentStreamFieldsTest { var r = new NumberHolder(123); var deser1 = deserialize(serialize(r)); - assertEquals(deser1, r); + assertEquals(r, deser1); byte[] builderBytes = SerialObjectBuilder .newBuilder(NumberHolder.class.getName()) @@ -310,7 +315,7 @@ public class DifferentStreamFieldsTest { .build(); var deser2 = deserialize(builderBytes); - assertEquals(deser2, deser1); + assertEquals(deser1, deser2); } { @@ -318,7 +323,7 @@ public class DifferentStreamFieldsTest { var r = new IntegerHolder(123); var deser1 = deserialize(serialize(r)); - assertEquals(deser1, r); + assertEquals(r, deser1); byte[] builderBytes = SerialObjectBuilder .newBuilder(IntegerHolder.class.getName()) @@ -326,7 +331,7 @@ public class DifferentStreamFieldsTest { .build(); var deser2 = deserialize(builderBytes); - assertEquals(deser2, deser1); + assertEquals(deser1, deser2); } } @@ -338,7 +343,7 @@ public class DifferentStreamFieldsTest { var r = new StringHolder("123"); var deser1 = deserialize(serialize(r)); - assertEquals(deser1, r); + assertEquals(r, deser1); byte[] builderBytes = SerialObjectBuilder .newBuilder(StringHolder.class.getName()) @@ -362,7 +367,7 @@ public class DifferentStreamFieldsTest { var r = new IntHolder(123); var deser1 = deserialize(serialize(r)); - assertEquals(deser1, r); + assertEquals(r, deser1); byte[] builderBytes = SerialObjectBuilder .newBuilder(IntHolder.class.getName()) diff --git a/test/jdk/java/io/Serializable/records/ProhibitedMethods.java b/test/jdk/java/io/Serializable/records/ProhibitedMethods.java index d744e9ddbad..815fbacc0f7 100644 --- a/test/jdk/java/io/Serializable/records/ProhibitedMethods.java +++ b/test/jdk/java/io/Serializable/records/ProhibitedMethods.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, 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,7 @@ * @bug 8246774 * @summary Basic tests for prohibited magic serialization methods * @library /test/lib - * @run testng ProhibitedMethods + * @run junit ProhibitedMethods */ import java.io.ByteArrayInputStream; @@ -49,24 +49,28 @@ import java.math.BigDecimal; import jdk.test.lib.compiler.InMemoryJavaCompiler; import jdk.test.lib.ByteCodeLoader; -import org.testng.Assert; -import org.testng.annotations.BeforeTest; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import static java.lang.System.out; import static java.lang.classfile.ClassFile.ACC_PRIVATE; +import static java.lang.constant.ConstantDescs.CD_Object; import static java.lang.constant.ConstantDescs.CD_String; import static java.lang.constant.ConstantDescs.CD_void; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; -import static org.testng.Assert.expectThrows; -import static org.testng.Assert.fail; + +import org.junit.jupiter.api.Assertions; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; /** * Checks that the various prohibited Serialization magic methods, and * Externalizable methods, are not invoked ( effectively ignored ) for * record objects. */ +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class ProhibitedMethods { public interface ThrowingExternalizable extends Externalizable { @@ -100,7 +104,7 @@ public class ProhibitedMethods { * fail("readObjectNoData should not be invoked"); } * } */ - @BeforeTest + @BeforeAll public void setup() { { byte[] byteCode = InMemoryJavaCompiler.compile("Foo", @@ -165,7 +169,6 @@ public class ProhibitedMethods { } } - @DataProvider(name = "recordInstances") public Object[][] recordInstances() { return new Object[][] { new Object[] { newFoo() }, @@ -177,7 +180,8 @@ public class ProhibitedMethods { }; } - @Test(dataProvider = "recordInstances") + @ParameterizedTest + @MethodSource("recordInstances") public void roundTrip(Object objToSerialize) throws Exception { out.println("\n---"); out.println("serializing : " + objToSerialize); @@ -245,8 +249,8 @@ public class ProhibitedMethods { return cf.transformClass(cf.parse(classBytes), ClassTransform.endHandler(clb -> { clb.withMethodBody(name, desc, ACC_PRIVATE, cob -> { cob.loadConstant(name + " should not be invoked"); - cob.invokestatic(Assert.class.describeConstable().orElseThrow(), "fail", - MethodTypeDesc.of(CD_void, CD_String)); + cob.invokestatic(Assertions.class.describeConstable().orElseThrow(), "fail", + MethodTypeDesc.of(CD_Object, CD_String)); cob.return_(); }); })); @@ -266,37 +270,37 @@ public class ProhibitedMethods { Method m = obj.getClass().getDeclaredMethod("writeObject", ObjectOutputStream.class); assertTrue((m.getModifiers() & Modifier.PRIVATE) != 0); m.setAccessible(true); - ReflectiveOperationException t = expectThrows(ROE, () -> + ReflectiveOperationException t = Assertions.assertThrows(ROE, () -> m.invoke(obj, new ObjectOutputStream(OutputStream.nullOutputStream()))); Throwable assertionError = t.getCause(); out.println("caught expected AssertionError: " + assertionError); assertTrue(assertionError instanceof AssertionError, "Expected AssertionError, got:" + assertionError); - assertEquals(assertionError.getMessage(), "writeObject should not be invoked"); + assertEquals("writeObject should not be invoked", assertionError.getMessage()); } { // readObject Method m = obj.getClass().getDeclaredMethod("readObject", ObjectInputStream.class); assertTrue((m.getModifiers() & Modifier.PRIVATE) != 0); m.setAccessible(true); - ReflectiveOperationException t = expectThrows(ROE, () -> + ReflectiveOperationException t = Assertions.assertThrows(ROE, () -> m.invoke(obj, new ObjectInputStream() { })); Throwable assertionError = t.getCause(); out.println("caught expected AssertionError: " + assertionError); assertTrue(assertionError instanceof AssertionError, "Expected AssertionError, got:" + assertionError); - assertEquals(assertionError.getMessage(), "readObject should not be invoked"); + assertEquals("readObject should not be invoked", assertionError.getMessage()); } { // readObjectNoData Method m = obj.getClass().getDeclaredMethod("readObjectNoData"); assertTrue((m.getModifiers() & Modifier.PRIVATE) != 0); m.setAccessible(true); - ReflectiveOperationException t = expectThrows(ROE, () -> m.invoke(obj)); + ReflectiveOperationException t = Assertions.assertThrows(ROE, () -> m.invoke(obj)); Throwable assertionError = t.getCause(); out.println("caught expected AssertionError: " + assertionError); assertTrue(assertionError instanceof AssertionError, "Expected AssertionError, got:" + assertionError); - assertEquals(assertionError.getMessage(), "readObjectNoData should not be invoked"); + assertEquals("readObjectNoData should not be invoked", assertionError.getMessage()); } } } diff --git a/test/jdk/java/io/Serializable/records/ReadResolveTest.java b/test/jdk/java/io/Serializable/records/ReadResolveTest.java index 04de34781f9..2eb77bbf663 100644 --- a/test/jdk/java/io/Serializable/records/ReadResolveTest.java +++ b/test/jdk/java/io/Serializable/records/ReadResolveTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, 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,7 +25,7 @@ * @test * @bug 8246774 * @summary Basic tests for readResolve - * @run testng ReadResolveTest + * @run junit ReadResolveTest */ import java.io.ByteArrayInputStream; @@ -35,15 +35,19 @@ import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serial; import java.io.Serializable; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import static java.lang.String.format; import static java.lang.System.out; -import static org.testng.Assert.assertEquals; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; /** * Tests records being used as a serial proxy. */ +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class ReadResolveTest { static class C1 implements Serializable { @@ -94,7 +98,6 @@ public class ReadResolveTest { } } - @DataProvider(name = "objectsToSerialize") public Object[][] objectsToSerialize() { return new Object[][] { new Object[] { new C1(3,4) }, @@ -103,13 +106,14 @@ public class ReadResolveTest { }; } - @Test(dataProvider = "objectsToSerialize") + @ParameterizedTest + @MethodSource("objectsToSerialize") public void testSerialize(Object objectToSerialize) throws Exception { out.println("\n---"); out.println("serializing : " + objectToSerialize); Object deserializedObj = serializeDeserialize(objectToSerialize); out.println("deserialized: " + deserializedObj); - assertEquals(deserializedObj, objectToSerialize); + assertEquals(objectToSerialize, deserializedObj); } // -- null replacement @@ -128,7 +132,7 @@ public class ReadResolveTest { out.println("serializing : " + objectToSerialize); Object deserializedObj = serializeDeserialize(objectToSerialize); out.println("deserialized: " + deserializedObj); - assertEquals(deserializedObj, null); + assertEquals(null, deserializedObj); } // --- infra diff --git a/test/jdk/java/io/Serializable/records/RecordClassTest.java b/test/jdk/java/io/Serializable/records/RecordClassTest.java index 401512056e6..ba920ce92e5 100644 --- a/test/jdk/java/io/Serializable/records/RecordClassTest.java +++ b/test/jdk/java/io/Serializable/records/RecordClassTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, 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,7 +25,7 @@ * @test * @bug 8246774 * @summary Basic tests for serializing and deserializing record classes - * @run testng RecordClassTest + * @run junit RecordClassTest */ import java.io.ByteArrayInputStream; @@ -38,15 +38,18 @@ import java.io.ObjectOutput; import java.io.ObjectOutputStream; import java.io.ObjectStreamClass; import java.io.Serializable; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import static java.lang.System.out; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.fail; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.fail; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; /** * Serializes and deserializes record classes. Ensures that the SUID is 0. */ +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class RecordClassTest { record Foo () implements Serializable { } @@ -74,7 +77,6 @@ public class RecordClassTest { record Wubble (Wobble wobble, Wibble wibble, String s) implements ThrowingExternalizable { } - @DataProvider(name = "recordClasses") public Object[][] recordClasses() { return new Object[][] { new Object[] { Foo.class , 0L }, @@ -87,7 +89,8 @@ public class RecordClassTest { } /** Tests that the serialized and deserialized instances are equal. */ - @Test(dataProvider = "recordClasses") + @ParameterizedTest + @MethodSource("recordClasses") public void testClassSerialization(Class recordClass, long unused) throws Exception { @@ -95,21 +98,22 @@ public class RecordClassTest { out.println("serializing : " + recordClass); var deserializedClass = serializeDeserialize(recordClass); out.println("deserialized: " + deserializedClass); - assertEquals(recordClass, deserializedClass); assertEquals(deserializedClass, recordClass); + assertEquals(recordClass, deserializedClass); } /** Tests that the SUID is always 0 unless explicitly declared. */ - @Test(dataProvider = "recordClasses") + @ParameterizedTest + @MethodSource("recordClasses") public void testSerialVersionUID(Class recordClass, long expectedUID) { out.println("\n---"); ObjectStreamClass osc = ObjectStreamClass.lookup(recordClass); out.println("ObjectStreamClass::lookup : " + osc); - assertEquals(osc.getSerialVersionUID(), expectedUID); + assertEquals(expectedUID, osc.getSerialVersionUID()); osc = ObjectStreamClass.lookupAny(recordClass); out.println("ObjectStreamClass::lookupAny: " + osc); - assertEquals(osc.getSerialVersionUID(), expectedUID); + assertEquals(expectedUID, osc.getSerialVersionUID()); } // --- not Serializable @@ -120,7 +124,6 @@ public class RecordClassTest { record NotSerializable3(T t) { } - @DataProvider(name = "notSerRecordClasses") public Object[][] notSerRecordClasses() { return new Object[][] { new Object[] { NotSerializable1.class }, @@ -130,16 +133,17 @@ public class RecordClassTest { } /** Tests that the generated SUID is always 0 for all non-Serializable record classes. */ - @Test(dataProvider = "notSerRecordClasses") + @ParameterizedTest + @MethodSource("notSerRecordClasses") public void testSerialVersionUIDNonSer(Class recordClass) { out.println("\n---"); ObjectStreamClass osc = ObjectStreamClass.lookup(recordClass); out.println("ObjectStreamClass::lookup : " + osc); - assertEquals(osc, null); + assertEquals(null, osc); osc = ObjectStreamClass.lookupAny(recordClass); out.println("ObjectStreamClass::lookupAny: " + osc); - assertEquals(osc.getSerialVersionUID(), 0L); + assertEquals(0L, osc.getSerialVersionUID()); } // --- infra diff --git a/test/jdk/java/io/Serializable/records/SerialPersistentFieldsTest.java b/test/jdk/java/io/Serializable/records/SerialPersistentFieldsTest.java index 16266806850..471e94b6ed7 100644 --- a/test/jdk/java/io/Serializable/records/SerialPersistentFieldsTest.java +++ b/test/jdk/java/io/Serializable/records/SerialPersistentFieldsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, 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,7 @@ * @bug 8246774 * @summary Basic tests for prohibited magic serialPersistentFields * @library /test/lib - * @run testng SerialPersistentFieldsTest + * @run junit SerialPersistentFieldsTest */ import java.io.ByteArrayInputStream; @@ -52,9 +52,6 @@ import java.math.BigDecimal; import jdk.test.lib.ByteCodeLoader; import jdk.test.lib.compiler.InMemoryJavaCompiler; -import org.testng.annotations.BeforeTest; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import static java.lang.System.out; import static java.lang.classfile.ClassFile.ACC_FINAL; import static java.lang.classfile.ClassFile.ACC_PRIVATE; @@ -65,12 +62,18 @@ import static java.lang.constant.ConstantDescs.CD_void; import static java.lang.constant.ConstantDescs.CLASS_INIT_NAME; import static java.lang.constant.ConstantDescs.INIT_NAME; import static java.lang.constant.ConstantDescs.MTD_void; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; /** * Checks that the serialPersistentFields declaration is effectively ignored. */ +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class SerialPersistentFieldsTest { ClassLoader serializableRecordLoader; @@ -88,7 +91,7 @@ public class SerialPersistentFieldsTest { * }; * } */ - @BeforeTest + @BeforeAll public void setup() { { // R1 byte[] byteCode = InMemoryJavaCompiler.compile("R1", @@ -174,7 +177,6 @@ public class SerialPersistentFieldsTest { return newRecord("R5", new Class[]{int.class}, new Object[]{x}); } - @DataProvider(name = "recordInstances") public Object[][] recordInstances() { return new Object[][] { new Object[] { newR1() }, @@ -185,14 +187,15 @@ public class SerialPersistentFieldsTest { }; } - @Test(dataProvider = "recordInstances") + @ParameterizedTest + @MethodSource("recordInstances") public void roundTrip(Object objToSerialize) throws Exception { out.println("\n---"); out.println("serializing : " + objToSerialize); var objDeserialized = serializeDeserialize(objToSerialize); out.println("deserialized: " + objDeserialized); - assertEquals(objToSerialize, objDeserialized); assertEquals(objDeserialized, objToSerialize); + assertEquals(objToSerialize, objDeserialized); } byte[] serialize(T obj) throws IOException { @@ -290,7 +293,8 @@ public class SerialPersistentFieldsTest { // -- infra sanity -- /** Checks to ensure correct operation of the test's generation logic. */ - @Test(dataProvider = "recordInstances") + @ParameterizedTest + @MethodSource("recordInstances") public void wellFormedGeneratedClasses(Object obj) throws Exception { out.println("\n---"); out.println(obj); diff --git a/test/jdk/java/io/Serializable/records/SerialVersionUIDTest.java b/test/jdk/java/io/Serializable/records/SerialVersionUIDTest.java index abc0c63b0f2..2c133392dcb 100644 --- a/test/jdk/java/io/Serializable/records/SerialVersionUIDTest.java +++ b/test/jdk/java/io/Serializable/records/SerialVersionUIDTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, 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,7 +25,7 @@ * @test * @bug 8246774 * @summary Basic tests for SUID in the serial stream - * @run testng SerialVersionUIDTest + * @run junit SerialVersionUIDTest */ import java.io.ByteArrayInputStream; @@ -39,13 +39,16 @@ import java.io.Serializable; import java.util.ArrayList; import java.util.List; import java.util.stream.LongStream; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import static java.io.ObjectStreamConstants.*; import static java.lang.System.out; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class SerialVersionUIDTest { record R1 () implements Serializable { @@ -64,7 +67,6 @@ public class SerialVersionUIDTest { private static final long serialVersionUID = 5678L; } - @DataProvider(name = "recordObjects") public Object[][] recordObjects() { return new Object[][] { new Object[] { new R1(), 1L }, @@ -78,7 +80,8 @@ public class SerialVersionUIDTest { /** * Tests that a declared SUID for a record class is inserted into the stream. */ - @Test(dataProvider = "recordObjects") + @ParameterizedTest + @MethodSource("recordObjects") public void testSerialize(Object objectToSerialize, long expectedUID) throws Exception { @@ -90,17 +93,16 @@ public class SerialVersionUIDTest { DataInputStream dis = new DataInputStream(bais); // sanity - assertEquals(dis.readShort(), STREAM_MAGIC); - assertEquals(dis.readShort(), STREAM_VERSION); - assertEquals(dis.readByte(), TC_OBJECT); - assertEquals(dis.readByte(), TC_CLASSDESC); - assertEquals(dis.readUTF(), objectToSerialize.getClass().getName()); + assertEquals(STREAM_MAGIC, dis.readShort()); + assertEquals(STREAM_VERSION, dis.readShort()); + assertEquals(TC_OBJECT, dis.readByte()); + assertEquals(TC_CLASSDESC, dis.readByte()); + assertEquals(objectToSerialize.getClass().getName(), dis.readUTF()); // verify that the UID is as expected - assertEquals(dis.readLong(), expectedUID); + assertEquals(expectedUID, dis.readLong()); } - @DataProvider(name = "recordClasses") public Object[][] recordClasses() { List list = new ArrayList<>(); List> recordClasses = List.of(R1.class, R2.class, R3.class, R4.class, R5.class); @@ -115,14 +117,15 @@ public class SerialVersionUIDTest { * Tests that matching of the serialVersionUID values ( stream value * and runtime class value ) is waived for record classes. */ - @Test(dataProvider = "recordClasses") + @ParameterizedTest + @MethodSource("recordClasses") public void testSerializeFromClass(Class cl, long suid) throws Exception { out.println("\n---"); byte[] bytes = byteStreamFor(cl.getName(), suid); Object obj = deserialize(bytes); - assertEquals(obj.getClass(), cl); + assertEquals(cl, obj.getClass()); assertTrue(obj.getClass().isRecord()); } diff --git a/test/jdk/java/io/Serializable/records/StreamRefTest.java b/test/jdk/java/io/Serializable/records/StreamRefTest.java index b0c72ec8a96..d0d3e353bdb 100644 --- a/test/jdk/java/io/Serializable/records/StreamRefTest.java +++ b/test/jdk/java/io/Serializable/records/StreamRefTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, 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,7 +25,7 @@ * @test * @bug 8246774 * @summary Tests for stream references - * @run testng StreamRefTest + * @run junit StreamRefTest */ import java.io.ByteArrayInputStream; @@ -36,11 +36,12 @@ import java.io.InvalidObjectException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; -import org.testng.annotations.Test; import static java.lang.System.out; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; -import static org.testng.Assert.expectThrows; + +import org.junit.jupiter.api.Assertions; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.Test; /** * Tests for stream references. @@ -123,14 +124,14 @@ public class StreamRefTest { updateIntValue(3, -3, bytes, 40); var byteStream = new ObjectInputStream(new ByteArrayInputStream(bytes)); - InvalidObjectException ioe = expectThrows(IOE, () -> deserializeOne(byteStream)); + InvalidObjectException ioe = Assertions.assertThrows(IOE, () -> deserializeOne(byteStream)); out.println("caught expected IOE: " + ioe); Throwable t = ioe.getCause(); assertTrue(t instanceof IllegalArgumentException, "Expected IAE, got:" + t); out.println("expected cause IAE: " + t); B b1 = (B)deserializeOne(byteStream); - assertEquals(b1.a, null); + assertEquals(null, b1.a); } @Test @@ -144,14 +145,14 @@ public class StreamRefTest { updateIntValue(3, -3, bytes, 96); var byteStream = new ObjectInputStream(new ByteArrayInputStream(bytes)); - InvalidObjectException ioe = expectThrows(IOE, () -> deserializeOne(byteStream)); + InvalidObjectException ioe = Assertions.assertThrows(IOE, () -> deserializeOne(byteStream)); out.println("caught expected IOE: " + ioe); Throwable t = ioe.getCause(); assertTrue(t instanceof IllegalArgumentException, "Expected IAE, got:" + t); out.println("expected cause IAE: " + t); A a1 = (A)deserializeOne(byteStream); - assertEquals(a1, null); + assertEquals(null, a1); } // --- @@ -211,7 +212,7 @@ public class StreamRefTest { throws IOException { ByteArrayInputStream bais = new ByteArrayInputStream(bytes, offset, 4); DataInputStream dis = new DataInputStream(bais); - assertEquals(dis.readInt(), expectedValue); + assertEquals(expectedValue, dis.readInt()); } static void updateIntValue(int expectedValue, int newValue, byte[] bytes, int offset) diff --git a/test/jdk/java/io/Serializable/records/ThrowingConstructorTest.java b/test/jdk/java/io/Serializable/records/ThrowingConstructorTest.java index 8e43a11a832..ee05930f29e 100644 --- a/test/jdk/java/io/Serializable/records/ThrowingConstructorTest.java +++ b/test/jdk/java/io/Serializable/records/ThrowingConstructorTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, 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,7 +25,7 @@ * @test * @bug 8246774 * @summary Tests constructor invocation exceptions are handled appropriately - * @run testng ThrowingConstructorTest + * @run junit ThrowingConstructorTest */ import java.io.ByteArrayInputStream; @@ -35,17 +35,20 @@ import java.io.InvalidObjectException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import static java.lang.System.out; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; -import static org.testng.Assert.expectThrows; + +import org.junit.jupiter.api.Assertions; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; /** * If the constructor invocation throws an exception, an * `InvalidObjectException` is thrown with that exception as its cause. */ +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class ThrowingConstructorTest { /** "big switch" that can be used to allow/disallow record construction @@ -84,7 +87,6 @@ public class ThrowingConstructorTest { static final Class IOE = InvalidObjectException.class; - @DataProvider(name = "exceptionInstances") public Object[][] exceptionInstances() { Object[][] objs = new Object[][] { new Object[] { new R1(), NullPointerException.class, "thrown from R1" }, @@ -98,7 +100,8 @@ public class ThrowingConstructorTest { return objs; } - @Test(dataProvider = "exceptionInstances") + @ParameterizedTest + @MethodSource("exceptionInstances") public void testExceptions(Object objectToSerialize, Class expectedExType, String expectedExMessage) @@ -107,13 +110,13 @@ public class ThrowingConstructorTest { out.println("\n---"); out.println("serializing: " + objectToSerialize); byte[] bytes = serialize(objectToSerialize); - InvalidObjectException ioe = expectThrows(IOE, () -> deserialize(bytes)); + InvalidObjectException ioe = Assertions.assertThrows(IOE, () -> deserialize(bytes)); out.println("caught expected IOE: " + ioe); Throwable t = ioe.getCause(); assertTrue(t.getClass().equals(expectedExType), "Expected:" + expectedExType + ", got:" + t); out.println("expected cause " + expectedExType +" : " + t); - assertEquals(t.getMessage(), expectedExMessage); + assertEquals(expectedExMessage, t.getMessage()); } // -- errors ( pass through unwrapped ) @@ -143,7 +146,6 @@ public class ThrowingConstructorTest { } } - @DataProvider(name = "errorInstances") public Object[][] errorInstances() { Object[][] objs = new Object[][] { new Object[] { new R4(), OutOfMemoryError.class, "thrown from R4" }, @@ -157,7 +159,8 @@ public class ThrowingConstructorTest { return objs; } - @Test(dataProvider = "errorInstances") + @ParameterizedTest + @MethodSource("errorInstances") public void testErrors(Object objectToSerialize, Class expectedExType, String expectedExMessage) @@ -166,11 +169,11 @@ public class ThrowingConstructorTest { out.println("\n---"); out.println("serializing: " + objectToSerialize); byte[] bytes = serialize(objectToSerialize); - Throwable t = expectThrows(expectedExType, () -> deserialize(bytes)); + Throwable t = Assertions.assertThrows(expectedExType, () -> deserialize(bytes)); assertTrue(t.getClass().equals(expectedExType), "Expected:" + expectedExType + ", got:" + t); out.println("caught expected " + expectedExType +" : " + t); - assertEquals(t.getMessage(), expectedExMessage); + assertEquals(expectedExMessage, t.getMessage()); } // --- infra diff --git a/test/jdk/java/io/Serializable/records/UnsharedTest.java b/test/jdk/java/io/Serializable/records/UnsharedTest.java index c96010c83ab..114e2dc6e10 100644 --- a/test/jdk/java/io/Serializable/records/UnsharedTest.java +++ b/test/jdk/java/io/Serializable/records/UnsharedTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, 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,7 +25,7 @@ * @test * @bug 8238763 8246774 * @summary ObjectInputStream readUnshared method handling of Records - * @run testng UnsharedTest + * @run junit UnsharedTest */ import java.io.ByteArrayInputStream; @@ -35,10 +35,11 @@ import java.io.InvalidObjectException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; -import org.testng.annotations.Test; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; -import static org.testng.Assert.expectThrows; +import org.junit.jupiter.api.Assertions; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.Test; /** * Tests OOS::writeUnshared and OIS::readUnshared to verify that records @@ -56,16 +57,16 @@ public class UnsharedTest { { // shared - sanity to ensure the second foo is a ref var byteStream = serialize(foo, foo); var foo1 = (Foo) deserializeOne(byteStream); - assertEquals(foo1.x, foo.x); + assertEquals(foo.x, foo1.x); var foo2 = (Foo) deserializeOne(byteStream); - assertEquals(foo2.x, foo.x); + assertEquals(foo.x, foo2.x); assertTrue(foo2 == foo1); } { // unshared var byteStream = serialize(foo, foo); var foo1 = (Foo) deserializeOneUnshared(byteStream); - assertEquals(foo1.x, foo.x); - var expected = expectThrows(IOE, () -> deserializeOne(byteStream)); + assertEquals(foo.x, foo1.x); + var expected = Assertions.assertThrows(IOE, () -> deserializeOne(byteStream)); assertTrue(expected.getMessage().contains("cannot read back reference to unshared object")); } } @@ -76,17 +77,17 @@ public class UnsharedTest { { // shared - sanity to ensure the second foo is NOT a ref var byteStream = serializeUnshared(foo, foo); var foo1 = (Foo) deserializeOne(byteStream); - assertEquals(foo1.x, foo.x); + assertEquals(foo.x, foo1.x); var foo2 = (Foo) deserializeOne(byteStream); - assertEquals(foo2.x, foo.x); + assertEquals(foo.x, foo2.x); assertTrue(foo2 != foo1); } { // unshared var byteStream = serializeUnshared(foo, foo); var foo1 = (Foo) deserializeOneUnshared(byteStream); - assertEquals(foo1.x, foo.x); + assertEquals(foo.x, foo1.x); var foo2 = (Foo) deserializeOneUnshared(byteStream); - assertEquals(foo2.x, foo.x); + assertEquals(foo.x, foo2.x); assertTrue(foo2 != foo1); } } diff --git a/test/jdk/java/io/Serializable/records/WriteReplaceTest.java b/test/jdk/java/io/Serializable/records/WriteReplaceTest.java index c64d6355dd2..2e253c166a0 100644 --- a/test/jdk/java/io/Serializable/records/WriteReplaceTest.java +++ b/test/jdk/java/io/Serializable/records/WriteReplaceTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, 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,7 +25,7 @@ * @test * @bug 8246774 * @summary Basic tests for writeReplace - * @run testng WriteReplaceTest + * @run junit WriteReplaceTest */ import java.io.ByteArrayInputStream; @@ -34,11 +34,15 @@ import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import static java.lang.System.out; -import static org.testng.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class WriteReplaceTest { record R1 () implements Serializable { @@ -71,7 +75,6 @@ public class WriteReplaceTest { } } - @DataProvider(name = "recordObjects") public Object[][] recordObjects() { return new Object[][] { new Object[] { new R1(), R1.class }, @@ -81,7 +84,8 @@ public class WriteReplaceTest { }; } - @Test(dataProvider = "recordObjects") + @ParameterizedTest + @MethodSource("recordObjects") public void testSerialize(Object objectToSerialize, Class expectedType) throws Exception { @@ -90,9 +94,9 @@ public class WriteReplaceTest { Object deserializedObj = serializeDeserialize(objectToSerialize); out.println("deserialized: " + deserializedObj); if (objectToSerialize.getClass().equals(expectedType)) - assertEquals(deserializedObj, objectToSerialize); + assertEquals(objectToSerialize, deserializedObj); else - assertEquals(deserializedObj.getClass(), expectedType); + assertEquals(expectedType, deserializedObj.getClass()); } // -- null replacement @@ -108,7 +112,7 @@ public class WriteReplaceTest { out.println("serializing : " + objectToSerialize); Object deserializedObj = serializeDeserialize(objectToSerialize); out.println("deserialized: " + deserializedObj); - assertEquals(deserializedObj, null); + assertEquals(null, deserializedObj); } // --- infra diff --git a/test/jdk/java/io/Serializable/records/migration/AbstractTest.java b/test/jdk/java/io/Serializable/records/migration/AbstractTest.java index e0bbc574500..488f4a33acd 100644 --- a/test/jdk/java/io/Serializable/records/migration/AbstractTest.java +++ b/test/jdk/java/io/Serializable/records/migration/AbstractTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, 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,8 +34,9 @@ import java.net.URL; import java.net.URLClassLoader; import java.nio.file.Path; import jdk.test.lib.compiler.CompilerUtils; -import org.testng.annotations.BeforeTest; -import static org.testng.Assert.*; + +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.BeforeAll; /** * An abstract superclass for tests that require to serialize and deserialize @@ -54,7 +55,7 @@ public class AbstractTest { static final Path RECORD_SRC_DIR = Path.of(TEST_SRC, "record"); static final Path RECORD_DEST_DIR = Path.of("record"); - @BeforeTest + @BeforeAll public void setup() throws IOException { assertTrue(CompilerUtils.compile(PLAIN_SRC_DIR, PLAIN_DEST_DIR, "--class-path", TEST_CLASSES_DIR.toString())); diff --git a/test/jdk/java/io/Serializable/records/migration/AssignableFromTest.java b/test/jdk/java/io/Serializable/records/migration/AssignableFromTest.java index 6097e2477df..117a8474c67 100644 --- a/test/jdk/java/io/Serializable/records/migration/AssignableFromTest.java +++ b/test/jdk/java/io/Serializable/records/migration/AssignableFromTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, 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,24 +29,26 @@ * @modules jdk.compiler * @compile AssignableFrom.java Point.java * DefaultValues.java SuperStreamFields.java - * @run testng AssignableFromTest + * @run junit AssignableFromTest */ import java.math.BigDecimal; import java.math.BigInteger; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import static java.lang.System.out; -import static org.testng.Assert.assertEquals; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; /** * Basic test to check that stream field values that are not the exact * declared param/field type, but assignable to a declared supertype, * are bound/assigned correctly. */ +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class AssignableFromTest extends AbstractTest { - @DataProvider(name = "plainInstances") public Object[][] plainInstances() { return new Object[][] { new Object[] { newPlainAssignableFrom(Byte.valueOf((byte)11)) }, @@ -59,7 +61,8 @@ public class AssignableFromTest extends AbstractTest { } /** Serialize non-record (plain) instances, deserialize as a record. */ - @Test(dataProvider = "plainInstances") + @ParameterizedTest + @MethodSource("plainInstances") public void testPlainToRecord(AssignableFrom objToSerialize) throws Exception { assert !objToSerialize.getClass().isRecord(); out.println("serialize : " + objToSerialize); @@ -68,13 +71,12 @@ public class AssignableFromTest extends AbstractTest { assert objDeserialized.getClass().isRecord(); out.println("deserialized: " + objDeserialized); - assertEquals(objToSerialize.number(), objDeserialized.number()); assertEquals(objDeserialized.number(), objToSerialize.number()); + assertEquals(objToSerialize.number(), objDeserialized.number()); assertEquals(objDeserialized.number().getClass(), objDeserialized.number().getClass()); } - @DataProvider(name = "recordInstances") public Object[][] recordInstances() { return new Object[][] { new Object[] { newRecordAssignableFrom(Byte.valueOf((byte)21)) }, @@ -87,7 +89,8 @@ public class AssignableFromTest extends AbstractTest { } /** Serialize record instances, deserialize as non-record (plain). */ - @Test(dataProvider = "recordInstances") + @ParameterizedTest + @MethodSource("recordInstances") public void testRecordToPlain(AssignableFrom objToSerialize) throws Exception { assert objToSerialize.getClass().isRecord(); out.println("serialize : " + objToSerialize); @@ -96,8 +99,8 @@ public class AssignableFromTest extends AbstractTest { assert !objDeserialized.getClass().isRecord(); out.println("deserialized: " + objDeserialized); - assertEquals(objToSerialize.number(), objDeserialized.number()); assertEquals(objDeserialized.number(), objToSerialize.number()); + assertEquals(objToSerialize.number(), objDeserialized.number()); assertEquals(objDeserialized.number().getClass(), objDeserialized.number().getClass()); } diff --git a/test/jdk/java/io/Serializable/records/migration/DefaultValuesTest.java b/test/jdk/java/io/Serializable/records/migration/DefaultValuesTest.java index 4af684156c6..357c9400777 100644 --- a/test/jdk/java/io/Serializable/records/migration/DefaultValuesTest.java +++ b/test/jdk/java/io/Serializable/records/migration/DefaultValuesTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, 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,21 +28,24 @@ * @library /test/lib * @modules jdk.compiler * @compile AssignableFrom.java Point.java DefaultValues.java SuperStreamFields.java - * @run testng DefaultValuesTest + * @run junit DefaultValuesTest */ import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; -import org.testng.annotations.Test; import static java.io.ObjectStreamConstants.*; import static java.lang.System.out; -import static org.testng.Assert.*; + +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; /** * Basic test to check that default primitive / reference values are * presented to the record's canonical constructor, for fields not in * the stream. */ +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class DefaultValuesTest extends AbstractTest { /** @@ -77,13 +80,13 @@ public class DefaultValuesTest extends AbstractTest { Point point = deserializeAsPlain(bytes); out.println("deserialized: " + point); - assertEquals(point.x(), 0); - assertEquals(point.y(), 0); + assertEquals(0, point.x()); + assertEquals(0, point.y()); point = deserializeAsRecord(bytes); out.println("deserialized: " + point); - assertEquals(point.x(), 0); - assertEquals(point.y(), 0); + assertEquals(0, point.x()); + assertEquals(0, point.y()); } // --- @@ -115,8 +118,8 @@ public class DefaultValuesTest extends AbstractTest { DefaultValues o1 = deserializeAsRecord(bytes); out.println("deserialized: " + o1); - assertEquals(o1.point().x(), point.x()); // sanity - assertEquals(o1.point().y(), point.y()); // sanity + assertEquals(point.x(), o1.point().x()); // sanity + assertEquals(point.y(), o1.point().y()); // sanity assertTrue(o1.bool() == Defaults.bool); assertTrue(o1.by() == Defaults.by); assertTrue(o1.ch() == Defaults.ch); diff --git a/test/jdk/java/io/Serializable/records/migration/SuperStreamFieldsTest.java b/test/jdk/java/io/Serializable/records/migration/SuperStreamFieldsTest.java index 6090d71003e..35e75341dbf 100644 --- a/test/jdk/java/io/Serializable/records/migration/SuperStreamFieldsTest.java +++ b/test/jdk/java/io/Serializable/records/migration/SuperStreamFieldsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, 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,20 +28,23 @@ * @library /test/lib * @modules jdk.compiler * @compile AssignableFrom.java Point.java DefaultValues.java SuperStreamFields.java - * @run testng SuperStreamFieldsTest + * @run junit SuperStreamFieldsTest */ -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import static java.lang.System.out; -import static org.testng.Assert.assertEquals; + +import org.junit.jupiter.api.Assertions; +import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; /** * Tests that superclass fields in the stream are discarded. */ +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class SuperStreamFieldsTest extends AbstractTest { - @DataProvider(name = "plainInstances") public Object[][] plainInstances() { return new Object[][] { new Object[] { newPlainSuperStreamFields("cat", new int[] { 1 }, 1) }, @@ -51,7 +54,8 @@ public class SuperStreamFieldsTest extends AbstractTest { } /** Serializes non-record (plain) instance, deserializes as a record. */ - @Test(dataProvider = "plainInstances") + @ParameterizedTest + @MethodSource("plainInstances") public void testPlainToRecord(SuperStreamFields objToSerialize) throws Exception { assert !objToSerialize.getClass().isRecord(); out.println("serialize : " + objToSerialize); @@ -60,12 +64,11 @@ public class SuperStreamFieldsTest extends AbstractTest { assert objDeserialized.getClass().isRecord(); out.println("deserialized: " + objDeserialized); - assertEquals(objToSerialize.str(), objDeserialized.str()); - assertEquals(objToSerialize.x(), objDeserialized.x()); - assertEquals(objToSerialize.y(), objDeserialized.y()); + assertEquals(objDeserialized.str(), objToSerialize.str()); + Assertions.assertArrayEquals(objDeserialized.x(), objToSerialize.x()); + assertEquals(objDeserialized.y(), objToSerialize.y()); } - @DataProvider(name = "recordInstances") public Object[][] recordInstances() { return new Object[][] { new Object[] { newRecordSuperStreamFields("goat", new int[] { 56 }, 66) }, @@ -75,7 +78,8 @@ public class SuperStreamFieldsTest extends AbstractTest { } /** Serializes record instance, deserializes as non-record (plain). */ - @Test(dataProvider = "recordInstances") + @ParameterizedTest + @MethodSource("recordInstances") public void testRecordToPlain(SuperStreamFields objToSerialize) throws Exception { assert objToSerialize.getClass().isRecord(); out.println("serialize : " + objToSerialize); @@ -84,9 +88,9 @@ public class SuperStreamFieldsTest extends AbstractTest { assert !objDeserialized.getClass().isRecord(); out.println("deserialized: " + objDeserialized); - assertEquals(objToSerialize.str(), objDeserialized.str()); - assertEquals(objToSerialize.x(), objDeserialized.x()); - assertEquals(objToSerialize.y(), objDeserialized.y()); + assertEquals(objDeserialized.str(), objToSerialize.str()); + Assertions.assertArrayEquals(objDeserialized.x(), objToSerialize.x()); + assertEquals(objDeserialized.y(), objToSerialize.y()); } From d02abfe765a1e67c5e37f3450aa5a0d8fb97a208 Mon Sep 17 00:00:00 2001 From: Khalid Boulanouare Date: Tue, 16 Dec 2025 20:37:57 +0000 Subject: [PATCH 322/706] 8158801: [TEST_BUG] Mixing tests fail because of focus workaround trick Reviewed-by: aivanov, prr, psadhukhan --- test/jdk/ProblemList.txt | 29 +------- .../GlassPaneOverlappingTestBase.java | 69 +++++++++---------- .../AWT_Mixing/JComboBoxOverlapping.java | 4 +- .../JInternalFrameMoveOverlapping.java | 4 +- .../AWT_Mixing/JInternalFrameOverlapping.java | 3 +- .../AWT_Mixing/JMenuBarOverlapping.java | 7 +- .../AWT_Mixing/JPopupMenuOverlapping.java | 6 +- .../AWT_Mixing/JScrollPaneOverlapping.java | 3 +- .../AWT_Mixing/JSplitPaneOverlapping.java | 3 +- .../AWT_Mixing/MixingFrameResizing.java | 5 +- .../AWT_Mixing/MixingPanelsResizing.java | 27 ++++++-- .../Mixing/AWT_Mixing/OpaqueOverlapping.java | 7 +- .../AWT_Mixing/OverlappingTestBase.java | 13 +++- .../AWT_Mixing/SimpleOverlappingTestBase.java | 59 +++++++++++----- 14 files changed, 132 insertions(+), 107 deletions(-) diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 974e719c1c9..a81e48f3883 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -152,7 +152,6 @@ java/awt/event/InputEvent/EventWhenTest/EventWhenTest.java 8168646 generic-all java/awt/List/KeyEventsTest/KeyEventsTest.java 8201307 linux-all java/awt/List/NoEvents/ProgrammaticChange.java 8201307 linux-all java/awt/Paint/ListRepaint.java 8201307 linux-all -java/awt/Mixing/AWT_Mixing/HierarchyBoundsListenerMixingTest.java 8049405 macosx-all java/awt/Mixing/AWT_Mixing/OpaqueOverlapping.java 8370584 windows-x64 java/awt/Mixing/AWT_Mixing/OpaqueOverlappingChoice.java 8048171 generic-all java/awt/Mixing/AWT_Mixing/JMenuBarOverlapping.java 8159451 linux-all,windows-all,macosx-all @@ -161,33 +160,7 @@ java/awt/Mixing/AWT_Mixing/JInternalFrameMoveOverlapping.java 6986109 windows-al java/awt/Mixing/AWT_Mixing/MixingPanelsResizing.java 8049405 generic-all java/awt/Mixing/AWT_Mixing/JComboBoxOverlapping.java 8049405 macosx-all java/awt/Mixing/AWT_Mixing/JPopupMenuOverlapping.java 8049405 macosx-all -java/awt/Mixing/AWT_Mixing/JButtonInGlassPaneOverlapping.java 8158801 windows-all -java/awt/Mixing/AWT_Mixing/JButtonOverlapping.java 8158801 windows-all -java/awt/Mixing/AWT_Mixing/JColorChooserOverlapping.java 8158801 windows-all -java/awt/Mixing/AWT_Mixing/JEditorPaneInGlassPaneOverlapping.java 8158801 windows-all -java/awt/Mixing/AWT_Mixing/JEditorPaneOverlapping.java 8158801 windows-all -java/awt/Mixing/AWT_Mixing/JLabelInGlassPaneOverlapping.java 8158801 windows-all -java/awt/Mixing/AWT_Mixing/JLabelOverlapping.java 8158801 windows-all -java/awt/Mixing/AWT_Mixing/JListInGlassPaneOverlapping.java 8158801 windows-all -java/awt/Mixing/AWT_Mixing/JListOverlapping.java 8158801 windows-all -java/awt/Mixing/AWT_Mixing/JPanelInGlassPaneOverlapping.java 8158801 windows-all -java/awt/Mixing/AWT_Mixing/JPanelOverlapping.java 8158801 windows-all -java/awt/Mixing/AWT_Mixing/JProgressBarInGlassPaneOverlapping.java 8158801 windows-all -java/awt/Mixing/AWT_Mixing/JProgressBarOverlapping.java 8158801 windows-all -java/awt/Mixing/AWT_Mixing/JScrollBarInGlassPaneOverlapping.java 8158801 windows-all -java/awt/Mixing/AWT_Mixing/JScrollBarOverlapping.java 8158801 windows-all -java/awt/Mixing/AWT_Mixing/JSliderInGlassPaneOverlapping.java 8158801 windows-all -java/awt/Mixing/AWT_Mixing/JSliderOverlapping.java 8158801 windows-all -java/awt/Mixing/AWT_Mixing/JSpinnerInGlassPaneOverlapping.java 8158801 windows-all -java/awt/Mixing/AWT_Mixing/JSpinnerOverlapping.java 8158801 windows-all -java/awt/Mixing/AWT_Mixing/JTableInGlassPaneOverlapping.java 8158801,8357360 windows-all,linux-all -java/awt/Mixing/AWT_Mixing/JTableOverlapping.java 8158801 windows-all -java/awt/Mixing/AWT_Mixing/JTextAreaInGlassPaneOverlapping.java 8158801 windows-all -java/awt/Mixing/AWT_Mixing/JTextAreaOverlapping.java 8158801 windows-all -java/awt/Mixing/AWT_Mixing/JTextFieldInGlassPaneOverlapping.java 8158801 windows-all -java/awt/Mixing/AWT_Mixing/JTextFieldOverlapping.java 8158801 windows-all -java/awt/Mixing/AWT_Mixing/JToggleButtonInGlassPaneOverlapping.java 8158801 windows-all -java/awt/Mixing/AWT_Mixing/JToggleButtonOverlapping.java 8158801 windows-all +java/awt/Mixing/AWT_Mixing/JTableInGlassPaneOverlapping.java 8357360 windows-all,linux-all java/awt/Mixing/NonOpaqueInternalFrame.java 7124549 macosx-all java/awt/Focus/ActualFocusedWindowTest/ActualFocusedWindowRetaining.java 6829264 generic-all java/awt/datatransfer/DragImage/MultiResolutionDragImageTest.java 8080982 generic-all diff --git a/test/jdk/java/awt/Mixing/AWT_Mixing/GlassPaneOverlappingTestBase.java b/test/jdk/java/awt/Mixing/AWT_Mixing/GlassPaneOverlappingTestBase.java index f67e71b1b19..f5dd838eff2 100644 --- a/test/jdk/java/awt/Mixing/AWT_Mixing/GlassPaneOverlappingTestBase.java +++ b/test/jdk/java/awt/Mixing/AWT_Mixing/GlassPaneOverlappingTestBase.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, 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,12 +25,11 @@ import java.awt.Container; import java.awt.Point; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; -import java.awt.event.InputEvent; import java.lang.reflect.InvocationTargetException; + import javax.swing.JFrame; import javax.swing.SpringLayout; import javax.swing.SwingUtilities; -import test.java.awt.regtesthelpers.Util; /** * Base class for testing overlapping of Swing and AWT component put into GlassPane. @@ -46,7 +45,6 @@ public abstract class GlassPaneOverlappingTestBase extends SimpleOverlappingTest */ protected boolean testResize = true; private JFrame f = null; - private volatile Point ancestorLoc; /** * Setups GlassPane with lightweight component returned by {@link SimpleOverlappingTestBase#getSwingComponent() } @@ -83,6 +81,7 @@ public abstract class GlassPaneOverlappingTestBase extends SimpleOverlappingTest testedComponent.setBounds(0, 0, testedComponent.getPreferredSize().width, testedComponent.getPreferredSize().height); glassPane.add(testedComponent); + f.setLocationRelativeTo(null); f.setVisible(true); } @@ -94,6 +93,11 @@ public abstract class GlassPaneOverlappingTestBase extends SimpleOverlappingTest super(defaultClickValidation); } + @Override + protected final boolean isMultiFramesTest() { + return false; + } + /** * Run test by {@link OverlappingTestBase#clickAndBlink(java.awt.Robot, java.awt.Point) } validation for current lightweight component. *

      Also resize component and repeat validation in the resized area. @@ -106,40 +110,33 @@ public abstract class GlassPaneOverlappingTestBase extends SimpleOverlappingTest if (!super.performTest()) { return false; } - if (testResize) { - wasLWClicked = false; - try { - SwingUtilities.invokeAndWait(new Runnable() { - public void run() { - testedComponent.setBounds(0, 0, testedComponent.getPreferredSize().width, testedComponent.getPreferredSize().height + 20); - ancestorLoc = f.getLocationOnScreen(); - } - }); - } catch (InterruptedException ex) { - fail(ex.getMessage()); - } catch (InvocationTargetException ex) { - fail(ex.getMessage()); - } - Point lLoc = testedComponent.getLocationOnScreen(); - lLoc.translate(1, testedComponent.getPreferredSize().height + 1); - - /* this is a workaround for certain jtreg(?) focus issue: - tests fail starting after failing mixing tests but always pass alone. - */ - Util.waitForIdle(robot); - ancestorLoc.translate(isOel7orLater() ? 5 : f.getWidth() / 2 - 15, 2); - robot.mouseMove(ancestorLoc.x, ancestorLoc.y); - Util.waitForIdle(robot); - robot.mousePress(InputEvent.BUTTON1_MASK); - robot.delay(50); - robot.mouseRelease(InputEvent.BUTTON1_MASK); - Util.waitForIdle(robot); - - clickAndBlink(robot, lLoc); - return wasLWClicked; - } else { + if (!testResize) { return true; } + + wasLWClicked = false; + try { + SwingUtilities.invokeAndWait(new Runnable() { + + public void run() { + testedComponent.setBounds(0, 0, + testedComponent.getPreferredSize().width, + testedComponent.getPreferredSize().height + 20); + } + }); + } catch (InterruptedException | InvocationTargetException ex) { + fail(ex.getMessage()); + } + Point lLoc = testedComponent.getLocationOnScreen(); + lLoc.translate(1, testedComponent.getPreferredSize().height + 1); + clickAndBlink(robot, lLoc); + + return wasLWClicked; + } + + @Override + protected void cleanup() { + f.dispose(); } } diff --git a/test/jdk/java/awt/Mixing/AWT_Mixing/JComboBoxOverlapping.java b/test/jdk/java/awt/Mixing/AWT_Mixing/JComboBoxOverlapping.java index cc02e9afbeb..d71fa7b3522 100644 --- a/test/jdk/java/awt/Mixing/AWT_Mixing/JComboBoxOverlapping.java +++ b/test/jdk/java/awt/Mixing/AWT_Mixing/JComboBoxOverlapping.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, 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,7 +64,6 @@ public class JComboBoxOverlapping extends OverlappingTestBase { frame = new JFrame("Mixing : Dropdown Overlapping test"); frame.getContentPane().setLayout(new BoxLayout(frame.getContentPane(), BoxLayout.Y_AXIS)); frame.setSize(200, 200); - frame.setVisible(true); cb = new JComboBox(petStrings); cb.setPreferredSize(new Dimension(frame.getContentPane().getWidth(), 20)); @@ -79,6 +78,7 @@ public class JComboBoxOverlapping extends OverlappingTestBase { frame.add(cb); propagateAWTControls(frame); + frame.setLocationRelativeTo(null); frame.setVisible(true); } diff --git a/test/jdk/java/awt/Mixing/AWT_Mixing/JInternalFrameMoveOverlapping.java b/test/jdk/java/awt/Mixing/AWT_Mixing/JInternalFrameMoveOverlapping.java index 443ff70727d..6f27aba85da 100644 --- a/test/jdk/java/awt/Mixing/AWT_Mixing/JInternalFrameMoveOverlapping.java +++ b/test/jdk/java/awt/Mixing/AWT_Mixing/JInternalFrameMoveOverlapping.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, 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,6 @@ import test.java.awt.regtesthelpers.Util; /** * AWT/Swing overlapping test for {@link javax.swing.JInternalFrame } component during move. - *

      See CR6768230 for details and base class for test info. */ /* * @test @@ -117,6 +116,7 @@ public class JInternalFrameMoveOverlapping extends OverlappingTestBase { JFrame frame = new JFrame("Test Window"); frame.setSize(300, 300); frame.setContentPane(desktopPane); + frame.setLocationRelativeTo(null); frame.setVisible(true); locTopFrame = topFrame.getLocationOnScreen(); diff --git a/test/jdk/java/awt/Mixing/AWT_Mixing/JInternalFrameOverlapping.java b/test/jdk/java/awt/Mixing/AWT_Mixing/JInternalFrameOverlapping.java index 4cb9425abe7..8d619e34c35 100644 --- a/test/jdk/java/awt/Mixing/AWT_Mixing/JInternalFrameOverlapping.java +++ b/test/jdk/java/awt/Mixing/AWT_Mixing/JInternalFrameOverlapping.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, 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 @@ -75,6 +75,7 @@ public class JInternalFrameOverlapping extends OverlappingTestBase { JFrame frame = new JFrame("Test Window"); frame.setSize(300, 300); frame.setContentPane(desktopPane); + frame.setLocationRelativeTo(null); frame.setVisible(true); JInternalFrame bottomFrame = new JInternalFrame("bottom frame", false, false, false, false); bottomFrame.setSize(220, 220); diff --git a/test/jdk/java/awt/Mixing/AWT_Mixing/JMenuBarOverlapping.java b/test/jdk/java/awt/Mixing/AWT_Mixing/JMenuBarOverlapping.java index 792831c2d8d..f3a213e5144 100644 --- a/test/jdk/java/awt/Mixing/AWT_Mixing/JMenuBarOverlapping.java +++ b/test/jdk/java/awt/Mixing/AWT_Mixing/JMenuBarOverlapping.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, 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,6 @@ */ -import java.awt.Color; import java.awt.GridLayout; import java.awt.Point; import java.awt.Robot; @@ -30,12 +29,14 @@ import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; + import javax.swing.JFrame; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JSeparator; import javax.swing.SwingUtilities; + import test.java.awt.regtesthelpers.Util; /** @@ -72,7 +73,6 @@ public class JMenuBarOverlapping extends OverlappingTestBase { frame = new JFrame("Mixing : Dropdown Overlapping test"); frame.setLayout(new GridLayout(0,1)); frame.setSize(200, 200); - frame.setVisible(true); menuBar = new JMenuBar(); JMenu menu = new JMenu("Test Menu"); @@ -104,6 +104,7 @@ public class JMenuBarOverlapping extends OverlappingTestBase { frame.setJMenuBar(menuBar); propagateAWTControls(frame); + frame.setLocationRelativeTo(null); frame.setVisible(true); } diff --git a/test/jdk/java/awt/Mixing/AWT_Mixing/JPopupMenuOverlapping.java b/test/jdk/java/awt/Mixing/AWT_Mixing/JPopupMenuOverlapping.java index d4b50287dc6..e80475088ac 100644 --- a/test/jdk/java/awt/Mixing/AWT_Mixing/JPopupMenuOverlapping.java +++ b/test/jdk/java/awt/Mixing/AWT_Mixing/JPopupMenuOverlapping.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, 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,17 +22,18 @@ */ -import java.awt.Color; import java.awt.Point; import java.awt.Robot; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.lang.reflect.InvocationTargetException; + import javax.swing.JFrame; import javax.swing.JMenuItem; import javax.swing.JPopupMenu; import javax.swing.SpringLayout; import javax.swing.SwingUtilities; + import test.java.awt.regtesthelpers.Util; /** @@ -82,6 +83,7 @@ public class JPopupMenuOverlapping extends OverlappingTestBase { item.addActionListener(menuListener); } propagateAWTControls(frame); + frame.setLocationRelativeTo(null); frame.setVisible(true); loc = frame.getContentPane().getLocationOnScreen(); } diff --git a/test/jdk/java/awt/Mixing/AWT_Mixing/JScrollPaneOverlapping.java b/test/jdk/java/awt/Mixing/AWT_Mixing/JScrollPaneOverlapping.java index f22eacba82d..91538b75c13 100644 --- a/test/jdk/java/awt/Mixing/AWT_Mixing/JScrollPaneOverlapping.java +++ b/test/jdk/java/awt/Mixing/AWT_Mixing/JScrollPaneOverlapping.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, 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 @@ -95,6 +95,7 @@ public class JScrollPaneOverlapping extends OverlappingTestBase { }); f.getContentPane().add(scrollPane); + f.setLocationRelativeTo(null); f.setVisible(true); propagateAWTControls(p); // JButton b = new JButton("Space extender"); diff --git a/test/jdk/java/awt/Mixing/AWT_Mixing/JSplitPaneOverlapping.java b/test/jdk/java/awt/Mixing/AWT_Mixing/JSplitPaneOverlapping.java index 7e1cb9434e4..5875a04b62b 100644 --- a/test/jdk/java/awt/Mixing/AWT_Mixing/JSplitPaneOverlapping.java +++ b/test/jdk/java/awt/Mixing/AWT_Mixing/JSplitPaneOverlapping.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, 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 @@ -89,6 +89,7 @@ public class JSplitPaneOverlapping extends OverlappingTestBase { frame.getContentPane().add(splitPane); frame.pack(); + frame.setLocationRelativeTo(null); frame.setVisible(true); } diff --git a/test/jdk/java/awt/Mixing/AWT_Mixing/MixingFrameResizing.java b/test/jdk/java/awt/Mixing/AWT_Mixing/MixingFrameResizing.java index 545566970f8..8c19a80bd43 100644 --- a/test/jdk/java/awt/Mixing/AWT_Mixing/MixingFrameResizing.java +++ b/test/jdk/java/awt/Mixing/AWT_Mixing/MixingFrameResizing.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, 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,9 +26,11 @@ import java.awt.Dimension; import java.awt.Point; import java.awt.Robot; import java.awt.event.InputEvent; + import javax.swing.JFrame; import javax.swing.SpringLayout; import javax.swing.SwingUtilities; + import test.java.awt.regtesthelpers.Util; /** @@ -65,6 +67,7 @@ public class MixingFrameResizing extends OverlappingTestBase { frame = new JFrame("Mixing : Frame Resizing test"); frame.setLayout(new SpringLayout()); frame.setSize(50, 50); + frame.setLocationRelativeTo(null); frame.setVisible(true); propagateAWTControls(frame); Util.waitTillShown(frame); diff --git a/test/jdk/java/awt/Mixing/AWT_Mixing/MixingPanelsResizing.java b/test/jdk/java/awt/Mixing/AWT_Mixing/MixingPanelsResizing.java index 39a59dc2a5c..1bb9b442dd8 100644 --- a/test/jdk/java/awt/Mixing/AWT_Mixing/MixingPanelsResizing.java +++ b/test/jdk/java/awt/Mixing/AWT_Mixing/MixingPanelsResizing.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, 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,10 +22,23 @@ */ -import java.awt.*; +import java.awt.BorderLayout; +import java.awt.Button; +import java.awt.Color; +import java.awt.Panel; +import java.awt.Point; +import java.awt.Robot; +import java.awt.Toolkit; import java.awt.event.InputEvent; -import javax.swing.*; -import java.io.*; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; + +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.SwingUtilities; + import test.java.awt.regtesthelpers.Util; /** @@ -130,6 +143,7 @@ public class MixingPanelsResizing { frame.add(jPanel, BorderLayout.NORTH); frame.pack(); + frame.setLocationRelativeTo(null); frame.setVisible(true); } }); @@ -298,6 +312,7 @@ public class MixingPanelsResizing { failureMessage = whyFailed; mainThread.interrupt(); }//fail() + + static class TestPassedException extends RuntimeException { + } }// class JButtonInGlassPane -class TestPassedException extends RuntimeException { -} diff --git a/test/jdk/java/awt/Mixing/AWT_Mixing/OpaqueOverlapping.java b/test/jdk/java/awt/Mixing/AWT_Mixing/OpaqueOverlapping.java index 4975cc165c2..03abb58f673 100644 --- a/test/jdk/java/awt/Mixing/AWT_Mixing/OpaqueOverlapping.java +++ b/test/jdk/java/awt/Mixing/AWT_Mixing/OpaqueOverlapping.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, 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 @@ -56,13 +56,13 @@ public class OpaqueOverlapping extends OverlappingTestBase { { useClickValidation = false; - failMessage = "Opacity test mismatchs"; + failMessage = "Opacity test mismatches"; // CR 6994264 (Choice autohides dropdown on Solaris 10) skipClassNames = new String[] { "Choice" }; } private String testSeq; - private final static String checkSeq = "010000101"; + private static final String checkSeq = "010000101"; private Point heavyLoc; private JButton light; private Frame frame = null; @@ -89,6 +89,7 @@ public class OpaqueOverlapping extends OverlappingTestBase { panel.add(light); frame.add(panel); frame.setBounds(50, 50, 400, 400); + frame.setLocationRelativeTo(null); frame.setVisible(true); currentAwtControl.addMouseListener(new MouseAdapter() { diff --git a/test/jdk/java/awt/Mixing/AWT_Mixing/OverlappingTestBase.java b/test/jdk/java/awt/Mixing/AWT_Mixing/OverlappingTestBase.java index 794578a5907..3d4adecbd17 100644 --- a/test/jdk/java/awt/Mixing/AWT_Mixing/OverlappingTestBase.java +++ b/test/jdk/java/awt/Mixing/AWT_Mixing/OverlappingTestBase.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, 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.awt.Robot; import java.awt.Scrollbar; import java.awt.TextField; import java.awt.Toolkit; +import java.awt.Window; import java.awt.event.InputEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; @@ -171,6 +172,7 @@ public abstract class OverlappingTestBase { frame.getContentPane().setBackground(AWT_BACKGROUND_COLOR); frame.setSize(size, size); frame.setUndecorated(true); + frame.setLocationRelativeTo(null); frame.setVisible(true); frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); p[0] = frame.getLocation(); @@ -259,6 +261,9 @@ public abstract class OverlappingTestBase { embedder.setBackground(Color.RED); embedder.setPreferredSize(new Dimension(150, 150)); container.add(embedder); + if (container instanceof Window) { + ((Window) container).setLocationRelativeTo(null); + } container.setVisible(true); // create peer long frameWindow = 0; @@ -301,6 +306,7 @@ public abstract class OverlappingTestBase { EmbeddedFrame eframe = (EmbeddedFrame) eframeCtor.newInstance(frameWindow); setupControl(eframe); eframe.setSize(new Dimension(150, 150)); + eframe.setLocationRelativeTo(null); eframe.setVisible(true); // System.err.println(eframe.getSize()); } catch (Exception ex) { @@ -682,6 +688,7 @@ public abstract class OverlappingTestBase { failureMessage = whyFailed; mainThread.interrupt(); }//fail() + + static class TestPassedException extends RuntimeException { + } }// class LWComboBox -class TestPassedException extends RuntimeException { -} diff --git a/test/jdk/java/awt/Mixing/AWT_Mixing/SimpleOverlappingTestBase.java b/test/jdk/java/awt/Mixing/AWT_Mixing/SimpleOverlappingTestBase.java index 928a5c437cb..0dd42a36cd0 100644 --- a/test/jdk/java/awt/Mixing/AWT_Mixing/SimpleOverlappingTestBase.java +++ b/test/jdk/java/awt/Mixing/AWT_Mixing/SimpleOverlappingTestBase.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, 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 @@ -21,10 +21,21 @@ * questions. */ -import java.awt.*; -import java.awt.event.*; -import java.util.regex.*; -import javax.swing.*; +import java.awt.Point; +import java.awt.Robot; +import java.awt.event.FocusAdapter; +import java.awt.event.FocusEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.swing.JComponent; +import javax.swing.JFrame; +import javax.swing.SpringLayout; + import test.java.awt.regtesthelpers.Util; /** @@ -55,6 +66,10 @@ public abstract class SimpleOverlappingTestBase extends OverlappingTestBase { this.useDefaultClickValidation = defaultClickValidation; } + protected boolean isMultiFramesTest(){ + return true; + } + public SimpleOverlappingTestBase() { this(true); } @@ -114,6 +129,7 @@ public abstract class SimpleOverlappingTestBase extends OverlappingTestBase { propagateAWTControls(f); + f.setLocationRelativeTo(null); f.setVisible(true); } @@ -140,21 +156,29 @@ public abstract class SimpleOverlappingTestBase extends OverlappingTestBase { /* this is a workaround for certain jtreg(?) focus issue: tests fail starting after failing mixing tests but always pass alone. */ - JFrame ancestor = (JFrame)(testedComponent.getTopLevelAncestor()); - if( ancestor != null ) { - Point ancestorLoc = ancestor.getLocationOnScreen(); - ancestorLoc.translate(isOel7orLater() ? 5 : - ancestor.getWidth() / 2 - 15, 2); - robot.mouseMove(ancestorLoc.x, ancestorLoc.y); - Util.waitForIdle(robot); - robot.mousePress(InputEvent.BUTTON1_MASK); - robot.delay(50); - robot.mouseRelease(InputEvent.BUTTON1_MASK); - Util.waitForIdle(robot); + JFrame ancestor = (JFrame) (testedComponent.getTopLevelAncestor()); + if (ancestor != null) { + final CountDownLatch latch = new CountDownLatch(1); + ancestor.addFocusListener(new FocusAdapter() { + @Override public void focusGained(FocusEvent e) { + latch.countDown(); + } + }); + ancestor.requestFocus(); + try { + if (!latch.await(1L, TimeUnit.SECONDS)) { + throw new RuntimeException( + "Ancestor frame didn't receive focus"); + } + } catch (InterruptedException e) { + throw new RuntimeException(e); + } } clickAndBlink(robot, lLoc); - Util.waitForIdle(robot); + if (ancestor != null && isMultiFramesTest()) { + ancestor.dispose(); + } return wasLWClicked; } @@ -172,5 +196,4 @@ public abstract class SimpleOverlappingTestBase extends OverlappingTestBase { } return false; } - } From fb99ba6ccd6e6d7a0e717a1b9f2a80402af5c661 Mon Sep 17 00:00:00 2001 From: Damon Nguyen Date: Tue, 16 Dec 2025 21:19:33 +0000 Subject: [PATCH 323/706] 8373119: JDK 26 RDP1 L10n resource files update Reviewed-by: jlu, asemenyuk, almatvee --- .../launcher/resources/launcher_de.properties | 5 +- .../launcher/resources/launcher_ja.properties | 6 +- .../resources/launcher_zh_CN.properties | 8 +- .../keytool/resources/keytool_de.properties | 2 +- .../keytool/resources/keytool_ja.properties | 2 +- .../resources/keytool_zh_CN.properties | 2 +- .../util/resources/security_de.properties | 5 +- .../util/resources/security_ja.properties | 3 + .../util/resources/security_zh_CN.properties | 3 + .../javac/resources/compiler_de.properties | 69 ++++--- .../javac/resources/compiler_ja.properties | 69 ++++--- .../javac/resources/compiler_zh_CN.properties | 69 ++++--- .../tools/javac/resources/javac_de.properties | 24 ++- .../tools/javac/resources/javac_ja.properties | 26 +-- .../javac/resources/javac_zh_CN.properties | 26 +-- .../javac/resources/launcher_de.properties | 3 + .../javac/resources/launcher_ja.properties | 3 + .../javac/resources/launcher_zh_CN.properties | 3 + .../resources/jarsigner_de.properties | 1 + .../resources/jarsigner_ja.properties | 1 + .../resources/jarsigner_zh_CN.properties | 1 + .../sun/tools/jar/resources/jar_de.properties | 2 + .../sun/tools/jar/resources/jar_ja.properties | 2 + .../tools/jar/resources/jar_zh_CN.properties | 2 + .../html/resources/standard_de.properties | 6 + .../html/resources/standard_ja.properties | 6 + .../html/resources/standard_zh_CN.properties | 6 + .../toolkit/resources/doclets_de.properties | 8 +- .../toolkit/resources/doclets_ja.properties | 4 + .../resources/doclets_zh_CN.properties | 4 + .../tool/resources/javadoc_de.properties | 2 +- .../tools/jlink/resources/jlink_de.properties | 3 +- .../tools/jlink/resources/jlink_ja.properties | 3 +- .../jlink/resources/jlink_zh_CN.properties | 3 +- .../jlink/resources/plugins_de.properties | 12 +- .../jlink/resources/plugins_ja.properties | 12 +- .../jlink/resources/plugins_zh_CN.properties | 12 +- .../resources/LinuxResources_de.properties | 6 - .../resources/LinuxResources_ja.properties | 6 - .../resources/LinuxResources_zh_CN.properties | 6 - .../resources/MacResources_de.properties | 31 ++- .../resources/MacResources_ja.properties | 31 ++- .../resources/MacResources_zh_CN.properties | 33 ++-- .../resources/HelpResources_de.properties | 176 +++++++++++++++-- .../resources/HelpResources_ja.properties | 179 ++++++++++++++++-- .../resources/HelpResources_zh_CN.properties | 177 +++++++++++++++-- .../resources/MainResources_de.properties | 106 ++++++----- .../resources/MainResources_ja.properties | 106 ++++++----- .../resources/MainResources_zh_CN.properties | 106 ++++++----- .../resources/WinResources_de.properties | 8 - .../resources/WinResources_ja.properties | 8 - .../resources/WinResources_zh_CN.properties | 8 - 52 files changed, 976 insertions(+), 429 deletions(-) diff --git a/src/java.base/share/classes/sun/launcher/resources/launcher_de.properties b/src/java.base/share/classes/sun/launcher/resources/launcher_de.properties index 79b5968b210..e80869b868c 100644 --- a/src/java.base/share/classes/sun/launcher/resources/launcher_de.properties +++ b/src/java.base/share/classes/sun/launcher/resources/launcher_de.properties @@ -30,8 +30,8 @@ java.launcher.opt.vmselect =\ {0}\t zur Auswahl der "{1}" VM\n java.launcher.opt.hotspot =\ {0}\t ist ein Synonym für die "{1}" VM [verworfen]\n # Translators please note do not translate the options themselves -java.launcher.opt.footer = \ -cp \n -classpath \n --class-path \n Eine durch "{0}" getrennte Liste mit Verzeichnissen, JAR-Archiven\n und ZIP-Archiven, in denen nach Klassendateien gesucht wird.\n -p \n --module-path ...\n Eine durch "{0}" getrennte Liste mit Elementen, von denen jedes Element ein Dateipfad ist\n zu einem Modul oder einem Verzeichnis mit Modulen ist. Jedes Modul ist entweder\n ein modulares JAR oder ein entpacktes Modulverzeichnis.\n --upgrade-module-path ...\n Eine durch "{0}" getrennte Liste mit Elementen, von denen jedes Element ein Dateipfad ist\n zu einem Modul oder einem Verzeichnis mit Modulen ist,\n um upgradefähige Module im Laufzeitimage zu ersetzen. Jedes Modul ist entweder\n ein modulares JAR oder ein entpacktes Modulverzeichnis.\n --add-modules [,...]\n Root-Module, die zusätzlich zum anfänglichen Modul aufgelöst werden sollen.\n kann auch wie folgt lauten: ALL-DEFAULT, ALL-SYSTEM,\n ALL-MODULE-PATH.\n --enable-native-access [,...]\n Damit kann der Code in Modulen auf Code und Daten außerhalb der JRE zugreifen.\n kann auch ALL-UNNAMED sein, um den Code im Classpath anzugeben.\n --illegal-native-access=\n Zugriff auf Code und Daten außerhalb der JRE\n durch Code in Modulen zulassen oder verweigern, für die der native Zugriff nicht explizit aktiviert ist.\n ist "deny", "warn" oder "allow". Der Standardwert ist "warn".\n Diese Option wird in einem zukünftigen Release entfernt.\n --list-modules\n Listet beobachtbare Module auf und beendet den Vorgang\n -d \n --describe-module \n Beschreibt ein Modul und beendet den Vorgang\n --dry-run Erstellt eine VM und lädt die Hauptklasse, führt aber nicht die Hauptmethode aus.\n Die Option "--dry-run" kann nützlich sein, um die\n Befehlszeilenoptionen, wie die Modulsystemkonfiguration, zu validieren.\n --validate-modules\n Validiert alle Module und beendet den Vorgang\n Die Option "--validate-modules" kann nützlich sein, um\n Konflikte und andere Fehler mit Modulen auf dem Modulpfad zu ermitteln.\n -D=\n Legt eine Systemeigenschaft fest\n -verbose:[class|module|gc|jni]\n Aktiviert die Verbose-Ausgabe für das angegebene Subsystem\n -version Gibt die Produktversion an den Fehlerstream aus und beendet den Vorgang\n --version Gibt die Produktversion an den Outputstream aus und beendet den Vorgang\n -showversion Gibt die Produktversion an den Fehlerstream aus und setzt den Vorgang fort\n --show-version\n Gibt die Produktversion an den Outputstream aus und setzt den Vorgang fort\n --show-module-resolution\n Zeigt die Modulauflösungsausgabe beim Start an\n -? -h -help\n Gibt diese Hilfemeldung an den Fehlerstream aus\n --help Gibt diese Hilfemeldung an den Outputstream aus\n -X Gibt Hilfe zu zusätzlichen Optionen an den Fehlerstream aus\n --help-extra Gibt Hilfe zu zusätzlichen Optionen an den Outputstream aus\n -ea[:...|:]\n -enableassertions[:...|:]\n Aktiviert Assertions mit angegebener \ -Granularität\n -da[:...|:]\n -disableassertions[:...|:]\n Deaktiviert Assertions mit angegebener Granularität\n -esa | -enablesystemassertions\n Aktiviert System-Assertions\n -dsa | -disablesystemassertions\n Deaktiviert System-Assertions\n -agentlib:[=]\n Lädt die native Agent Library . Beispiel: -agentlib:jdwp\n siehe auch -agentlib:jdwp=help\n -agentpath:[=]\n Lädt die native Agent Library mit dem vollständigen Pfadnamen\n -javaagent:[=]\n Lädt den Java-Programmiersprachen-Agent, siehe java.lang.instrument\n -splash:\n Zeigt den Startbildschirm mit einem angegebenen Bild an\n Skalierte HiDPI-Bilder werden automatisch unterstützt und verwendet,\n falls verfügbar. Der nicht skalierte Bilddateiname (Beispiel: image.ext)\n muss immer als Argument an die Option "-splash" übergeben werden.\n Das am besten geeignete angegebene skalierte Bild wird\n automatisch ausgewählt.\n Weitere Informationen finden Sie in der Dokumentation zur SplashScreen-API\n @argument files\n Eine oder mehrere Argumentdateien mit Optionen\n --disable-@files\n Verhindert die weitere Erweiterung von Argumentdateien\n --enable-preview\n Lässt zu, das Klassen von Vorschaufeatures dieses Release abhängig sind\nUm ein Argument für eine lange Option anzugeben, können Sie --= oder\n-- verwenden.\n +java.launcher.opt.footer = \ -cp \n -classpath \n --class-path \n Eine durch "{0}" getrennte Liste mit Verzeichnissen, JAR-Archiven\n und ZIP-Archiven, in denen nach Klassendateien gesucht wird.\n -p \n --module-path ...\n Eine durch "{0}" getrennte Liste mit Elementen, von denen jedes Element ein Dateipfad ist\n zu einem Modul oder einem Verzeichnis mit Modulen ist. Jedes Modul ist entweder\n ein modulares JAR oder ein entpacktes Modulverzeichnis.\n --upgrade-module-path ...\n Eine durch "{0}" getrennte Liste mit Elementen, von denen jedes Element ein Dateipfad ist\n zu einem Modul oder einem Verzeichnis mit Modulen ist,\n um upgradefähige Module im Laufzeitimage zu ersetzen. Jedes Modul ist entweder\n ein modulares JAR oder ein entpacktes Modulverzeichnis.\n --add-modules [,...]\n Root-Module, die zusätzlich zum anfänglichen Modul aufgelöst werden sollen.\n kann auch wie folgt lauten: ALL-DEFAULT, ALL-SYSTEM,\n ALL-MODULE-PATH.\n --enable-native-access [,...]\n Damit kann der Code in Modulen auf Code und Daten außerhalb der JRE zugreifen.\n kann auch ALL-UNNAMED sein, um den Code im Classpath anzugeben.\n --illegal-native-access=\n Zugriff auf Code und Daten außerhalb der JRE\n durch Code in Modulen zulassen oder verweigern, für die der native Zugriff nicht explizit aktiviert ist.\n ist "deny", "warn" oder "allow". Der Standardwert ist "warn".\n Diese Option wird in einem zukünftigen Release entfernt.\n --enable-final-field-mutation [,...]\n Zulassen, dass die endgültigen Instanzfelder durch Code in den angegebenen Modulen mutiert werden.\n kann auch ALL-UNNAMED sein, um den Code im Classpath anzugeben.\n --illegal-final-field-mutation=\n Erlauben oder verweigern Sie die Mutation von endgültigen Feldern durch Code in Modulen, für die die Mutation\n von endgültigen Feldern nicht explizit aktiviert ist.\n ist "deny", "warn", "debug" oder "allow". Der Standardwert ist "warn".\n Diese Option wird in einem zukünftigen Release entfernt.\n --list-modules\n Listet beobachtbare Module auf und beendet den Vorgang\n -d \n --describe-module \n Beschreibt ein Modul und beendet den Vorgang\n --dry-run Erstellt eine VM und lädt die Hauptklasse, führt aber nicht die Hauptmethode aus.\n Die Option "--dry-run" kann nützlich sein, um die\n Befehlszeilenoptionen, wie die Modulsystemkonfiguration, zu validieren.\n --validate-modules\n Validiert alle Module und beendet den Vorgang\n Die Option "--validate-modules" kann nützlich sein, um\n Konflikte und andere Fehler mit Modulen auf dem Modulpfad zu ermitteln.\n -D=\n Legt eine Systemeigenschaft fest\n -verbose:[class|module|gc|jni]\n Aktiviert die Verbose-Ausgabe für das angegebene Subsystem\n -version Gibt die Produktversion an den Fehlerstream aus und beendet den Vorgang\n --version Gibt die Produktversion an den Outputstream aus und beendet den Vorgang\n -showversion Gibt die Produktversion an den Fehlerstream aus und \ +setzt den Vorgang fort\n --show-version\n Gibt die Produktversion an den Outputstream aus und setzt den Vorgang fort\n --show-module-resolution\n Zeigt die Modulauflösungsausgabe beim Start an\n -? -h -help\n Gibt diese Hilfemeldung an den Fehlerstream aus\n --help Gibt diese Hilfemeldung an den Outputstream aus\n -X Gibt Hilfe zu zusätzlichen Optionen an den Fehlerstream aus\n --help-extra Gibt Hilfe zu zusätzlichen Optionen an den Outputstream aus\n -ea[:...|:]\n -enableassertions[:...|:]\n Aktiviert Assertions mit angegebener Granularität\n -da[:...|:]\n -disableassertions[:...|:]\n Deaktiviert Assertions mit angegebener Granularität\n -esa | -enablesystemassertions\n Aktiviert System-Assertions\n -dsa | -disablesystemassertions\n Deaktiviert System-Assertions\n -agentlib:[=]\n Lädt die native Agent Library . Beispiel: -agentlib:jdwp\n siehe auch -agentlib:jdwp=help\n -agentpath:[=]\n Lädt die native Agent Library mit dem vollständigen Pfadnamen\n -javaagent:[=]\n Lädt den Java-Programmiersprachen-Agent, siehe java.lang.instrument\n -splash:\n Zeigt den Startbildschirm mit einem angegebenen Bild an\n Skalierte HiDPI-Bilder werden automatisch unterstützt und verwendet,\n falls verfügbar. Der nicht skalierte Bilddateiname (Beispiel: image.ext)\n muss immer als Argument an die Option "-splash" übergeben werden.\n Das am besten geeignete angegebene skalierte Bild wird\n automatisch ausgewählt.\n Weitere Informationen finden Sie in der Dokumentation zur SplashScreen-API\n @argument files\n Eine oder mehrere Argumentdateien mit Optionen\n --disable-@files\n Verhindert die weitere Erweiterung von Argumentdateien\n --enable-preview\n Lässt zu, das Klassen von Vorschaufeatures dieses Release abhängig sind\nUm ein Argument für eine lange Option anzugeben, können Sie --= oder\n-- verwenden.\n # Translators please note do not translate the options themselves java.launcher.X.usage=\n -Xbatch Deaktiviert die Hintergrundkompilierung\n -Xbootclasspath/a:\n An das Ende des Bootstrap Classpaths anhängen\n -Xcheck:jni Führt zusätzliche Prüfungen für JNI-Funktionen aus\n -Xcomp Erzwingt die Kompilierung von Methoden beim ersten Aufruf\n -Xdebug Führt keine Aktion aus. Ist veraltet und wird in einem zukünftigen Release entfernt.\n -Xdiag Zeigt zusätzliche Diagnosemeldungen an\n -Xint Nur Ausführung im interpretierten Modus\n -Xinternalversion\n Zeigt detailliertere JVM-Versionsinformationen an als die\n Option -version\n -Xlog: Konfiguriert oder aktiviert Logging mit dem einheitlichen Java Virtual\n Machine-(JVM-)Logging-Framework. Verwenden Sie -Xlog:help\n für weitere Einzelheiten.\n -Xloggc: Protokolliert den GC-Status in einer Datei mit Zeitstempeln.\n Diese Option ist veraltet und kann in einem\n zukünftigen Release entfernt werden. Wird durch -Xlog:gc: ersetzt.\n -Xmixed Ausführung im gemischten Modus (Standard)\n -Xmn Legt die anfängliche und maximale Größe (in Byte) des Heaps\n für die Young Generation (Nursery) fest\n -Xms Legt die minimale und die anfängliche Java-Heap-Größe fest\n -Xmx Legt die maximale Java-Heap-Größe fest\n -Xnoclassgc Deaktiviert die Klassen-Garbage Collection\n -Xrs Reduziert die Verwendung von BS-Signalen durch Java/VM (siehe Dokumentation)\n -Xshare:auto Verwendet freigegebene Klassendaten, wenn möglich (Standard)\n -Xshare:off Versucht nicht, freigegebene Klassendaten zu verwenden\n -Xshare:on Erfordert die Verwendung freigegebener Klassendaten, verläuft sonst nicht erfolgreich.\n Diese Testoption kann zeitweise zu\n Fehlern führen. Sie darf nicht in Produktionsumgebungen verwendet werden.\n -XshowSettings Zeigt alle Einstellungen an und fährt fort\n -XshowSettings:all\n Zeigt alle Einstellungen als Verbose-Ausgabe an und fährt fort\n -XshowSettings:locale\n Zeigt alle gebietsschemabezogenen Einstellungen an und fährt fort\n -XshowSettings:properties\n Zeigt alle Eigenschaftseinstellungen an und fährt fort\n -XshowSettings:vm\n Zeigt alle VM-bezogenen Einstellungen an und fährt fort\n -XshowSettings:security\n Zeigt alle Sicherheitseinstellungen an und fährt fort\n -XshowSettings:security:all\n Zeigt alle Sicherheitseinstellungen an und fährt fort\n -XshowSettings:security:properties\n Zeigt Sicherheitseigenschaften an und fährt fort\n -XshowSettings:security:providers\n Zeigt statische Sicherheitsprovidereinstellungen an und fährt fort\n -XshowSettings:security:tls\n Zeigt TLS-bezogene Sicherheitseinstellungen an und fährt fort\n -XshowSettings:system\n (Nur Linux) Zeigt die Konfiguration des Hostsystems oder Containers an\n und fährt fort\n -Xss Legt die Stackgröße des Java-Threads fest\n Die tatsächliche Größe kann auf ein Vielfaches der\n Systemseitengröße aufgerundet werden, wenn für das Betriebssystem erforderlich.\n -Xverify Legt den Modus der Bytecodeverifizierung fest\n \ @@ -58,6 +58,7 @@ java.launcher.jar.error3=kein Hauptmanifestattribut, in {0} java.launcher.jar.error4=Fehler beim Laden des Java-Agents in {0} java.launcher.jar.error5=Fehler: Beim Versuch, Datei {0} zu schließen, ist ein unerwarteter Fehler aufgetreten java.launcher.jar.error.illegal.ena.value=Fehler: Ungültiger Wert "{0}" für das Manifestattribut "Enable-Native-Access". Nur ''ALL-UNNAMED'' ist zulässig +java.launcher.jar.error.illegal.effm.value=Fehler: Ungültiger Wert "{0}" für das Manifestattribut "Enable-Final-Field-Mutation". Nur "ALL-UNNAMED" ist zulässig java.launcher.init.error=Initialisierungsfehler java.launcher.javafx.error1=Fehler: Die JavaFX-Methode launchApplication hat die falsche Signatur, sie\nmuss als statisch deklariert werden und einen Wert vom Typ VOID zurückgeben java.launcher.module.error1=Modul {0} weist kein ModuleMainClass-Attribut auf. Verwenden Sie -m / diff --git a/src/java.base/share/classes/sun/launcher/resources/launcher_ja.properties b/src/java.base/share/classes/sun/launcher/resources/launcher_ja.properties index 04b68db3a8e..49712b21c52 100644 --- a/src/java.base/share/classes/sun/launcher/resources/launcher_ja.properties +++ b/src/java.base/share/classes/sun/launcher/resources/launcher_ja.properties @@ -31,8 +31,9 @@ java.launcher.opt.hotspot =\ {0}\t は"{1}" VMのシノニムです [非 # Translators please note do not translate the options themselves java.launcher.opt.footer = \ -cp <ディレクトリおよびzip/jarファイルのクラス検索パス>\n -classpath <ディレクトリおよびzip/jarファイルのクラス検索パス>\n --class-path <ディレクトリおよびzip/jarファイルのクラス検索パス>\n "{0}"区切りリスト(ディレクトリ、JARアーカイブ、\n ZIPアーカイブ)で、クラス・ファイルの検索用。\n -p \n --module-path ...\n 要素を"{0}"で区切ったリストで、各要素は次へのファイル・パスです:\n モジュール、またはモジュールが格納されているディレクトリ。各モジュールは次のいずれかです:\n モジュラJARまたは展開形式のモジュール・ディレクトリ。\n --upgrade-module-path ...\n 要素を"{0}"で区切ったリストで、各要素は次へのファイル・パスです:\n モジュール、またはモジュールが格納されているディレクトリで、次のものを置き換えます:\n ランタイム・イメージのアップグレード可能なモジュール。各モジュールは次のいずれかです:\n モジュラJARまたは展開形式のモジュール・ディレクトリ。\n --add-modules [,...]\n 初期モジュールに加えて解決するルート・モジュール。\n には次も指定できます: ALL-DEFAULT、ALL-SYSTEM、\n ALL-MODULE-PATH.\n --enable-native-access [,...]\n モジュール内のコードをJavaランタイムの外のコードおよびデータにアクセスさせることができます。\n は、クラス・パス上のコードを指定するためにALL-UNNAMEDにもできます。\n --illegal-native-access=\n Javaランタイムの外のコードおよびデータへのアクセスを許可または拒否します\n (ネイティブ・アクセスが明示的に有効化されていないモジュール内のコードによる)。\n \ -は、"deny"、"warn"または"allow"のいずれかです。デフォルト値は"warn"です。\n このオプションは、将来のリリースで削除される予定です。\n --list-modules\n 参照可能なモジュールをリストし終了します\n -d \n --describe-module \n モジュールを説明し終了します\n --dry-run VMを作成しメイン・クラスをロードしますが、メイン・メソッドは実行しません。\n --dry-runオプションは、次の検証に役立つ場合があります:\n モジュール・システム構成などのコマンド行オプション。\n --validate-modules\n すべてのモジュールを検証し終了します\n --validate-modulesオプションは、次の検索に役立つ場合があります:\n モジュール・パス上のモジュールでの競合およびその他のエラー。\n -D=\n システム・プロパティを設定します\n -verbose:[class|module|gc|jni]\n 特定のサブシステムで詳細出力を有効にする\n -version 製品バージョンをエラー・ストリームに出力して終了します\n --version 製品バージョンを出力ストリームに出力して終了します\n -showversion 製品バージョンをエラー・ストリームに出力して続行します\n --show-version\n 製品バージョンを出力ストリームに出力して続行します\n --show-module-resolution\n 起動時にモジュール解決出力を表示します\n -? -h -help\n このヘルプ・メッセージをエラー・ストリームに出力します\n --help このヘルプ・メッセージを出力ストリームに出力します\n -X 追加オプションのヘルプをエラー・ストリームに出力します\n --help-extra 追加オプションのヘルプを出力ストリームに出力します\n -ea[:...|:]\n -enableassertions[:...|:]\n 指定した粒度でアサーションを有効にします\n -da[:...|:]\n \ --disableassertions[:...|:]\n 指定した粒度でアサーションを無効にします\n -esa | -enablesystemassertions\n システム・アサーションを有効にします\n -dsa | -disablesystemassertions\n システム・アサーションを無効にします\n -agentlib:[=]\n ネイティブ・エージェント・ライブラリをロードします。例: -agentlib:jdwp\n -agentlib:jdwp=helpも参照してください\n -agentpath:[=]\n フルパス名を使用して、ネイティブ・エージェント・ライブラリをロードします\n -javaagent:[=]\n Javaプログラミング言語エージェントをロードします。java.lang.instrumentを参照してください\n -splash:\n 指定されたイメージを含むスプラッシュ画面を表示します\n HiDPIスケールのイメージが自動的にサポートされて使用されます\n (可能な場合)。スケーリングされないイメージのファイル名(image.extなど)を\n 引数として-splashオプションに必ず渡す必要があります。\n 指定された最も適切なスケーリング済イメージが選択されます\n (自動的)。\n 詳細は、SplashScreen APIのドキュメントを参照してください\n @argumentファイル\n オプションを含む1つ以上の引数ファイル\n --disable-@files\n さらなる引数ファイル拡張を無効にします\n --enable-preview\n クラスをこのリリースのプレビュー機能に依存させることができます\n長いオプションの引数を指定する場合、--=または\n-- を使用できます。\n +は、"deny"、"warn"または"allow"のいずれかです。デフォルト値は"warn"です。\n このオプションは、将来のリリースで削除される予定です。\n --enable-final-field-mutation [,...]\n 指定されたモジュールのコードで、finalインスタンス・フィールドを変更できます。\n は、クラス・パス上のコードを指定するためにALL-UNNAMEDにもできます。\n --illegal-final-field-mutation=\n finalのモジュール内のコードによるfinalフィールド変更を許可または拒否します\n フィールド変更は明示的に有効化されていません。\n は、"deny"、"warn"、"debug"または"allow"のいずれかです。デフォルト値は"warn"です。\n このオプションは、将来のリリースで削除される予定です。\n --list-modules\n 参照可能なモジュールをリストし終了します\n -d \n --describe-module \n モジュールを説明し終了します\n --dry-run VMを作成しメイン・クラスをロードしますが、メイン・メソッドは実行しません。\n --dry-runオプションは、次の検証に役立つ場合があります:\n モジュール・システム構成などのコマンド行オプション。\n --validate-modules\n すべてのモジュールを検証し終了します\n --validate-modulesオプションは、次の検索に役立つ場合があります:\n モジュール・パス上のモジュールでの競合およびその他のエラー。\n -D=\n システム・プロパティを設定します\n -verbose:[class|module|gc|jni]\n 特定のサブシステムで詳細出力を有効にする\n -version 製品バージョンをエラー・ストリームに出力して終了します\n --version 製品バージョンを出力ストリームに出力して終了します\n -showversion 製品バージョンをエラー・ストリームに出力して続行します\n --show-version\n \ + 製品バージョンを出力ストリームに出力して続行します\n --show-module-resolution\n 起動時にモジュール解決出力を表示します\n -? -h -help\n このヘルプ・メッセージをエラー・ストリームに出力します\n --help このヘルプ・メッセージを出力ストリームに出力します\n -X 追加オプションのヘルプをエラー・ストリームに出力します\n --help-extra 追加オプションのヘルプを出力ストリームに出力します\n -ea[:...|:]\n -enableassertions[:...|:]\n 指定した粒度でアサーションを有効にします\n -da[:...|:]\n -disableassertions[:...|:]\n 指定した粒度でアサーションを無効にします\n -esa | -enablesystemassertions\n システム・アサーションを有効にします\n -dsa | -disablesystemassertions\n システム・アサーションを無効にします\n -agentlib:[=]\n ネイティブ・エージェント・ライブラリをロードします。例: -agentlib:jdwp\n -agentlib:jdwp=helpも参照してください\n -agentpath:[=]\n フルパス名を使用して、ネイティブ・エージェント・ライブラリをロードします\n -javaagent:[=]\n Javaプログラミング言語エージェントをロードします。java.lang.instrumentを参照してください\n -splash:\n 指定されたイメージを含むスプラッシュ画面を表示します\n HiDPIスケールのイメージが自動的にサポートされて使用されます\n (可能な場合)。スケーリングされないイメージのファイル名(image.extなど)を\n 引数として-splashオプションに必ず渡す必要があります。\n 指定された最も適切なスケーリング済イメージが選択されます\n (自動的)。\n 詳細は、SplashScreen APIのドキュメントを参照してください\n @argumentファイル\n \ +オプションを含む1つ以上の引数ファイル\n --disable-@files\n さらなる引数ファイル拡張を無効にします\n --enable-preview\n クラスをこのリリースのプレビュー機能に依存させることができます\n長いオプションの引数を指定する場合、--=または\n-- を使用できます。\n # Translators please note do not translate the options themselves java.launcher.X.usage=\n -Xbatch バックグラウンド・コンパイルを無効にします\n -Xbootclasspath/a:\n ブートストラップ・クラス・パスの最後に追加します\n -Xcheck:jni JNI関数に対する追加のチェックを実行します\n -Xcomp 初回呼出し時にメソッドのコンパイルを強制します\n -Xdebug 何も実行されません。将来のリリースで削除されるため、非推奨になりました。\n -Xdiag 追加の診断メッセージを表示します\n -Xint インタプリタ・モードの実行のみ\n -Xinternalversion\n -versionオプションより詳細なJVMバージョン情報を\n 表示します\n -Xlog: Java Virtual Machine (JVM)統合ロギング・フレームワークでの\n ロギングを構成または有効化します。詳細は、-Xlog:helpを\n 使用してください。\n -Xloggc: タイムスタンプが付いたファイルにGCステータスのログを記録します\n このオプションは非推奨であり、将来のリリースで削除される\n 可能性があります。-Xlog:gc:で置換されています。\n -Xmixed 混合モードの実行(デフォルト)\n -Xmn 若い世代(ナーサリ)のヒープの初期サイズおよび最大サイズ\n (バイト単位)を設定します\n -Xms Javaの最小および初期のヒープ・サイズを設定します\n -Xmx Javaの最大ヒープ・サイズを設定します\n -Xnoclassgc クラスのガベージ・コレクションを無効にします\n -Xrs Java/VMによるOSシグナルの使用を削減します(ドキュメントを参照)\n -Xshare:auto 可能であれば共有クラス・データを使用します(デフォルト)\n -Xshare:off 共有クラス・データの使用を試みません\n -Xshare:on 共有クラス・データの使用を必須にし、できなければ失敗します。\n \ @@ -60,6 +61,7 @@ java.launcher.jar.error3={0}にメイン・マニフェスト属性がありま java.launcher.jar.error4={0}内のJavaエージェントのロード中にエラーが発生しました java.launcher.jar.error5=エラー: ファイル{0}を閉じるときに、予期しないエラーが発生しました java.launcher.jar.error.illegal.ena.value=エラー: Enable-Native-Accessマニフェスト属性の値"{0}"が不正です。''ALL-UNNAMED''のみ許可されます +java.launcher.jar.error.illegal.effm.value=エラー: Enable-Final-Field-Mutationマニフェスト属性の値"{0}"が不正です。''ALL-UNNAMED''のみ許可されます java.launcher.init.error=初期化エラー java.launcher.javafx.error1=エラー: JavaFX launchApplicationメソッドに誤ったシグネチャがあり、\nstaticを宣言してvoid型の値を返す必要があります java.launcher.module.error1=モジュール{0}にModuleMainClass属性がありません。-m /を使用してください diff --git a/src/java.base/share/classes/sun/launcher/resources/launcher_zh_CN.properties b/src/java.base/share/classes/sun/launcher/resources/launcher_zh_CN.properties index ec466bf3019..b3c0268f953 100644 --- a/src/java.base/share/classes/sun/launcher/resources/launcher_zh_CN.properties +++ b/src/java.base/share/classes/sun/launcher/resources/launcher_zh_CN.properties @@ -30,8 +30,9 @@ java.launcher.opt.vmselect =\ {0}\t 选择 "{1}" VM\n java.launcher.opt.hotspot =\ {0}\t 是 "{1}" VM 的同义词 [已过时]\n # Translators please note do not translate the options themselves -java.launcher.opt.footer = \ -cp <目录和 zip/jar 文件的类搜索路径>\n -classpath <目录和 zip/jar 文件的类搜索路径>\n --class-path <目录和 zip/jar 文件的类搜索路径>\n 以 "{0}" 分隔的用于搜索类文件的目录、JAR 档案\n 和 ZIP 档案列表。\n -p <模块路径>\n --module-path <模块路径>...\n 以 "{0}" 分隔的元素列表,每个元素都是\n 模块或包含模块的目录的文件路径。每个模块都是\n 模块化 JAR 或展开的模块目录。\n --upgrade-module-path <模块路径>...\n 以 "{0}" 分隔的元素列表,每个元素都是\n 模块或包含模块(用于替换运行时映像中的\n 可升级模块)的目录的文件路径。每个模块都是\n 模块化 JAR 或展开的模块目录。\n --add-modules <模块名称>[,<模块名称>...]\n 除了初始模块之外要解析的根模块。\n <模块名称> 还可以为 ALL-DEFAULT, ALL-SYSTEM,\n ALL-MODULE-PATH.\n --enable-native-access [,...]\n 允许模块中的代码访问 Java 运行时之外的代码和数据。\n 也可以是 ALL-UNNAMED,以指示类路径上的代码。\n --illegal-native-access=\n 允许或拒绝模块中没有明确为其启用本机访问的\n 代码访问 Java 运行时之外的代码和数据。\n 为 "deny"、"warn" 或 "allow" 之一。默认值为 "warn"。\n 此选项将在未来发行版中删除。\n --list-modules\n 列出可观察模块并退出\n -d \n --describe-module <模块名称>\n 描述模块并退出\n --dry-run 创建 VM 并加载主类, 但不执行 main 方法。\n 此 --dry-run 选项对于验证诸如\n 模块系统配置这样的命令行选项可能非常有用。\n --validate-modules\n 验证所有模块并退出\n --validate-modules 选项对于查找\n 模块路径中模块的冲突及其他错误可能非常有用。\n -D<名称>=<值>\n 设置系统属性\n -verbose:[class|module|gc|jni]\n 为给定子系统启用详细输出\n -version 将产品版本输出到错误流并退出\n --version \ -将产品版本输出到输出流并退出\n -showversion 将产品版本输出到错误流并继续\n --show-version\n 将产品版本输出到输出流并继续\n --show-module-resolution\n 在启动过程中显示模块解析输出\n -? -h -help\n 将此帮助消息输出到错误流\n --help 将此帮助消息输出到输出流\n -X 将额外选项的帮助输出到错误流\n --help-extra 将额外选项的帮助输出到输出流\n -ea[:<程序包名称>...|:<类名>]\n -enableassertions[:<程序包名称>...|:<类名>]\n 按指定的粒度启用断言\n -da[:<程序包名称>...|:<类名>]\n -disableassertions[:<程序包名称>...|:<类名>]\n 按指定的粒度禁用断言\n -esa | -enablesystemassertions\n 启用系统断言\n -dsa | -disablesystemassertions\n 禁用系统断言\n -agentlib:<库名>[=<选项>]\n 加载本机代理库 <库名>, 例如 -agentlib:jdwp\n 另请参阅 -agentlib:jdwp=help\n -agentpath:<路径名>[=<选项>]\n 按完整路径名加载本机代理库\n -javaagent:[=<选项>]\n 加载 Java 编程语言代理, 请参阅 java.lang.instrument\n -splash:<图像路径>\n 使用指定的图像显示启动屏幕\n 自动支持和使用 HiDPI 缩放图像\n (如果可用)。应始终将未缩放的图像文件名 (例如, image.ext)\n 作为参数传递给 -splash 选项。\n 将自动选取提供的最合适的缩放\n 图像。\n 有关详细信息, 请参阅 SplashScreen API 文档\n @argument 文件\n 一个或多个包含选项的参数文件\n --disable-@files\n 阻止进一步扩展参数文件\n --enable-preview\n 允许类依赖于此发行版的预览功能\n要为长选项指定参数, 可以使用 --<名称>=<值> 或\n--<名称> <值>。\n +java.launcher.opt.footer = \ -cp <目录和 zip/jar 文件的类搜索路径>\n -classpath <目录和 zip/jar 文件的类搜索路径>\n --class-path <目录和 zip/jar 文件的类搜索路径>\n 以 "{0}" 分隔的用于搜索类文件的目录、JAR 档案\n 和 ZIP 档案列表。\n -p <模块路径>\n --module-path <模块路径>...\n 以 "{0}" 分隔的元素列表,每个元素都是\n 模块或包含模块的目录的文件路径。每个模块都是\n 模块化 JAR 或展开的模块目录。\n --upgrade-module-path <模块路径>...\n 以 "{0}" 分隔的元素列表,每个元素都是\n 模块或包含模块(用于替换运行时映像中的\n 可升级模块)的目录的文件路径。每个模块都是\n 模块化 JAR 或展开的模块目录。\n --add-modules <模块名称>[,<模块名称>...]\n 除了初始模块之外要解析的根模块。\n <模块名称> 还可以为 ALL-DEFAULT, ALL-SYSTEM,\n ALL-MODULE-PATH.\n --enable-native-access [,...]\n 允许模块中的代码访问 Java 运行时之外的代码和数据。\n 也可以是 ALL-UNNAMED,以指示类路径上的代码。\n --illegal-native-access=\n 允许或拒绝模块中没有明确为其启用本机访问的\n 代码访问 Java 运行时之外的代码和数据。\n 为 "deny"、"warn" 或 "allow" 之一。默认值为 "warn"。\n 此选项将在未来发行版中删除。\n --enable-final-field-mutation [,...]\n 允许指定模块中的代码变更最终实例字段。\n 也可以是 ALL-UNNAMED,以指示类路径上的代码。\n --illegal-final-field-mutation=\n 允许或拒绝模块中的代码在未明确启用最终字段变更时\n 变更最终字段。\n 为 "deny"、"warn"、"debug" 或 "allow" 之一。默认值为 "warn"。\n 此选项将在未来发行版中删除。\n --list-modules\n 列出可观察模块并退出\n -d \n --describe-module <模块名称>\n 描述模块并退出\n --dry-run 创建 VM 并加载主类, 但不执行 main 方法。\n 此 --dry-run \ +选项对于验证诸如\n 模块系统配置这样的命令行选项可能非常有用。\n --validate-modules\n 验证所有模块并退出\n --validate-modules 选项对于查找\n 模块路径中模块的冲突及其他错误可能非常有用。\n -D<名称>=<值>\n 设置系统属性\n -verbose:[class|module|gc|jni]\n 为给定子系统启用详细输出\n -version 将产品版本输出到错误流并退出\n --version 将产品版本输出到输出流并退出\n -showversion 将产品版本输出到错误流并继续\n --show-version\n 将产品版本输出到输出流并继续\n --show-module-resolution\n 在启动过程中显示模块解析输出\n -? -h -help\n 将此帮助消息输出到错误流\n --help 将此帮助消息输出到输出流\n -X 将额外选项的帮助输出到错误流\n --help-extra 将额外选项的帮助输出到输出流\n -ea[:<程序包名称>...|:<类名>]\n -enableassertions[:<程序包名称>...|:<类名>]\n 按指定的粒度启用断言\n -da[:<程序包名称>...|:<类名>]\n -disableassertions[:<程序包名称>...|:<类名>]\n 按指定的粒度禁用断言\n -esa | -enablesystemassertions\n 启用系统断言\n -dsa | -disablesystemassertions\n 禁用系统断言\n -agentlib:<库名>[=<选项>]\n 加载本机代理库 <库名>, 例如 -agentlib:jdwp\n 另请参阅 -agentlib:jdwp=help\n -agentpath:<路径名>[=<选项>]\n 按完整路径名加载本机代理库\n -javaagent:[=<选项>]\n 加载 Java 编程语言代理, 请参阅 java.lang.instrument\n -splash:<图像路径>\n 使用指定的图像显示启动屏幕\n 自动支持和使用 HiDPI 缩放图像\n (如果可用)。应始终将未缩放的图像文件名 (例如, image.ext)\n 作为参数传递给 -splash 选项。\n 将自动选取提供的最合适的缩放\n 图像。\n 有关详细信息, 请参阅 SplashScreen API 文档\n @argument 文件\n 一个或多个包含选项的参数文件\n --disable-@files\n 阻止进一步扩展参数文件\n --enable-preview\n \ +允许类依赖于此发行版的预览功能\n要为长选项指定参数, 可以使用 --<名称>=<值> 或\n--<名称> <值>。\n # Translators please note do not translate the options themselves java.launcher.X.usage=\n -Xbatch 禁用后台编译\n -Xbootclasspath/a:<以 {0} 分隔的目录和 zip/jar 文件>\n 附加在引导类路径末尾\n -Xcheck:jni 对 JNI 函数执行其他检查\n -Xcomp 强制在首次调用时编译方法\n -Xdebug 不执行任何操作;已过时,将在未来发行版中删除。\n -Xdiag 显示附加诊断消息\n -Xint 仅解释模式执行\n -Xinternalversion\n 显示比 -version 选项更详细的\n JVM 版本信息\n -Xlog: 配置或启用采用 Java 虚拟\n 机 (Java Virtual Machine, JVM) 统一记录框架进行事件记录。使用 -Xlog:help\n 可了解详细信息。\n -Xloggc: 将 GC 状态记录在文件中(带时间戳)。\n 此选项已过时,可能会在\n 将来的发行版中删除。它将替换为 -Xlog:gc:。\n -Xmixed 混合模式执行(默认值)\n -Xmn 为年轻代(新生代)设置初始和最大堆大小\n (以字节为单位)\n -Xms 设置最小和初始 Java 堆大小\n -Xmx 设置最大 Java 堆大小\n -Xnoclassgc 禁用类垃圾收集\n -Xrs 减少 Java/VM 对操作系统信号的使用(请参见文档)\n -Xshare:auto 在可能的情况下使用共享类数据(默认值)\n -Xshare:off 不尝试使用共享类数据\n -Xshare:on 要求使用共享类数据,否则将失败。\n 这是一个测试选项,可能导致间歇性\n 故障。不应在生产环境中使用它。\n -XshowSettings 显示所有设置并继续\n -XshowSettings:all\n 详细显示所有设置并继续\n -XshowSettings:locale\n 显示所有与区域设置相关的设置并继续\n -XshowSettings:properties\n 显示所有属性设置并继续\n -XshowSettings:vm\n 显示所有与 vm 相关的设置并继续\n -XshowSettings:security\n 显示所有安全设置并继续\n -XshowSettings:security:all\n 显示所有安全设置并继续\n -XshowSettings:security:properties\n 显示安全属性并继续\n -XshowSettings:security:providers\n 显示静态安全提供方设置并继续\n -XshowSettings:security:tls\n 显示与 TLS \ @@ -49,7 +50,7 @@ java.launcher.cls.error2=错误: 在类 {0} 中找不到 main 方法, 请将 mai java.launcher.cls.error3=错误: 缺少 JavaFX 运行时组件, 需要使用该组件来运行此应用程序 java.launcher.cls.error4=错误: 加载主类 {0} 时出现 LinkageError\n\t{1} java.launcher.cls.error5=错误: 无法初始化主类 {0}\n原因: {1}: {2} -java.launcher.cls.error6=错误:在类 {0} 中未找到非专用零参数构造器\n请从现有构造器中删除专用,或者定义为:\n public {0}() +java.launcher.cls.error6=错误:在类 {0} 中未找到非专用零参数构造器\n请从现有构造器中删除 private,或者定义为:\n public {0}() java.launcher.cls.error7=错误:无法调用非静态内部类 {0} 构造器\n请将内部类设为静态或将内部类移出到单独的源文件 java.launcher.cls.error8=错误:无法实例化抽象类 {0}\n请使用具体类 java.launcher.jar.error1=错误: 尝试打开文件{0}时出现意外错误 @@ -58,6 +59,7 @@ java.launcher.jar.error3={0}中没有主清单属性 java.launcher.jar.error4=在 {0} 中加载 Java 代理时出错 java.launcher.jar.error5=错误:尝试关闭文件 {0} 时出现意外错误 java.launcher.jar.error.illegal.ena.value=错误:Enable-Native-Access 清单属性的值 "{0}" 非法。仅允许使用 ''ALL-UNNAMED'' +java.launcher.jar.error.illegal.effm.value=错误:Enable-Final-Field-Mutation 清单属性的值 "{0}" 非法。仅允许使用 ''ALL-UNNAMED'' java.launcher.init.error=初始化错误 java.launcher.javafx.error1=错误: JavaFX launchApplication 方法具有错误的签名, 必须\n将方法声明为静态方法并返回空类型的值 java.launcher.module.error1=模块 {0} 不具有 ModuleMainClass 属性,请使用 -m <模块>/<主类> diff --git a/src/java.base/share/classes/sun/security/tools/keytool/resources/keytool_de.properties b/src/java.base/share/classes/sun/security/tools/keytool/resources/keytool_de.properties index 1c7a9cd17cf..a452dd34e9d 100644 --- a/src/java.base/share/classes/sun/security/tools/keytool/resources/keytool_de.properties +++ b/src/java.base/share/classes/sun/security/tools/keytool/resources/keytool_de.properties @@ -313,7 +313,7 @@ Unable.to.parse.denyAfter.string.in.exception.message=denyAfter-Datumszeichenfol whose.sigalg.weak=%1$s verwendet den Signaturalgorithmus %2$s. Dies gilt als Sicherheitsrisiko. whose.key.disabled=%1$s verwendet %2$s. Dies gilt als Sicherheitsrisiko und ist deaktiviert. whose.key.weak=%1$s verwendet %2$s. Das gilt als Sicherheitsrisiko. Dieser Schlüssel wird in einem zukünftigen Update deaktiviert. -jks.storetype.warning=Der %1$s-Keystore verwendet ein proprietäres Format. Es wird empfohlen, auf PKCS12 zu migrieren, das ein Industriestandardformat mit "keytool -importkeystore -srckeystore %2$s -destkeystore %2$s -deststoretype pkcs12" ist. +jks.storetype.warning=%1$s verwendet veraltete kryptografische Algorithmen und wird in einer zukünftigen Version entfernt. Migrieren Sie zu PKCS12 mit:\nkeytool -importkeystore -srckeystore %2$s -destkeystore %2$s -deststoretype pkcs12 migrate.keystore.warning="%1$s" zu %4$s migriert. Der %2$s-Keystore wurde als "%3$s" gesichert. backup.keystore.warning=Der ursprüngliche Keystore "%1$s" wird als "%3$s" gesichert... importing.keystore.status=Keystore %1$s wird in %2$s importiert... diff --git a/src/java.base/share/classes/sun/security/tools/keytool/resources/keytool_ja.properties b/src/java.base/share/classes/sun/security/tools/keytool/resources/keytool_ja.properties index 63ba4f220dd..a3d7771eb38 100644 --- a/src/java.base/share/classes/sun/security/tools/keytool/resources/keytool_ja.properties +++ b/src/java.base/share/classes/sun/security/tools/keytool/resources/keytool_ja.properties @@ -313,7 +313,7 @@ Unable.to.parse.denyAfter.string.in.exception.message=例外メッセージのde whose.sigalg.weak=%1$sは%2$s署名アルゴリズムを使用しており、これはセキュリティ・リスクとみなされます。 whose.key.disabled=%1$sは%2$sを使用しており、これはセキュリティ・リスクとみなされ、無効化されています。 whose.key.weak=%1$sは%2$sを使用しており、これはセキュリティ・リスクとみなされます。これは将来の更新で無効化されます。 -jks.storetype.warning=%1$sキーストアは独自の形式を使用しています。"keytool -importkeystore -srckeystore %2$s -destkeystore %2$s -deststoretype pkcs12"を使用する業界標準の形式であるPKCS12に移行することをお薦めします。 +jks.storetype.warning=%1$sは古い暗号化アルゴリズムを使用しているため、将来のリリースで削除されます。次を使用してPKCS12に移行します:\nkeytool -importkeystore -srckeystore %2$s -destkeystore %2$s -deststoretype pkcs12 migrate.keystore.warning="%1$s"が%4$sに移行されました。%2$sキーストアは"%3$s"としてバックアップされます。 backup.keystore.warning=元のキーストア"%1$s"は"%3$s"としてバックアップされます... importing.keystore.status=キーストア%1$sを%2$sにインポートしています... diff --git a/src/java.base/share/classes/sun/security/tools/keytool/resources/keytool_zh_CN.properties b/src/java.base/share/classes/sun/security/tools/keytool/resources/keytool_zh_CN.properties index 1f96aa12c57..435e74e468f 100644 --- a/src/java.base/share/classes/sun/security/tools/keytool/resources/keytool_zh_CN.properties +++ b/src/java.base/share/classes/sun/security/tools/keytool/resources/keytool_zh_CN.properties @@ -313,7 +313,7 @@ Unable.to.parse.denyAfter.string.in.exception.message=无法解析异常错误 whose.sigalg.weak=%1$s 使用的 %2$s 签名算法存在安全风险。 whose.key.disabled=%1$s 使用的 %2$s 被视为存在安全风险而且被禁用。 whose.key.weak=%1$s 使用的 %2$s 被视为存在安全风险。它将在未来的更新中被禁用。 -jks.storetype.warning=%1$s 密钥库使用专用格式。建议使用 "keytool -importkeystore -srckeystore %2$s -destkeystore %2$s -deststoretype pkcs12" 迁移到行业标准格式 PKCS12。 +jks.storetype.warning=%1$s 使用的加密算法已过时,将在未来发行版中删除。请使用以下命令迁移到 PKCS12:\nkeytool -importkeystore -srckeystore %2$s -destkeystore %2$s -deststoretype pkcs12 migrate.keystore.warning=已将 "%1$s" 迁移到 %4$s。将 %2$s 密钥库作为 "%3$s" 进行了备份。 backup.keystore.warning=已将原始密钥库 "%1$s" 备份为 "%3$s"... importing.keystore.status=正在将密钥库 %1$s 导入到 %2$s... diff --git a/src/java.base/share/classes/sun/security/util/resources/security_de.properties b/src/java.base/share/classes/sun/security/util/resources/security_de.properties index a431268831b..63c7fdca472 100644 --- a/src/java.base/share/classes/sun/security/util/resources/security_de.properties +++ b/src/java.base/share/classes/sun/security/util/resources/security_de.properties @@ -43,7 +43,7 @@ provided.null.OID.map=Null-OID-Zuordnung angegeben NEWLINE=\n invalid.null.action.provided=Ungültige Nullaktion angegeben invalid.null.Class.provided=Ungültige Nullklasse angegeben -Subject.=Subjekt:\n +Subject.=Subject:\n .Principal.=\tPrincipal:\u0020 .Public.Credential.=\tÖffentliche Zugangsdaten:\u0020 .Private.Credential.=\tPrivate Zugangsdaten:\u0020 @@ -74,3 +74,6 @@ line.number.expected.expect.found.actual.=Zeile {0}: [{1}] erwartet, [{2}] gefun # sun.security.pkcs11.SunPKCS11 PKCS11.Token.providerName.Password.=Kennwort für PKCS11-Token [{0}]:\u0020 + +# sun.security.util.Password +warning.input.may.be.visible.on.screen=[Warnung: Eingabe ist möglicherweise auf dem Bildschirm sichtbar]\u0020 diff --git a/src/java.base/share/classes/sun/security/util/resources/security_ja.properties b/src/java.base/share/classes/sun/security/util/resources/security_ja.properties index ff13b37cf3b..00d22e054a5 100644 --- a/src/java.base/share/classes/sun/security/util/resources/security_ja.properties +++ b/src/java.base/share/classes/sun/security/util/resources/security_ja.properties @@ -74,3 +74,6 @@ line.number.expected.expect.found.actual.=行{0}: [{1}]ではなく[{2}]が検 # sun.security.pkcs11.SunPKCS11 PKCS11.Token.providerName.Password.=PKCS11トークン[{0}]パスワード:\u0020 + +# sun.security.util.Password +warning.input.may.be.visible.on.screen=[警告: 入力が画面に表示される場合があります]\u0020 diff --git a/src/java.base/share/classes/sun/security/util/resources/security_zh_CN.properties b/src/java.base/share/classes/sun/security/util/resources/security_zh_CN.properties index 6a4ec11de77..a322cb7b1e8 100644 --- a/src/java.base/share/classes/sun/security/util/resources/security_zh_CN.properties +++ b/src/java.base/share/classes/sun/security/util/resources/security_zh_CN.properties @@ -74,3 +74,6 @@ line.number.expected.expect.found.actual.=行号 {0}: 应为 [{1}], 找到 [{2}] # sun.security.pkcs11.SunPKCS11 PKCS11.Token.providerName.Password.=PKCS11 标记 [{0}] 密码:\u0020 + +# sun.security.util.Password +warning.input.may.be.visible.on.screen=[警告:输入可能显示在屏幕上]\u0020 diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler_de.properties b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler_de.properties index 0787c839cb4..b8fa413adba 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler_de.properties +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler_de.properties @@ -292,10 +292,10 @@ compiler.err.annotation.decl.not.allowed.here=Annotationsschnittstellendeklarati compiler.err.cant.inherit.from.final=Erben aus finalem {0}-Element nicht möglich # 0: symbol or name -compiler.err.cant.ref.before.ctor.called={0} kann nicht referenziert werden, bevor der Supertypkonstruktor aufgerufen wurde +compiler.err.cant.ref.before.ctor.called=Referenz zu {0} darf nur nach einem expliziten Konstruktoraufruf angezeigt werden # 0: symbol or name -compiler.err.cant.assign.initialized.before.ctor.called=Initialisiertes Feld "{0}" kann nicht zugewiesen werden, bevor der Supertypkonstruktor aufgerufen wurde +compiler.err.cant.assign.initialized.before.ctor.called=Zuweisung zu initialisiertem Feld "{0}" darf nur nach einem expliziten Konstruktoraufruf angezeigt werden compiler.err.cant.select.static.class.from.param.type=Statische Klasse kann nicht aus einem parametrisierten Typ ausgewählt werden @@ -649,11 +649,14 @@ compiler.err.limit.string.overflow=UTF8-Darstellung für Zeichenfolge "{0}..." i compiler.err.malformed.fp.lit=Nicht wohlgeformtes Gleitkommaliteral -compiler.err.method.does.not.override.superclass=Methode überschreibt oder implementiert keine Methode aus einem Supertyp +# 0: symbol, 1: symbol +compiler.err.method.does.not.override.superclass={0} in {1} überschreibt oder implementiert keine Methode aus einem Supertyp -compiler.err.static.methods.cannot.be.annotated.with.override=Statische Methoden können nicht mit @Override-Annotation versehen werden +# 0: symbol, 1: symbol +compiler.err.static.methods.cannot.be.annotated.with.override=Statische Methode {0} in {1} kann nicht mit @Override-Annotation versehen werden -compiler.err.missing.meth.body.or.decl.abstract=Methodenbody fehlt oder als abstrakt deklarieren +# 0: symbol, 1: symbol +compiler.err.missing.meth.body.or.decl.abstract=In Methode {0} in {1} fehlt ein Methodenbody, oder sie muss als abstrakt deklariert werden compiler.err.missing.ret.stmt=Rückgabeanweisung fehlt @@ -1139,6 +1142,7 @@ compiler.err.multi-module.outdir.cannot.be.exploded.module=Im Modus für mehrere # 0: path # lint: path +# flags: default-enabled compiler.warn.outdir.is.in.exploded.module=Das Ausgabeverzeichnis befindet sich in einem entpackten Modul: {0} # 0: file object @@ -1198,6 +1202,7 @@ compiler.warn.output.file.clash=Ausgabedatei mehrmals geschrieben: {0} ## The following string will appear before all messages keyed as: ## "compiler.note". +# flags: mandatory compiler.note.compressed.diags=Einige Meldungen wurden vereinfacht. Wiederholen Sie die Kompilierung mit -Xdiags:verbose, um die vollständige Ausgabe abzurufen # 0: boolean, 1: symbol @@ -1378,17 +1383,17 @@ compiler.warn.incubating.modules=Inkubatormodul(e) verwendet: {0} # 0: symbol, 1: symbol # lint: deprecation -# flags: aggregate +# flags: aggregate, mandatory, default-enabled compiler.warn.has.been.deprecated={0} in {1} ist veraltet # 0: symbol, 1: symbol # lint: removal -# flags: aggregate +# flags: aggregate, mandatory, default-enabled compiler.warn.has.been.deprecated.for.removal={0} in {1} ist veraltet und wurde zum Entfernen markiert # 0: symbol # lint: preview -# flags: aggregate +# flags: aggregate, mandatory, default-enabled compiler.warn.is.preview={0} ist eine Vorschau-API, die in einem zukünftigen Release entfernt werden kann. # 0: symbol @@ -1396,7 +1401,7 @@ compiler.err.is.preview={0} ist eine Vorschau-API, die standardmäßig deaktivie # 0: symbol # lint: preview -# flags: aggregate +# flags: aggregate, mandatory, default-enabled compiler.warn.is.preview.reflective={0} ist eine reflektive Vorschau-API, die in einem zukünftigen Release entfernt werden kann. # 0: symbol, 1: symbol @@ -1405,12 +1410,12 @@ compiler.warn.restricted.method={0}.{1} ist eine eingeschränkte Methode.\n(Eing # 0: symbol # lint: deprecation -# flags: aggregate +# flags: aggregate, mandatory, default-enabled compiler.warn.has.been.deprecated.module=Modul {0} ist veraltet # 0: symbol # lint: removal -# flags: aggregate +# flags: aggregate, mandatory, default-enabled compiler.warn.has.been.deprecated.for.removal.module=Modul {0} ist veraltet und wurde zum Entfernen markiert # 0: symbol @@ -1583,10 +1588,12 @@ compiler.warn.static.not.qualified.by.type2={0} (statisch) darf nicht als Member # 0: string, 1: fragment # lint: options +# flags: default-enabled compiler.warn.source.no.bootclasspath=Bootstrap Classpath ist nicht zusammen mit -source {0} festgelegt\n{1} # 0: string, 1: fragment # lint: options +# flags: default-enabled compiler.warn.source.no.system.modules.path=Systemmodulpfad ist nicht zusammen mit -source {0} festgelegt\n{1} # 0: string @@ -1603,10 +1610,12 @@ compiler.misc.source.no.system.modules.path.with.target=Wenn Sie den Speicherort # 0: string # lint: options +# flags: default-enabled compiler.warn.option.obsolete.source=Quellwert {0} ist veraltet und wird in einem zukünftigen Release entfernt # 0: target # lint: options +# flags: default-enabled compiler.warn.option.obsolete.target=Zielwert {0} ist veraltet und wird in einem zukünftigen Release entfernt # 0: string, 1: string @@ -1616,12 +1625,17 @@ compiler.err.option.removed.source=Quelloption {0} wird nicht mehr unterstützt. compiler.err.option.removed.target=Zieloption {0} wird nicht mehr unterstützt. Verwenden Sie {1} oder höher. # lint: options +# flags: default-enabled compiler.warn.option.obsolete.suppression=Verwenden Sie -Xlint:-options, um Warnungen zu veralteten Optionen zu unterdrücken. # 0: name, 1: number, 2: number, 3: number, 4: number # lint: classfile compiler.warn.future.attr={0}-Attribut, das in Klassendateien der Version {1}.{2} eingeführt wurde, wird in Klassendateien der Version {3}.{4} ignoriert +# 0: symbol, 1: file object +# lint: classfile +compiler.warn.inconsistent.inner.classes=InnerClasses-Attribut für {0} in {1} inkonsistent mit Quellcode\n({1} muss möglicherweise mit {0} neu kompiliert werden) + # lint: requires-automatic compiler.warn.requires.automatic=Erfordert Direktive für ein automatisches Modul @@ -1706,17 +1720,21 @@ compiler.warn.try.resource.not.referenced=Automatisch schließbare Ressource {0} # lint: try compiler.warn.try.resource.throws.interrupted.exc=Automatisch schließbare Ressource {0} umfasst die Mitgliedsmethode close(), die InterruptedException auslösen könnte +# 0: type +# lint: try +compiler.warn.try.resource.can.throw.interrupted.exc=close()-Methode kann InterruptedException in automatisch schließbarer Klasse {0} auslösen + # lint: unchecked compiler.warn.unchecked.assign=Nicht geprüfte Zuweisung: {0} zu {1} # 0: symbol, 1: type # lint: unchecked -# flags: aggregate +# flags: aggregate, mandatory, default-enabled compiler.warn.unchecked.assign.to.var=Nicht geprüfte Zuweisung zu Variable {0} als Mitglied des Raw-Typs {1} # 0: symbol, 1: type # lint: unchecked -# flags: aggregate +# flags: aggregate, mandatory, default-enabled compiler.warn.unchecked.call.mbr.of.raw.type=Nicht geprüfter Aufruf von {0} als Mitglied des Raw-Typs {1} # lint: unchecked @@ -1724,17 +1742,17 @@ compiler.warn.unchecked.cast.to.type=Nicht geprüftes Casting zu Typ {0} # 0: kind name, 1: name, 2: object, 3: object, 4: kind name, 5: symbol # lint: unchecked -# flags: aggregate +# flags: aggregate, mandatory, default-enabled compiler.warn.unchecked.meth.invocation.applied=Nicht geprüfter Methodenaufruf: {0} {1} in {4} {5} wird auf die angegebenen Typen angewendet\nErforderlich: {2}\nErmittelt: {3} # 0: type # lint: unchecked -# flags: aggregate +# flags: aggregate, mandatory, default-enabled compiler.warn.unchecked.generic.array.creation=Nicht geprüfte Erstellung eines generischen Arrays für varargs-Parameter des Typs {0} # 0: type # lint: unchecked -# flags: aggregate +# flags: aggregate, mandatory, default-enabled compiler.warn.unchecked.varargs.non.reifiable.type=Möglich Heap-Beschädigung aus parametrisiertem vararg-Typ {0} # 0: symbol @@ -1772,6 +1790,10 @@ compiler.err.no.zipfs.for.archive=Kein Dateisystemprovider zur Verarbeitung dies # lint: divzero compiler.warn.div.zero=Division durch Null +# 0: type, 1: long, 2: number +# lint: lossy-conversions +compiler.warn.bit.shift.out.of.range=Das Verschieben von {0} um {1} Bit entspricht einer Verschiebung um {2} Bit + # lint: empty compiler.warn.empty.if=Leere Anweisung nach "if" @@ -2023,7 +2045,7 @@ compiler.misc.prob.found.req=Inkompatible Typen: {0} # 0: message segment, 1: type, 2: type # lint: unchecked -# flags: aggregate +# flags: aggregate, mandatory, default-enabled compiler.warn.prob.found.req={0}\nErforderlich: {2}\nErmittelt: {1} # 0: type, 1: type @@ -2297,12 +2319,12 @@ compiler.err.override.incompatible.ret={0}\nRückgabetyp {1} ist nicht mit {2} k # 0: message segment, 1: type, 2: type # lint: unchecked -# flags: aggregate +# flags: aggregate, mandatory, default-enabled compiler.warn.override.unchecked.ret={0}\nRückgabetyp erfordert eine nicht geprüfte Konvertierung von {1} in {2} # 0: message segment, 1: type # lint: unchecked -# flags: aggregate +# flags: aggregate, mandatory, default-enabled compiler.warn.override.unchecked.thrown={0}\nAußer Kraft gesetzte Methode löst nicht {1} aus # 0: symbol @@ -2377,16 +2399,17 @@ compiler.err.preview.feature.disabled.classfile=Klassendatei für {0} verwendet # 0: message segment (feature) # lint: preview -# flags: aggregate +# flags: aggregate, mandatory, default-enabled compiler.warn.preview.feature.use={0} ist ein Vorschaufeature, das in einem zukünftigen Release entfernt werden kann. # 0: message segment (feature) # lint: preview -# flags: aggregate +# flags: aggregate, mandatory, default-enabled compiler.warn.preview.feature.use.plural={0} sind ein Vorschaufeature, das in einem zukünftigen Release entfernt werden kann. # 0: file object (classfile), 1: string (expected version) # lint: preview +# flags: mandatory compiler.warn.preview.feature.use.classfile=Klassendatei für {0} verwendet Vorschaufeatures von Java SE {1}. compiler.misc.feature.modules=Module @@ -2783,6 +2806,7 @@ compiler.err.bad.name.for.option=Ungültiger Name im Wert für {0}-Option: "{1}" # 0: option name, 1: symbol # lint: options +# flags: default-enabled compiler.warn.module.for.option.not.found=Modulname in {0}-Option nicht gefunden: {1} compiler.err.addmods.all.module.path.invalid=--add-modules ALL-MODULE-PATH kann nur beim Kompilieren des unbenannten Moduls oder beim Kompilieren im Kontext eines automatischen Moduls verwendet werden @@ -2794,6 +2818,7 @@ compiler.err.add.exports.with.release=Export eines Packages aus Systemmodul {0} compiler.err.add.reads.with.release=Hinzufügen von Lese-Edges für Systemmodul {0} ist mit --release nicht zulässig # lint: options +# flags: default-enabled compiler.warn.addopens.ignored=--add-opens hat zur Kompilierungszeit keine Auswirkungen compiler.misc.locn.module_source_path=Modulquellpfad @@ -3060,7 +3085,7 @@ compiler.err.incorrect.number.of.nested.patterns=Falsche Anzahl verschachtelter # 0: kind name, 1: symbol # lint: preview -# flags: aggregate +# flags: aggregate, mandatory, default-enabled compiler.warn.declared.using.preview={0} {1} ist mit einem Vorschaufeature deklariert, das in einem zukünftigen Release entfernt werden kann. # lint: identity diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler_ja.properties b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler_ja.properties index 291d8aeeec5..89bdc893a43 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler_ja.properties +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler_ja.properties @@ -292,10 +292,10 @@ compiler.err.annotation.decl.not.allowed.here=ここでは注釈インタフェ compiler.err.cant.inherit.from.final=final {0}からは継承できません # 0: symbol or name -compiler.err.cant.ref.before.ctor.called=スーパータイプのコンストラクタの呼出し前は{0}を参照できません +compiler.err.cant.ref.before.ctor.called={0}への参照は、明示的なコンストラクタの呼出しの後にのみ表示されます # 0: symbol or name -compiler.err.cant.assign.initialized.before.ctor.called=スーパータイプのコンストラクタの呼出し前は、初期化されたフィールド''{0}''を割り当てられません +compiler.err.cant.assign.initialized.before.ctor.called=初期化されたフィールド''{0}''への割当ては、明示的なコンストラクタの呼出しの後にのみ表示されます compiler.err.cant.select.static.class.from.param.type=パラメータにされた型からstaticクラスを選択することはできません @@ -649,11 +649,14 @@ compiler.err.limit.string.overflow=文字列"{0}..."のUTF8表現が、定数プ compiler.err.malformed.fp.lit=浮動小数点リテラルが不正です -compiler.err.method.does.not.override.superclass=メソッドはスーパータイプのメソッドをオーバーライドまたは実装しません +# 0: symbol, 1: symbol +compiler.err.method.does.not.override.superclass={1}の{0}はスーパータイプのメソッドをオーバーライドまたは実装しません -compiler.err.static.methods.cannot.be.annotated.with.override=staticメソッドは@Overrideで注釈付けすることはできません +# 0: symbol, 1: symbol +compiler.err.static.methods.cannot.be.annotated.with.override={1}のstaticメソッド{0}は@Overrideで注釈付けすることはできません -compiler.err.missing.meth.body.or.decl.abstract=メソッド本体がないか、abstractとして宣言されています +# 0: symbol, 1: symbol +compiler.err.missing.meth.body.or.decl.abstract={1}のメソッド{0}にメソッド本体がないか、abstractを宣言する必要があります compiler.err.missing.ret.stmt=return文が指定されていません @@ -1139,6 +1142,7 @@ compiler.err.multi-module.outdir.cannot.be.exploded.module=複数モジュール # 0: path # lint: path +# flags: default-enabled compiler.warn.outdir.is.in.exploded.module=出力ディレクトリは展開したモジュール内です: {0} # 0: file object @@ -1198,6 +1202,7 @@ compiler.warn.output.file.clash=出力ファイルへの書込みが複数回あ ## The following string will appear before all messages keyed as: ## "compiler.note". +# flags: mandatory compiler.note.compressed.diags=一部のメッセージは簡略化されています。-Xdiags:verboseで再コンパイルして完全な出力を取得してください # 0: boolean, 1: symbol @@ -1378,17 +1383,17 @@ compiler.warn.incubating.modules=実験的なモジュールを使用してい # 0: symbol, 1: symbol # lint: deprecation -# flags: aggregate +# flags: aggregate, mandatory, default-enabled compiler.warn.has.been.deprecated={1}の{0}は推奨されません # 0: symbol, 1: symbol # lint: removal -# flags: aggregate +# flags: aggregate, mandatory, default-enabled compiler.warn.has.been.deprecated.for.removal={1}の{0}は推奨されておらず、削除用にマークされています # 0: symbol # lint: preview -# flags: aggregate +# flags: aggregate, mandatory, default-enabled compiler.warn.is.preview={0}はプレビューAPIであり、今後のリリースで削除される可能性があります。 # 0: symbol @@ -1396,7 +1401,7 @@ compiler.err.is.preview={0}はプレビューAPIであり、デフォルトで # 0: symbol # lint: preview -# flags: aggregate +# flags: aggregate, mandatory, default-enabled compiler.warn.is.preview.reflective={0}はリフレクティブ・プレビューAPIであり、今後のリリースで削除される可能性があります。 # 0: symbol, 1: symbol @@ -1405,12 +1410,12 @@ compiler.warn.restricted.method={0}.{1}は制限されたメソッドです。\n # 0: symbol # lint: deprecation -# flags: aggregate +# flags: aggregate, mandatory, default-enabled compiler.warn.has.been.deprecated.module=モジュール{0}は推奨されません # 0: symbol # lint: removal -# flags: aggregate +# flags: aggregate, mandatory, default-enabled compiler.warn.has.been.deprecated.for.removal.module=モジュール{0}は推奨されておらず、削除用にマークされています # 0: symbol @@ -1583,10 +1588,12 @@ compiler.warn.static.not.qualified.by.type2=static {0}を匿名クラスのメ # 0: string, 1: fragment # lint: options +# flags: default-enabled compiler.warn.source.no.bootclasspath=ブートストラップ・クラス・パスが-source {0}と一緒に設定されていません\n{1} # 0: string, 1: fragment # lint: options +# flags: default-enabled compiler.warn.source.no.system.modules.path=システム・モジュールの場所が-source {0}と一緒に設定されていません\n{1} # 0: string @@ -1603,10 +1610,12 @@ compiler.misc.source.no.system.modules.path.with.target=システム・モジュ # 0: string # lint: options +# flags: default-enabled compiler.warn.option.obsolete.source=ソース値{0}は廃止されていて、今後のリリースで削除される予定です # 0: target # lint: options +# flags: default-enabled compiler.warn.option.obsolete.target=ターゲット値{0}は廃止されていて、今後のリリースで削除される予定です # 0: string, 1: string @@ -1616,12 +1625,17 @@ compiler.err.option.removed.source=ソース・オプション{0}は現在サポ compiler.err.option.removed.target=ターゲット・オプション{0}は現在サポートされていません。{1}以降を使用してください。 # lint: options +# flags: default-enabled compiler.warn.option.obsolete.suppression=廃止されたオプションについての警告を表示しないようにするには、-Xlint:オプションを使用します。 # 0: name, 1: number, 2: number, 3: number, 4: number # lint: classfile compiler.warn.future.attr=バージョン{1}.{2}のクラス・ファイルで導入された{0}属性は、バージョン{3}.{4}のクラス・ファイルでは無視されます +# 0: symbol, 1: file object +# lint: classfile +compiler.warn.inconsistent.inner.classes={1}の{0}のInnerClasses属性はソース・コードと一貫性がありません\n({1}は{0}で再コンパイルする必要がある場合があります) + # lint: requires-automatic compiler.warn.requires.automatic=自動モジュールにはディレクティブが必要です @@ -1706,17 +1720,21 @@ compiler.warn.try.resource.not.referenced=自動クローズ可能なリソー # lint: try compiler.warn.try.resource.throws.interrupted.exc=自動クローズ可能なリソース{0}に、InterruptedExceptionをスローする可能性があるメンバー・メソッドclose()があります +# 0: type +# lint: try +compiler.warn.try.resource.can.throw.interrupted.exc=close()メソッドは、自動クローズ可能なクラス{0}でInterruptedExceptionをスローできます + # lint: unchecked compiler.warn.unchecked.assign={0}から{1}への無検査代入です # 0: symbol, 1: type # lint: unchecked -# flags: aggregate +# flags: aggregate, mandatory, default-enabled compiler.warn.unchecked.assign.to.var=raw型{1}のメンバーとして変数{0}への無検査代入です # 0: symbol, 1: type # lint: unchecked -# flags: aggregate +# flags: aggregate, mandatory, default-enabled compiler.warn.unchecked.call.mbr.of.raw.type=raw型{1}のメンバーとしての{0}への無検査呼出しです # lint: unchecked @@ -1724,17 +1742,17 @@ compiler.warn.unchecked.cast.to.type=型{0}への無検査キャストです # 0: kind name, 1: name, 2: object, 3: object, 4: kind name, 5: symbol # lint: unchecked -# flags: aggregate +# flags: aggregate, mandatory, default-enabled compiler.warn.unchecked.meth.invocation.applied=無検査メソッド呼出し: {4} {5}の{0} {1}は指定された型に適用されます\n期待値: {2}\n検出値: {3} # 0: type # lint: unchecked -# flags: aggregate +# flags: aggregate, mandatory, default-enabled compiler.warn.unchecked.generic.array.creation=型{0}の可変引数パラメータに対する総称型配列の無検査作成です # 0: type # lint: unchecked -# flags: aggregate +# flags: aggregate, mandatory, default-enabled compiler.warn.unchecked.varargs.non.reifiable.type=パラメータ化された可変引数型{0}からのヒープ汚染の可能性があります # 0: symbol @@ -1772,6 +1790,10 @@ compiler.err.no.zipfs.for.archive=このファイルの処理に使用できる # lint: divzero compiler.warn.div.zero=ゼロで除算 +# 0: type, 1: long, 2: number +# lint: lossy-conversions +compiler.warn.bit.shift.out.of.range={0}を{1}ビットでシフトすることは、{2}ビットでシフトすることと同等です + # lint: empty compiler.warn.empty.if=if以降が空の文です @@ -2023,7 +2045,7 @@ compiler.misc.prob.found.req=不適合な型: {0} # 0: message segment, 1: type, 2: type # lint: unchecked -# flags: aggregate +# flags: aggregate, mandatory, default-enabled compiler.warn.prob.found.req={0}\n期待値: {2}\n検出値: {1} # 0: type, 1: type @@ -2297,12 +2319,12 @@ compiler.err.override.incompatible.ret={0}\n戻り値の型{1}は{2}と互換性 # 0: message segment, 1: type, 2: type # lint: unchecked -# flags: aggregate +# flags: aggregate, mandatory, default-enabled compiler.warn.override.unchecked.ret={0}\n戻り値の型は{1}から{2}への無検査変換が必要です # 0: message segment, 1: type # lint: unchecked -# flags: aggregate +# flags: aggregate, mandatory, default-enabled compiler.warn.override.unchecked.thrown={0}\nオーバーライドされたメソッドは{1}をスローしません # 0: symbol @@ -2377,16 +2399,17 @@ compiler.err.preview.feature.disabled.classfile={0}のクラス・ファイル # 0: message segment (feature) # lint: preview -# flags: aggregate +# flags: aggregate, mandatory, default-enabled compiler.warn.preview.feature.use={0}はプレビュー機能であり、今後のリリースで削除される可能性があります。 # 0: message segment (feature) # lint: preview -# flags: aggregate +# flags: aggregate, mandatory, default-enabled compiler.warn.preview.feature.use.plural={0}はプレビュー機能であり、今後のリリースで削除される可能性があります。 # 0: file object (classfile), 1: string (expected version) # lint: preview +# flags: mandatory compiler.warn.preview.feature.use.classfile={0}のクラス・ファイルはJava SE {1}のプレビュー機能を使用します。 compiler.misc.feature.modules=モジュール @@ -2783,6 +2806,7 @@ compiler.err.bad.name.for.option={0}オプションの値に含まれる名前 # 0: option name, 1: symbol # lint: options +# flags: default-enabled compiler.warn.module.for.option.not.found={0}オプション内にモジュール名が見つかりません: {1} compiler.err.addmods.all.module.path.invalid=--add-modules ALL-MODULE-PATHは、名前のないモジュールのコンパイル時または自動モジュールのコンテキストでのコンパイル時のみ使用できます @@ -2794,6 +2818,7 @@ compiler.err.add.exports.with.release=システム・モジュール{0}からの compiler.err.add.reads.with.release=システム・モジュール{0}の読取りエッジの追加は--releaseを指定して実行できません # lint: options +# flags: default-enabled compiler.warn.addopens.ignored=--add-opensは、コンパイル時には無効です compiler.misc.locn.module_source_path=モジュール・ソース・パス @@ -3060,7 +3085,7 @@ compiler.err.incorrect.number.of.nested.patterns=ネスト・パターンの数 # 0: kind name, 1: symbol # lint: preview -# flags: aggregate +# flags: aggregate, mandatory, default-enabled compiler.warn.declared.using.preview={0} {1}はプレビュー機能を使用して宣言されており、今後のリリースで削除される可能性があります。 # lint: identity diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler_zh_CN.properties b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler_zh_CN.properties index 268ce26bd49..861f371632d 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler_zh_CN.properties +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler_zh_CN.properties @@ -292,10 +292,10 @@ compiler.err.annotation.decl.not.allowed.here=此处不允许批注接口声明 compiler.err.cant.inherit.from.final=无法从最终{0}进行继承 # 0: symbol or name -compiler.err.cant.ref.before.ctor.called=无法在调用超类型构造器之前引用{0} +compiler.err.cant.ref.before.ctor.called=对 {0} 的引用只能在显式调用构造器后显示 # 0: symbol or name -compiler.err.cant.assign.initialized.before.ctor.called=无法在调用超类型构造器之前分配初始化字段 ''{0}'' +compiler.err.cant.assign.initialized.before.ctor.called=对初始化字段 ''{0}'' 的分配只能在显式调用构造器后显示 compiler.err.cant.select.static.class.from.param.type=无法从参数化的类型中选择静态类 @@ -649,11 +649,14 @@ compiler.err.limit.string.overflow=对于常量池来说, 字符串 "{0}..." 的 compiler.err.malformed.fp.lit=浮点文字的格式错误 -compiler.err.method.does.not.override.superclass=方法不会覆盖或实现超类型的方法 +# 0: symbol, 1: symbol +compiler.err.method.does.not.override.superclass={1} 中的 {0} 不会覆盖或实现超类型中的方法 -compiler.err.static.methods.cannot.be.annotated.with.override=不能使用 @Override 对静态方法进行批注 +# 0: symbol, 1: symbol +compiler.err.static.methods.cannot.be.annotated.with.override=不能使用 @Override 对 {1} 中的静态方法 {0} 进行批注 -compiler.err.missing.meth.body.or.decl.abstract=缺少方法主体, 或声明抽象 +# 0: symbol, 1: symbol +compiler.err.missing.meth.body.or.decl.abstract={1} 中的方法 {0} 缺少方法主体,或者应声明为抽象方法 compiler.err.missing.ret.stmt=缺少返回语句 @@ -1139,6 +1142,7 @@ compiler.err.multi-module.outdir.cannot.be.exploded.module=在多模块模式下 # 0: path # lint: path +# flags: default-enabled compiler.warn.outdir.is.in.exploded.module=输出目录位于展开的模块中: {0} # 0: file object @@ -1198,6 +1202,7 @@ compiler.warn.output.file.clash=多次写入输出文件:{0} ## The following string will appear before all messages keyed as: ## "compiler.note". +# flags: mandatory compiler.note.compressed.diags=某些消息已经过简化; 请使用 -Xdiags:verbose 重新编译以获得完整输出 # 0: boolean, 1: symbol @@ -1378,17 +1383,17 @@ compiler.warn.incubating.modules=使用 incubating 模块: {0} # 0: symbol, 1: symbol # lint: deprecation -# flags: aggregate +# flags: aggregate, mandatory, default-enabled compiler.warn.has.been.deprecated={1}中的{0}已过时 # 0: symbol, 1: symbol # lint: removal -# flags: aggregate +# flags: aggregate, mandatory, default-enabled compiler.warn.has.been.deprecated.for.removal={1} 中的 {0} 已过时, 且标记为待删除 # 0: symbol # lint: preview -# flags: aggregate +# flags: aggregate, mandatory, default-enabled compiler.warn.is.preview={0} 是预览 API,可能会在未来发行版中删除。 # 0: symbol @@ -1396,7 +1401,7 @@ compiler.err.is.preview={0} 是预览 API,默认情况下处于禁用状态。 # 0: symbol # lint: preview -# flags: aggregate +# flags: aggregate, mandatory, default-enabled compiler.warn.is.preview.reflective={0} 是反射预览 API,可能会在未来发行版中删除。 # 0: symbol, 1: symbol @@ -1405,12 +1410,12 @@ compiler.warn.restricted.method={0}.{1} 是受限制的方法。\n(受限制 # 0: symbol # lint: deprecation -# flags: aggregate +# flags: aggregate, mandatory, default-enabled compiler.warn.has.been.deprecated.module=模块 {0} 已过时 # 0: symbol # lint: removal -# flags: aggregate +# flags: aggregate, mandatory, default-enabled compiler.warn.has.been.deprecated.for.removal.module=模块 {0} 已过时, 且标记为待删除 # 0: symbol @@ -1583,10 +1588,12 @@ compiler.warn.static.not.qualified.by.type2=static {0} 不应用作匿名类的 # 0: string, 1: fragment # lint: options +# flags: default-enabled compiler.warn.source.no.bootclasspath=未与 -source {0} 一起设置引导类路径\n{1} # 0: string, 1: fragment # lint: options +# flags: default-enabled compiler.warn.source.no.system.modules.path=未与 -source {0} 一起设置系统模块的位置\n{1} # 0: string @@ -1603,10 +1610,12 @@ compiler.misc.source.no.system.modules.path.with.target=不设置系统模块的 # 0: string # lint: options +# flags: default-enabled compiler.warn.option.obsolete.source=源值 {0} 已过时,将在未来发行版中删除 # 0: target # lint: options +# flags: default-enabled compiler.warn.option.obsolete.target=目标值 {0} 已过时,将在未来发行版中删除 # 0: string, 1: string @@ -1616,12 +1625,17 @@ compiler.err.option.removed.source=不再支持源选项 {0}。请使用 {1} 或 compiler.err.option.removed.target=不再支持目标选项 {0}。请使用 {1} 或更高版本。 # lint: options +# flags: default-enabled compiler.warn.option.obsolete.suppression=要隐藏有关已过时选项的警告, 请使用 -Xlint:-options。 # 0: name, 1: number, 2: number, 3: number, 4: number # lint: classfile compiler.warn.future.attr={1}.{2} 版类文件中引入的 {0} 属性在 {3}.{4} 版类文件中被忽略 +# 0: symbol, 1: file object +# lint: classfile +compiler.warn.inconsistent.inner.classes={1} 中 {0} 的 InnerClasses 属性与源代码不一致\n(可能需要使用 {0} 重新编译 {1}) + # lint: requires-automatic compiler.warn.requires.automatic=需要自动模块的指令 @@ -1706,17 +1720,21 @@ compiler.warn.try.resource.not.referenced=不能在相应的 try 语句的正文 # lint: try compiler.warn.try.resource.throws.interrupted.exc=可自动关闭的资源{0}包含的成员方法 close() 可能抛出 InterruptedException +# 0: type +# lint: try +compiler.warn.try.resource.can.throw.interrupted.exc=在可自动关闭的类 {0} 中,close() 方法可能抛出 InterruptedException + # lint: unchecked compiler.warn.unchecked.assign=未经检查的分配: 将{0}分配给{1} # 0: symbol, 1: type # lint: unchecked -# flags: aggregate +# flags: aggregate, mandatory, default-enabled compiler.warn.unchecked.assign.to.var=对作为原始类型{1}的成员的变量{0}的分配未经过检查 # 0: symbol, 1: type # lint: unchecked -# flags: aggregate +# flags: aggregate, mandatory, default-enabled compiler.warn.unchecked.call.mbr.of.raw.type=对作为原始类型{1}的成员的{0}的调用未经过检查 # lint: unchecked @@ -1724,17 +1742,17 @@ compiler.warn.unchecked.cast.to.type=向类型{0}的转换未经过检查 # 0: kind name, 1: name, 2: object, 3: object, 4: kind name, 5: symbol # lint: unchecked -# flags: aggregate +# flags: aggregate, mandatory, default-enabled compiler.warn.unchecked.meth.invocation.applied=方法调用未经过检查: 将{4} {5}中的{0} {1}应用到给定的类型\n需要: {2}\n找到: {3} # 0: type # lint: unchecked -# flags: aggregate +# flags: aggregate, mandatory, default-enabled compiler.warn.unchecked.generic.array.creation=对于类型为{0}的 varargs 参数, 泛型数组创建未经过检查 # 0: type # lint: unchecked -# flags: aggregate +# flags: aggregate, mandatory, default-enabled compiler.warn.unchecked.varargs.non.reifiable.type=参数化 vararg 类型{0}的堆可能已受污染 # 0: symbol @@ -1772,6 +1790,10 @@ compiler.err.no.zipfs.for.archive=没有任何文件系统提供方可处理此 # lint: divzero compiler.warn.div.zero=除数为零 +# 0: type, 1: long, 2: number +# lint: lossy-conversions +compiler.warn.bit.shift.out.of.range=按 {1} 位移动 {0} 相当于按 {2} 位移动 + # lint: empty compiler.warn.empty.if=if 之后没有语句 @@ -2023,7 +2045,7 @@ compiler.misc.prob.found.req=不兼容的类型: {0} # 0: message segment, 1: type, 2: type # lint: unchecked -# flags: aggregate +# flags: aggregate, mandatory, default-enabled compiler.warn.prob.found.req={0}\n需要: {2}\n找到: {1} # 0: type, 1: type @@ -2297,12 +2319,12 @@ compiler.err.override.incompatible.ret={0}\n返回类型{1}与{2}不兼容 # 0: message segment, 1: type, 2: type # lint: unchecked -# flags: aggregate +# flags: aggregate, mandatory, default-enabled compiler.warn.override.unchecked.ret={0}\n返回类型需要从{1}到{2}的未经检查的转换 # 0: message segment, 1: type # lint: unchecked -# flags: aggregate +# flags: aggregate, mandatory, default-enabled compiler.warn.override.unchecked.thrown={0}\n被覆盖的方法未抛出{1} # 0: symbol @@ -2377,16 +2399,17 @@ compiler.err.preview.feature.disabled.classfile={0} 的类文件使用 Java SE { # 0: message segment (feature) # lint: preview -# flags: aggregate +# flags: aggregate, mandatory, default-enabled compiler.warn.preview.feature.use={0} 是预览功能,可能会在未来发行版中删除。 # 0: message segment (feature) # lint: preview -# flags: aggregate +# flags: aggregate, mandatory, default-enabled compiler.warn.preview.feature.use.plural={0} 是预览功能,可能会在未来发行版中删除。 # 0: file object (classfile), 1: string (expected version) # lint: preview +# flags: mandatory compiler.warn.preview.feature.use.classfile={0} 的类文件使用 Java SE {1} 的预览功能。 compiler.misc.feature.modules=模块 @@ -2783,6 +2806,7 @@ compiler.err.bad.name.for.option={0} 选项的值中有错误的名称: ''{1}'' # 0: option name, 1: symbol # lint: options +# flags: default-enabled compiler.warn.module.for.option.not.found=找不到 {0} 选项中的模块名称: {1} compiler.err.addmods.all.module.path.invalid=--add-modules ALL-MODULE-PATH 只能在编译未命名模块或在自动模块的上下文中编译时使用 @@ -2794,6 +2818,7 @@ compiler.err.add.exports.with.release=不允许在使用 --release 时从系统 compiler.err.add.reads.with.release=不允许在使用 --release 时为系统模块 {0} 添加读取维边: # lint: options +# flags: default-enabled compiler.warn.addopens.ignored=--add-opens 在编译时没有任何效果 compiler.misc.locn.module_source_path=模块源路径 @@ -3060,7 +3085,7 @@ compiler.err.incorrect.number.of.nested.patterns=嵌套模式数不正确\n需 # 0: kind name, 1: symbol # lint: preview -# flags: aggregate +# flags: aggregate, mandatory, default-enabled compiler.warn.declared.using.preview={0} {1} 是使用预览功能声明的,可能会在未来发行版中删除。 # lint: identity diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/javac_de.properties b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/javac_de.properties index 1a00fad1dd0..b36ad3d00ac 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/javac_de.properties +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/javac_de.properties @@ -60,6 +60,8 @@ javac.opt.target=Generiert Klassendateien, die sich für das angegebene Java SE- javac.opt.release=Kompiliert für das angegebene Java SE-Release.\nUnterstützte Releases: \n {0} javac.opt.source=Liefert Quellkompatibilität mit dem angegebenen Release von Java SE.\nUnterstützte Releases: \n {0} javac.opt.Werror=Kompilierung beenden, wenn Warnungen auftreten +javac.opt.arg.Werror=(,)* +javac.opt.Werror.custom=Geben Sie Lint-Kategorien, für die die Kompilierung durch Warnungen beendet werden soll,\ndurch Komma getrennt an. \nStellen Sie einem Schlüssel "-" voran, um die angegebene Kategorie auszuschließen. Verwenden Sie --help-lint, um die unterstützten Schlüssel anzuzeigen. javac.opt.A=Optionen zur Übergabe an die Annotationsprozessoren javac.opt.implicit=Gibt an, ob Klassendateien für implizit referenzierte Dateien generiert werden javac.opt.pkginfo=Gibt an, wie package-info-Dateien behandelt werden sollen @@ -97,12 +99,12 @@ javac.opt.arg.pathname= javac.opt.arg.file= javac.opt.Xbootclasspath.p=Dem Bootstrap Classpath voranstellen javac.opt.Xbootclasspath.a=An Bootstrap Classpath anhängen -javac.opt.Xlint=Empfohlene Warnungskategorien aktivieren -javac.opt.Xlint.all=Alle Warnungskategorien aktivieren -javac.opt.Xlint.none=Alle Warnungskategorien deaktivieren +javac.opt.Xlint=Aktivieren Sie empfohlene Lint-Warnungskategorien. In diesem Release werden alle\nverfügbaren Lint-Warnungskategorien empfohlen. +javac.opt.Xlint.all=Alle Lint-Warnungskategorien aktivieren +javac.opt.Xlint.none=Alle Lint-Warnungskategorien deaktivieren #L10N: do not localize: -Xlint javac.opt.arg.Xlint=(,)* -javac.opt.Xlint.custom=Durch Komma getrennte Warnungskategorien, die aktiviert oder deaktiviert werden sollen.\nStellen Sie einem Schlüssel "-" voran, um die angegebene Warnung zu deaktivieren.\nVerwenden Sie "--help-lint", um die unterstützten Schlüssel anzuzeigen. +javac.opt.Xlint.custom=Lint-Warnungskategorien, die aktiviert oder deaktiviert werden sollen, durch Komma getrennt. \nStellen Sie einem Schlüssel "-" voran, um die angegebene Kategorie zu deaktivieren. Verwenden Sie\n''--help-lint'', um unterstützte Schlüssel und die standardmäßig aktivierten\nKategorien anzuzeigen. javac.opt.Xlint.desc.auxiliaryclass=Warnt vor Auxiliary-Klassen, die in einer Quelldatei verborgen sind und aus anderen Dateien heraus verwendet werden. javac.opt.Xlint.desc.cast=Warnt vor unnötigen Umwandlungen mit Cast. @@ -129,7 +131,7 @@ javac.opt.Xlint.desc.finally=Warnt vor Finally-Klauseln, die nicht normal beende javac.opt.Xlint.desc.incubating=Warnt vor der Verwendung von Inkubatormodulen. -javac.opt.Xlint.desc.lossy-conversions=Warnung über möglichen Verlust von Konvertierungen in zusammengesetzten Zuweisungen. +javac.opt.Xlint.desc.lossy-conversions=Warnung über möglichen Verlust von Konvertierungen in zusammengesetzten Zuweisungen und Bitverschiebungsvorgängen. javac.opt.Xlint.desc.module=Warnt vor Problemen im Zusammenhang mit dem Modulsystem. @@ -175,11 +177,10 @@ javac.opt.Xlint.desc.preview=Warnt vor Verwendung von Vorschausprachfeatures. javac.opt.Xlint.desc.restricted=Warnt vor der Verwendung eingeschränkter Methoden. -# L10N: do not localize: identity synchronization -javac.opt.Xlint.desc.synchronization=Warnt vor Synchronisierungsversuchen mit Instanzen wertbasierter Klassen.\n Dieser Schlüssel ist ein veralteter Alias für die Kategorie "identity", die dieselben Verwendungen und\n Effekte hat. Benutzern wird empfohlen, die Kategorie "identity" für alle zukünftigen\n und vorhandenen Verwendungen von "synchronization" zu verwenden. - javac.opt.Xlint.desc.identity=Warnt vor Verwendungen wertbasierter Klassen, wenn eine Identitätsklasse erwartet wird. +javac.opt.Xlint.alias.of=Veralteter Alias für "{0}" mit identischem Effekt. Benutzern wird empfohlen,\n "{0}" anstatt "{1}" für alle aktuellen und zukünftigen Verwendungen zu nutzen. + javac.opt.Xdoclint=Empfohlene Prüfungen für Probleme in javadoc-Kommentaren aktivieren # L10N: do not localize: all none javac.opt.Xdoclint.subopts = (all|none|[-])[/] @@ -195,14 +196,17 @@ javac.opt.Xdoclint.package.desc=Aktiviert oder deaktiviert Prüfungen in bestimm javac.opt.Xstdout=Leitet die Standardausgabe um javac.opt.X=Gibt Hilfe zu zusätzlichen Optionen aus javac.opt.help=Gibt diese Hilfemeldung aus -javac.opt.help.lint=Gibt die unterstützten Schlüssel für -Xlint aus +javac.opt.help.lint=Gibt die unterstützten Schlüssel für -Xlint und -Werror aus javac.opt.help.lint.header=Die unterstützten Schlüssel für -Xlint sind: +javac.opt.help.lint.enabled.by.default=Die folgenden Lint-Warnungskategorien sind standardmäßig aktiviert: +javac.opt.help.lint.footer=Kategorien und die zugehörigen Aliasnamen können austauschbar verwendet werden. Beispiel: Das Kennzeichen\n"-Xlint:{0},{1}" wäre redundant. javac.opt.print=Gibt eine Textdarstellung der angegebenen Typen aus javac.opt.printRounds=Gibt Informationen zu Durchläufen der Annotationsverarbeitung aus javac.opt.printProcessorInfo=Gibt Informationen dazu aus, welche Annotationen ein Prozessor\nverarbeiten soll javac.opt.userpathsfirst=Durchsucht classpath und sourcepath vor anstatt nach bootclasspath nach Klassen javac.opt.prefer=Gibt an, welche Datei gelesen werden soll, wenn sowohl eine Quell- als auch eine Klassendatei für eine implizit kompilierte Klasse gefunden werden -javac.opt.preview=Aktiviert Vorschausprachfeatures.\nWird in Verbindung mit -source oder --release verwendet. +# L10N: do not localize: ''preview'' +javac.opt.preview=Aktiviert Vorschausprachfeatures. \nDeaktiviert auch die Lint-Kategorie ''preview''. \nWird in Verbindung mit -source oder --release verwendet. javac.opt.AT=Liest Optionen und Dateinamen aus Datei javac.opt.diags=Wählt einen Diagnosemodus aus javac.opt.addExports=Gibt an, dass ein Package als aus seinem definierenden Modul in\nweitere Module oder, wenn ALL-UNNAMED lautet, in alle unbenannten Module\nexportiert betrachtet werden soll. diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/javac_ja.properties b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/javac_ja.properties index 3b967d368ae..0ea1796a8e6 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/javac_ja.properties +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/javac_ja.properties @@ -59,7 +59,9 @@ javac.opt.profile=使用されているAPIが、指定したプロファイル javac.opt.target=指定されたJava SEリリースに適したクラス・ファイルを生成します。サポートされているリリース: \n {0} javac.opt.release=指定されたJava SEリリースに対してコンパイルします。サポートされているリリース: \n {0} javac.opt.source=指定されたJava SEリリースとソースの互換性を保持します。サポートされているリリース: \n {0} -javac.opt.Werror=警告が発生した場合にコンパイルを終了する +javac.opt.Werror=警告が発生した場合にコンパイルを終了します +javac.opt.arg.Werror=(,)* +javac.opt.Werror.custom=コンパイルを終了する警告のlintカテゴリを\nコンマで区切って指定します。\n指定したカテゴリを除外するには、キーの前に''-''を指定します。\nサポートされているキーを表示するには--help-lintを使用します。 javac.opt.A=注釈プロセッサに渡されるオプション javac.opt.implicit=暗黙的に参照されるファイルについてクラス・ファイルを生成するかどうかを指定する javac.opt.pkginfo=package-infoファイルの処理を指定する @@ -97,12 +99,12 @@ javac.opt.arg.pathname= javac.opt.arg.file= javac.opt.Xbootclasspath.p=ブートストラップ・クラス・パスの先頭に付加する javac.opt.Xbootclasspath.a=ブートストラップ・クラス・パスに追加する -javac.opt.Xlint=推奨の警告カテゴリを有効にします -javac.opt.Xlint.all=すべての警告カテゴリを有効にします -javac.opt.Xlint.none=すべての警告カテゴリを無効にします +javac.opt.Xlint=推奨lint警告カテゴリを有効にします。このリリースでは、\n使用可能なすべてのlint警告カテゴリが推奨されます。 +javac.opt.Xlint.all=すべてのlint警告カテゴリを有効にします +javac.opt.Xlint.none=すべてのlint警告カテゴリを無効にします #L10N: do not localize: -Xlint javac.opt.arg.Xlint=(,)* -javac.opt.Xlint.custom=有効または無効にする警告カテゴリ(カンマ区切り)。\n指定した警告を無効にするには、キーの前に''-''を指定します。\nサポートされているキーを表示するには--help-lintを使用します。 +javac.opt.Xlint.custom=有効または無効にするLint警告カテゴリ(カンマ区切り)。\n指定されたカテゴリを無効にするには、キーの前に''-''を指定します。サポートされているキーと\nデフォルトで有効になっているカテゴリを表示するには、\n''--help-lint''を使用します。 javac.opt.Xlint.desc.auxiliaryclass=ソース・ファイルで非表示になっているが他のファイルから使用されている補助クラスについて警告します。 javac.opt.Xlint.desc.cast=不要なキャストの使用について警告します。 @@ -129,7 +131,7 @@ javac.opt.Xlint.desc.finally=正常に完了しないfinally節について警 javac.opt.Xlint.desc.incubating=実験的なモジュールの使用について警告します。 -javac.opt.Xlint.desc.lossy-conversions=複合代入における精度が失われる可能性がある変換についての警告。 +javac.opt.Xlint.desc.lossy-conversions=複合代入およびビット・シフト操作における精度が失われている可能性がある変換についての警告。 javac.opt.Xlint.desc.module=モジュール・システム関連の問題について警告します。 @@ -175,11 +177,10 @@ javac.opt.Xlint.desc.preview=プレビュー言語機能の使用について警 javac.opt.Xlint.desc.restricted=制限されたメソッドの使用について警告します。 -# L10N: do not localize: identity synchronization -javac.opt.Xlint.desc.synchronization=値ベース・クラスのインスタンスでの同期の試行について警告します。\n このキーは、''identity''の非推奨のエイリアスであり、同じ使用方法と効果を\n 持ちます。ユーザーには、今後および既存の''synchronization''の使用に対して''identity''カテゴリを\n 使用することをお薦めします。 - javac.opt.Xlint.desc.identity=アイデンティティ・クラスが必要な場所での値ベース・クラスの使用について警告します。 +javac.opt.Xlint.alias.of=同じ効果を持つ''{0}''の非推奨の別名。ユーザーは現在および将来のすべての使用で\n ''{1}''のかわりに''{0}''の使用が推奨されます。 + javac.opt.Xdoclint=javadocコメントの問題に関する推奨チェックを有効にします # L10N: do not localize: all none javac.opt.Xdoclint.subopts = (all|none|[-])[/] @@ -195,14 +196,17 @@ javac.opt.Xdoclint.package.desc=特定のパッケージのチェックを有効 javac.opt.Xstdout=標準出力をリダイレクトする javac.opt.X=追加オプションのヘルプを出力します javac.opt.help=このヘルプ・メッセージを出力します -javac.opt.help.lint=-Xlintにサポートされているキーを出力します +javac.opt.help.lint=-Xlintおよび-Werrorにサポートされているキーを出力します javac.opt.help.lint.header=-Xlintにサポートされているキーは次のとおりです: +javac.opt.help.lint.enabled.by.default=次のlint警告カテゴリはデフォルトで有効になっています: +javac.opt.help.lint.footer=カテゴリとその別名は同じ意味で使用できます。たとえば、フラグ\n''-Xlint:{0},{1}''は冗長です。 javac.opt.print=指定した型のテキスト表示を出力する javac.opt.printRounds=注釈処理の往復についての情報を印刷する javac.opt.printProcessorInfo=プロセッサが処理を依頼される注釈についての情報を印刷する javac.opt.userpathsfirst=ブート・クラスパスの後ではなく、ブート・クラスパスの前にクラスのクラスパスおよびソース・パスを検索する javac.opt.prefer=暗黙的にコンパイルされるクラスについて、ソース・ファイルとクラス・ファイルの両方が見つかった際どちらを読み込むか指定する -javac.opt.preview=プレビュー言語機能を有効にします。-sourceまたは--releaseとともに使用されます。 +# L10N: do not localize: ''preview'' +javac.opt.preview=プレビュー言語機能を有効にします。\nまた、''preview'' lintカテゴリも無効にします。\n-sourceまたは--releaseとともに使用されます。 javac.opt.AT=ファイルからの読取りオプションおよびファイル名 javac.opt.diags=診断モードの選択 javac.opt.addExports=がALL-UNNAMEDである場合、その定義モジュールから、追加モジュールまたは\n すべての名前のないモジュールにエクスポート済とみなされるようにパッケージを指定します。 diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/javac_zh_CN.properties b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/javac_zh_CN.properties index a24b5511c9c..0cbfac7e778 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/javac_zh_CN.properties +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/javac_zh_CN.properties @@ -59,7 +59,9 @@ javac.opt.profile=检查使用的 API 在指定的配置文件中是否可用。 javac.opt.target=生成适合指定的 Java SE 发行版的类文件。支持的发行版:{0} javac.opt.release=为指定的 Java SE 发行版编译。支持的发行版:{0} javac.opt.source=提供与指定的 Java SE 发行版的源兼容性。支持的发行版:{0} -javac.opt.Werror=出现警告时终止编译 +javac.opt.Werror=出现任何警告时终止编译 +javac.opt.arg.Werror=(,)* +javac.opt.Werror.custom=指定出现警告时应终止编译的 lint 类别,\n以逗号分隔。\n在关键字前面加上 ''-'' 可排除指定的类别。\n使用 --help-lint 可查看支持的关键字。 javac.opt.A=传递给批注处理程序的选项 javac.opt.implicit=指定是否为隐式引用文件生成类文件 javac.opt.pkginfo=指定 package-info 文件的处理 @@ -97,12 +99,12 @@ javac.opt.arg.pathname= javac.opt.arg.file= javac.opt.Xbootclasspath.p=置于引导类路径之前 javac.opt.Xbootclasspath.a=置于引导类路径之后 -javac.opt.Xlint=启用建议的警告类别 -javac.opt.Xlint.all=启用所有警告类别 -javac.opt.Xlint.none=禁用所有警告类别 +javac.opt.Xlint=启用建议的 lint 警告类别。在此发行版中,\n建议使用所有可用的 lint 警告类别。 +javac.opt.Xlint.all=启用所有 lint 警告类别 +javac.opt.Xlint.none=禁用所有 lint 警告类别 #L10N: do not localize: -Xlint javac.opt.arg.Xlint=(,)* -javac.opt.Xlint.custom=要启用或禁用的警告类别(以逗号分隔)。\n在关键字前面加上 ''-'' 可禁用指定的警告。\n使用 --help-lint 可查看受支持的关键字。 +javac.opt.Xlint.custom=要启用或禁用的 lint 警告类别(以逗号分隔)。\n在关键字前面加上 ''-'' 可禁用指定的类别。\n使用 ''--help-lint'' 可显示支持的关键字和\n默认情况下启用的类别。 javac.opt.Xlint.desc.auxiliaryclass=有关辅助类在源文件中隐藏, 但在其他文件中使用的警告。 javac.opt.Xlint.desc.cast=有关使用了不必要转换的警告。 @@ -129,7 +131,7 @@ javac.opt.Xlint.desc.finally=有关 finally 子句未正常终止的警告。 javac.opt.Xlint.desc.incubating=有关使用 incubating 模块的警告。 -javac.opt.Xlint.desc.lossy-conversions=有关复合赋值中的转换可能会有损失的警告。 +javac.opt.Xlint.desc.lossy-conversions=有关复合赋值和移位操作中的转换可能会有损失的警告。 javac.opt.Xlint.desc.module=有关模块系统相关问题的警告。 @@ -175,11 +177,10 @@ javac.opt.Xlint.desc.preview=有关使用预览语言功能的警告。 javac.opt.Xlint.desc.restricted=有关使用受限制方法的警告。 -# L10N: do not localize: identity synchronization -javac.opt.Xlint.desc.synchronization=有关尝试在基于值的类的实例上同步的警告。\n 此密钥是 ''identity'' 的已过时别名,具有相同的用法和\n 效果。建议用户在 ''synchronization'' 的所有未来和现有\n 用法中使用 ''identity'' 类别。 - javac.opt.Xlint.desc.identity=有关在需要身份类的情况下使用基于值的类的警告。 +javac.opt.Xlint.alias.of=具有相同效果的 ''{0}'' 的别名已过时。建议用户当前和将来\n 都使用 ''{0}'' 而不是 ''{1}''。 + javac.opt.Xdoclint=为 javadoc 注释中的问题启用建议的检查 # L10N: do not localize: all none javac.opt.Xdoclint.subopts = (all|none|[-])[/] @@ -195,14 +196,17 @@ javac.opt.Xdoclint.package.desc=在特定的程序包中启用或禁用检查。 javac.opt.Xstdout=重定向标准输出 javac.opt.X=输出额外选项的帮助 javac.opt.help=输出此帮助消息 -javac.opt.help.lint=输出 -Xlint 支持的关键字 +javac.opt.help.lint=输出 -Xlint 和 -Werror 支持的关键字 javac.opt.help.lint.header=-Xlint 支持的关键字包括: +javac.opt.help.lint.enabled.by.default=默认情况下会启用以下 lint 警告类别: +javac.opt.help.lint.footer=类别及其别名可以互换使用;例如,标记\n''-Xlint:{0},{1}'' 将是冗余的。 javac.opt.print=输出指定类型的文本表示 javac.opt.printRounds=输出有关批注处理循环的信息 javac.opt.printProcessorInfo=输出有关请求处理程序处理哪些批注的信息 javac.opt.userpathsfirst=在引导类路径之前而不是之后搜索类的类路径和源路径 javac.opt.prefer=指定读取文件, 当同时找到隐式编译类的源文件和类文件时 -javac.opt.preview=启用预览语言功能。要与 -source 或 --release 一起使用。 +# L10N: do not localize: ''preview'' +javac.opt.preview=启用预览语言功能。\n还禁用''preview''lint 类别。\n要与 -source 或 --release 一起使用。 javac.opt.AT=从文件读取选项和文件名 javac.opt.diags=选择诊断模式 javac.opt.addExports=指定被视为已从其定义模块导出到其他模块或者导出到所有\n 未命名模块 (如果 为 ALL-UNNAMED) 的程序包。 diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/launcher_de.properties b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/launcher_de.properties index 1edda5da22f..bb0f14ab833 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/launcher_de.properties +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/launcher_de.properties @@ -111,6 +111,9 @@ launcher.err.cant.access.main.method=kein Zugriff auf Methode "main" in Klasse: # 0: string launcher.err.cant.find.constructor=No-Argument-Konstruktor nicht gefunden in Klasse: {0} +# 0: string +launcher.err.cant.use.private.constructor=Kein nicht privater Null-Argument-Konstruktor in Klasse {0} gefunden\nEntfernen Sie die Eigenschaft "private" aus dem vorhandenen Konstruktor, oder definieren Sie ihn als:\n public {0}() + # 0: string launcher.err.cant.access.constructor=Kein Zugriff auf No-Argument-Konstruktor in Klasse: {0} diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/launcher_ja.properties b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/launcher_ja.properties index be1feb4a8a9..ed940e731bd 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/launcher_ja.properties +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/launcher_ja.properties @@ -111,6 +111,9 @@ launcher.err.cant.access.main.method=クラスのメイン・メソッドにア # 0: string launcher.err.cant.find.constructor=クラスに引数なしのコンストラクタが見つかりません: {0} +# 0: string +launcher.err.cant.use.private.constructor=非privateのゼロ引数コンストラクタがクラス{0}に見つかりません\n既存のコンストラクタからprivateを削除するか、次のように定義してください:\n public {0}() + # 0: string launcher.err.cant.access.constructor=クラスの引数なしのコンストラクタにアクセスできません: {0} diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/launcher_zh_CN.properties b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/launcher_zh_CN.properties index 5367036d82f..1fafa95c146 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/launcher_zh_CN.properties +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/launcher_zh_CN.properties @@ -111,6 +111,9 @@ launcher.err.cant.access.main.method=无法访问类 {0} 中的 main 方法 # 0: string launcher.err.cant.find.constructor=在类 {0} 中找不到无参数构造器 +# 0: string +launcher.err.cant.use.private.constructor=在类 {0} 中未找到 non-private 零参数构造器\n请从现有构造器中删除 private,或者定义为:\n public {0}() + # 0: string launcher.err.cant.access.constructor=无法访问类 {0} 中的无参数构造器 diff --git a/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/resources/jarsigner_de.properties b/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/resources/jarsigner_de.properties index c5d9f41ee85..2b76f1408fa 100644 --- a/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/resources/jarsigner_de.properties +++ b/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/resources/jarsigner_de.properties @@ -220,3 +220,4 @@ entry.1.is.signed.in.jarinputstream.but.is.not.signed.in.jarfile=Eintrag %s ist jar.contains.internal.inconsistencies.result.in.different.contents.via.jarfile.and.jarinputstream=Diese JAR-Datei enthält interne Inkonsistenzen, die zu anderem Inhalt beim Lesen über JarFile als beim Lesen über JarInputStream führen können: signature.verification.failed.on.entry.1.when.reading.via.jarinputstream=Signaturverifizierung war für Eintrag %s beim Lesen über JarInputStream nicht erfolgreich signature.verification.failed.on.entry.1.when.reading.via.jarfile=Signaturverifizierung war für Eintrag %s beim Lesen über JarFile nicht erfolgreich +jks.storetype.warning=%1$s verwendet veraltete kryptografische Algorithmen und wird in einer zukünftigen Version entfernt. Migrieren Sie zu PKCS12 mit:\nkeytool -importkeystore -srckeystore %2$s -destkeystore %2$s -deststoretype pkcs12 diff --git a/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/resources/jarsigner_ja.properties b/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/resources/jarsigner_ja.properties index 97ab6a918cb..f2a5ce39be3 100644 --- a/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/resources/jarsigner_ja.properties +++ b/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/resources/jarsigner_ja.properties @@ -220,3 +220,4 @@ entry.1.is.signed.in.jarinputstream.but.is.not.signed.in.jarfile=エントリ%s jar.contains.internal.inconsistencies.result.in.different.contents.via.jarfile.and.jarinputstream=このJARファイルには内部的な不整合があるため、JarFileとJarInputStreamから読み取る場合にコンテンツが異なる可能性があります: signature.verification.failed.on.entry.1.when.reading.via.jarinputstream=JarInputStreamを介して読み取るときに署名検証がエントリ%sで失敗しました signature.verification.failed.on.entry.1.when.reading.via.jarfile=JarFileを介して読み取るときに署名検証がエントリ%sで失敗しました +jks.storetype.warning=%1$sは古い暗号化アルゴリズムを使用しているため、将来のリリースで削除されます。次を使用してPKCS12に移行します:\nkeytool -importkeystore -srckeystore %2$s -destkeystore %2$s -deststoretype pkcs12 diff --git a/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/resources/jarsigner_zh_CN.properties b/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/resources/jarsigner_zh_CN.properties index 378cc3ba9fc..f780bd1f1c3 100644 --- a/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/resources/jarsigner_zh_CN.properties +++ b/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/resources/jarsigner_zh_CN.properties @@ -220,3 +220,4 @@ entry.1.is.signed.in.jarinputstream.but.is.not.signed.in.jarfile=条目 %s 已 jar.contains.internal.inconsistencies.result.in.different.contents.via.jarfile.and.jarinputstream=此 JAR 文件包含内部不一致,通过 JarFile 和 JarInputStream 读取时可能会导致内容不同: signature.verification.failed.on.entry.1.when.reading.via.jarinputstream=通过 JarInputStream 读取时,条目 %s 的签名验证失败 signature.verification.failed.on.entry.1.when.reading.via.jarfile=通过 JarFile 读取时,条目 %s 的签名验证失败 +jks.storetype.warning=%1$s 使用的加密算法已过时,将在未来发行版中删除。请使用以下命令迁移到 PKCS12:\nkeytool -importkeystore -srckeystore %2$s -destkeystore %2$s -deststoretype pkcs12 diff --git a/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar_de.properties b/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar_de.properties index 2a5786e10b4..292ec9c963d 100644 --- a/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar_de.properties +++ b/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar_de.properties @@ -80,6 +80,8 @@ error.validator.info.opens.notequal=module-info.class in einem versionierten Ver error.validator.info.provides.notequal=module-info.class in einem versionierten Verzeichnis enthält unterschiedliche "provides" error.validator.info.version.notequal={0}: module-info.class in einem versionierten Verzeichnis enthält unterschiedlichen "version"-Wert error.validator.info.manclass.notequal={0}: module-info.class in einem versionierten Verzeichnis enthält unterschiedlichen "main-class"-Wert +error.validator.metainf.wrong.position=Eintrag META-INF/ an Position 0 erwartet, aber an Position {0} gefunden +error.validator.manifest.wrong.position=Eintrag META-INF/MANIFEST.MF an Position 0 oder 1 erwartet, aber an Position {0} gefunden warn.validator.identical.entry=Warnung: Eintrag {0} enthält eine Klasse, die mit\neinem bereits in der JAR-Datei enthaltenen Eintrag identisch ist warn.validator.resources.with.same.name=Warnung: Eintrag {0}, mehrere Ressourcen mit demselben Namen warn.validator.concealed.public.class=Warnung: Eintrag {0} ist eine öffentliche Klasse\nin einem verdeckten Package. Wenn Sie diese JAR-Datei in den Classpath einfügen, kommt es\nzu nicht kompatiblen öffentlichen Schnittstellen diff --git a/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar_ja.properties b/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar_ja.properties index c7d7c14613a..0d0f91ad791 100644 --- a/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar_ja.properties +++ b/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar_ja.properties @@ -80,6 +80,8 @@ error.validator.info.opens.notequal=バージョニング・ディレクトリ error.validator.info.provides.notequal=バージョニングされたディレクトリのmodule-info.classに異なる"provides"が含まれています error.validator.info.version.notequal={0}: バージョニングされたディレクトリのmodule-info.classに異なる"version"が含まれています error.validator.info.manclass.notequal={0}: バージョニングされたディレクトリのmodule-info.classに異なる"main-class"が含まれています +error.validator.metainf.wrong.position=エントリMETA-INF/は0の位置にある必要がありますが、見つかりました: {0} +error.validator.manifest.wrong.position=エントリMETA-INF/MANIFEST.MFは0または1の位置にある必要がありますが、位置: {0}で見つかりました warn.validator.identical.entry=警告 : エントリ{0}には、jarにすでに存在する\nエントリと同じクラスが含まれます warn.validator.resources.with.same.name=警告 : エントリ{0}、同じ名前を持つ複数のリソース warn.validator.concealed.public.class=警告 : エントリ{0}は、隠しパッケージ内のpublicクラスです。\nクラスパスにこのjarを配置すると、互換性のない\npublicインタフェースが生成されます diff --git a/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar_zh_CN.properties b/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar_zh_CN.properties index 1979f3e2386..41833d28bfc 100644 --- a/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar_zh_CN.properties +++ b/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar_zh_CN.properties @@ -80,6 +80,8 @@ error.validator.info.opens.notequal=版本化目录中的 module-info.class 包 error.validator.info.provides.notequal=版本化目录中的 module-info.class 包含不同的 "provides" error.validator.info.version.notequal={0}: 版本化目录中的 module-info.class 包含不同的 "version" error.validator.info.manclass.notequal={0}: 版本化目录中的 module-info.class 包含不同的 "main-class" +error.validator.metainf.wrong.position=条目 META-INF/ 应位于位置 0 处,但发现:{0} +error.validator.manifest.wrong.position=条目 META-INF/MANIFEST.MF 应位于位置 0 或 1 处,但发现该条目位于位置 {0} 处 warn.validator.identical.entry=警告: 条目 {0} 包含与 jar 中的\n现有条目相同的类 warn.validator.resources.with.same.name=警告: 条目 {0}, 多个资源具有相同名称 warn.validator.concealed.public.class=警告: 条目 {0} 是已隐藏程序包中的\n公共类, 将此 jar 放置在类路径中\n将导致公共接口不兼容 diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard_de.properties b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard_de.properties index 4cbb4b97774..a380b29d553 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard_de.properties +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard_de.properties @@ -190,6 +190,10 @@ doclet.Window_Help_title=API-Hilfe doclet.references={0} Referenzen doclet.Window_Search_title=Suchen doclet.search.main_heading=Suchen +doclet.theme.select_theme=Theme auswählen +doclet.theme.light=Hell +doclet.theme.dark=Dunkel +doclet.theme.system=Systemeinstellung # label for link/button element to show the information below doclet.search.show_more=Zusätzliche Ressourcen @@ -539,3 +543,5 @@ doclet.NoFrames_specified=Die Option --no-frames wird nicht mehr benötigt und w # L10N: do not localize the option name -footer doclet.footer_specified=Die Option -footer wird nicht mehr unterstützt und wird ignoriert.\nSie wird möglicherweise in einem zukünftigen Release entfernt. + +doclet.selectModule=Wählen Sie das Modul aus, in dem gesucht werden soll. diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard_ja.properties b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard_ja.properties index 2151b3f4a2e..69cdc862b4c 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard_ja.properties +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard_ja.properties @@ -190,6 +190,10 @@ doclet.Window_Help_title=APIヘルプ doclet.references={0}の参照 doclet.Window_Search_title=検索 doclet.search.main_heading=検索 +doclet.theme.select_theme=テーマを選択 +doclet.theme.light=明るい +doclet.theme.dark=暗い +doclet.theme.system=システム設定 # label for link/button element to show the information below doclet.search.show_more=その他のリソース @@ -539,3 +543,5 @@ doclet.NoFrames_specified=--no-framesオプションは必須ではなくなり # L10N: do not localize the option name -footer doclet.footer_specified=-footerオプションはサポートされなくなったため、無視されます。\n将来のリリースで削除される可能性があります。 + +doclet.selectModule=検索するモジュールを選択します。 diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard_zh_CN.properties b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard_zh_CN.properties index 66620d158bb..b3a0a3a1197 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard_zh_CN.properties +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard_zh_CN.properties @@ -190,6 +190,10 @@ doclet.Window_Help_title=API 帮助 doclet.references={0} 个引用 doclet.Window_Search_title=搜索 doclet.search.main_heading=搜索 +doclet.theme.select_theme=选择主题 +doclet.theme.light=浅色 +doclet.theme.dark=深色 +doclet.theme.system=系统设置 # label for link/button element to show the information below doclet.search.show_more=其他资源 @@ -539,3 +543,5 @@ doclet.NoFrames_specified=--no-frames 选项不再是必需的,可能\n会在 # L10N: do not localize the option name -footer doclet.footer_specified=-footer 选项不再受支持并将被忽略。\n可能会在未来发行版中删除此选项。 + +doclet.selectModule=选择要在其中搜索的模块。 diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets_de.properties b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets_de.properties index 0ee34071c93..a6dbf050bf3 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets_de.properties +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets_de.properties @@ -65,6 +65,7 @@ doclet.JavaScript_in_comment=JavaScript in Dokumentationskommentar gefunden.\nVe doclet.JavaScript_in_option=Option {0} enthält JavaScript.\nVerwenden Sie --allow-script-in-comments, um die Verwendung von JavaScript zuzulassen. doclet.Link_icon=Linksymbol doclet.Link_to_section=Link zu diesem Abschnitt +doclet.Toggle_member_listing=Zwischen kurzer und detaillierter Listenansicht umschalten doclet.Packages=Packages doclet.All_Packages=Alle Packages doclet.Modules=Module @@ -114,7 +115,7 @@ doclet.inheritDocWithinInappropriateTag=@inheritDoc kann in diesem Tag nicht ver doclet.inheritDocNoDoc=überschriebene Methoden dokumentieren Ausnahmetyp {0} nicht doclet.throwsInheritDocUnsupported=@inheritDoc wird für Parameter vom Typ Ausnahme, die nicht von einer Methode deklariert werden, nicht unterstützt. Dokumentieren Sie solche Ausnahmetypen direkt. doclet.noInheritedDoc=@inheritDoc wurde verwendet, aber mit {0} wird keine Methode außer Kraft gesetzt oder implementiert. -doclet.tag_misuse=Tag {0} kann nicht in {1}-Dokumentation verwendet werden. Es kann nur in folgenden Dokumentationstypen verwendet werden: {2}. +doclet.tag_misuse=Tag {0} kann nicht in Dokumentation {1} verwendet werden. Es kann nur in folgenden Dokumentationstypen verwendet werden: {2}. doclet.Package_Summary=Packageübersicht doclet.Requires_Summary=Erfordernisse doclet.Indirect_Requires_Summary=Indirekte Erfordernisse @@ -226,7 +227,7 @@ doclet.search=Suchen doclet.search_placeholder=In Dokumentation suchen ("/" eingeben) doclet.search_in_documentation=In Dokumentation suchen doclet.search_reset=Zurücksetzen -doclet.Member=Mitglied +doclet.Member=Member doclet.Field=Feld doclet.Property=Eigenschaft doclet.Constructor=Konstruktor @@ -240,11 +241,14 @@ doclet.Description=Beschreibung doclet.ConstantField=Konstantenfeld doclet.Value=Wert doclet.table_of_contents=Inhaltsverzeichnis +doclet.Sort_lexicographically=Member-Details lexikographisch sortieren +doclet.Sort_by_source_order=Member-Details nach Quellreihenfolge sortieren doclet.hide_sidebar=Randleiste ausblenden doclet.show_sidebar=Randleiste einblenden doclet.filter_label=Inhalt filtern ("." eingeben) doclet.filter_table_of_contents=Inhaltsverzeichnis filtern doclet.filter_reset=Zurücksetzen +doclet.sort_table_of_contents=Member-Details in lexikographischer Reihenfolge sortieren doclet.linkMismatch_PackagedLinkedtoModule=Der Code, der dokumentiert wird, verwendet Packages im unbenannten Modul, aber die in {0} definierten Packages befinden sich in benannten Modulen. doclet.linkMismatch_ModuleLinkedtoPackage=Der Code, der dokumentiert wird, verwendet Module, aber die in {0} definierten Packages befinden sich im unbenannten Modul. doclet.urlRedirected=URL {0} wurde umgeleitet an {1} - Aktualisieren Sie die Befehlszeilenoptionen, um diese Warnung zu unterdrücken. diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets_ja.properties b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets_ja.properties index 2b10f4e6e9a..1970203da38 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets_ja.properties +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets_ja.properties @@ -65,6 +65,7 @@ doclet.JavaScript_in_comment=ドキュメント・コメントにJavaScriptが doclet.JavaScript_in_option=オプション{0}にJavaScriptが含まれています。\n--allow-script-in-commentsを使用して、JavaScriptの使用を許可してください。 doclet.Link_icon=リンク・アイコン doclet.Link_to_section=このセクションにリンク +doclet.Toggle_member_listing=短いリスト・ビューと詳細リスト・ビューの切替え doclet.Packages=パッケージ doclet.All_Packages=すべてのパッケージ doclet.Modules=モジュール @@ -240,11 +241,14 @@ doclet.Description=説明 doclet.ConstantField=定数フィールド doclet.Value=値 doclet.table_of_contents=目次 +doclet.Sort_lexicographically=メンバー詳細を辞書順にソート +doclet.Sort_by_source_order=メンバー詳細をソース順序にソート doclet.hide_sidebar=サイドバーの非表示 doclet.show_sidebar=サイドバーの表示 doclet.filter_label=コンテンツのフィルタ(.と入力) doclet.filter_table_of_contents=目次のフィルタ doclet.filter_reset=リセット +doclet.sort_table_of_contents=メンバー詳細を辞書順にソート doclet.linkMismatch_PackagedLinkedtoModule=ドキュメント化しようとしているコードでは名前のないモジュールのパッケージが使用されていますが、{0}で定義されているパッケージは名前のあるモジュールのものです。 doclet.linkMismatch_ModuleLinkedtoPackage=ドキュメント化しようとしているコードではモジュールが使用されていますが、{0}で定義されているパッケージは名前のないモジュールのものです。 doclet.urlRedirected=URL {0}は{1}にリダイレクトされました -- コマンドライン・オプションを更新してこの警告を表示しないようにしてください。 diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets_zh_CN.properties b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets_zh_CN.properties index f2c8762b283..62e51c2c1c4 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets_zh_CN.properties +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets_zh_CN.properties @@ -65,6 +65,7 @@ doclet.JavaScript_in_comment=文档注释中发现 JavaScript。\n使用 --allow doclet.JavaScript_in_option=选项 {0} 包含 JavaScript。\n使用 --allow-script-in-comments 可允许使用 JavaScript。 doclet.Link_icon=链接图标 doclet.Link_to_section=链接到此节 +doclet.Toggle_member_listing=在简短列表视图和详细列表视图之间切换 doclet.Packages=程序包 doclet.All_Packages=所有程序包 doclet.Modules=模块 @@ -240,11 +241,14 @@ doclet.Description=说明 doclet.ConstantField=常量字段 doclet.Value=值 doclet.table_of_contents=目录 +doclet.Sort_lexicographically=按字典顺序对成员详细信息进行排序 +doclet.Sort_by_source_order=按源顺序对成员详细信息进行排序 doclet.hide_sidebar=隐藏子工具栏 doclet.show_sidebar=显示子工具栏 doclet.filter_label=筛选内容(键入 .) doclet.filter_table_of_contents=筛选目录 doclet.filter_reset=重置 +doclet.sort_table_of_contents=按字典顺序对成员详细信息进行排序 doclet.linkMismatch_PackagedLinkedtoModule=进行文档化的代码使用了未命名模块中的程序包,但在 {0} 中定义的程序包在命名模块中。 doclet.linkMismatch_ModuleLinkedtoPackage=进行文档化的代码使用了模块,但在 {0} 中定义的程序包在未命名模块中。 doclet.urlRedirected=URL {0} 已重定向到 {1} — 更新命令行选项以隐藏此警告。 diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/resources/javadoc_de.properties b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/resources/javadoc_de.properties index 7829d2d7e27..57137ffe75d 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/resources/javadoc_de.properties +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/resources/javadoc_de.properties @@ -52,7 +52,7 @@ main.opt.package.desc=Zeigt Package-/geschützte/öffentliche Typen und Mitglied main.opt.private.desc=Zeigt alle Typen und Mitglieder. Zeigt bei benannten Modulen\nalle Packages und alle Moduldetails. main.opt.show.members.arg= -main.opt.show.members.desc=Gibt an, welche Member (Felder, Methoden oder Konstruktoren) dokumentiert\nwerden, wobei der Wert "public", "protected",\n"package" oder "private" lauten kann. Der Standardwert ist "protected"\nund zeigt öffentliche und geschützte Member an. "public" zeigt nur\nöffentliche Member, "package" zeigt öffentliche, geschützte und\nPackage-Member, und "private" zeigt alle Member an. +main.opt.show.members.desc=Gibt an, welche Members (Felder, Methoden oder Konstruktoren) dokumentiert\nwerden, wobei der Wert "public", "protected",\n"package" oder "private" lauten kann. Der Standardwert ist "protected"\nund zeigt öffentliche und geschützte Members an. "public" zeigt nur\nöffentliche Members, "package" zeigt öffentliche, geschützte und\nPackage-Members, und "private" zeigt alle Members an. main.opt.show.types.arg= main.opt.show.types.desc=Gibt an, welche Typen (Klassen, Schnittstellen usw.) dokumentiert\nwerden, wobei der Wert "public", "protected",\n"package" oder "private" lauten kann. Der Standardwert ist "protected"\nund zeigt öffentliche und geschützte Typen, "public" zeigt nur\nöffentliche Typen, "package" zeigt öffentliche, geschützte und\nPackagetypen, und "private" zeigt alle Typen. diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/jlink_de.properties b/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/jlink_de.properties index 9b776745c66..40022a5532b 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/jlink_de.properties +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/jlink_de.properties @@ -78,7 +78,8 @@ err.runtime.link.patched.module=jlink unterstützt keine Verknüpfung vom Laufze err.no.module.path=Option --module-path muss mit --add-modules ALL-MODULE-PATH angegeben werden err.empty.module.path=Kein Modul im Modulpfad "{0}" mit --add-modules ALL-MODULE-PATH gefunden err.limit.modules=--limit-modules nicht mit --add-modules ALL-MODULE-PATH zulässig -err.jlink.version.mismatch=jlink-Version {0}.{1} stimmt nicht mit Ziel-java.base-Version {2}.{3} überein +err.jlink.version.mismatch=jlink-Build "{0}" stimmt nicht mit dem java.base-Ziel-Build "{1}" überein +err.jlink.version.missing=jlink-Build "{0}" kann die Build-Signatur nicht im Modul java.base finden, das im Modulpfad angegebenen wird. Wahrscheinlich stammt es aus einem früheren Build. err.automatic.module:automatisches Modul kann nicht mit jlink verwendet werden: {0} aus {1} err.unknown.byte.order:unbekannte Bytereihenfolge {0} err.launcher.main.class.empty:Launcher-Hauptklassenname darf nicht leer sein: {0} diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/jlink_ja.properties b/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/jlink_ja.properties index c925f250c41..9519a24c96e 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/jlink_ja.properties +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/jlink_ja.properties @@ -78,7 +78,8 @@ err.runtime.link.patched.module=--patch-moduleを使用してパッチ済ラン err.no.module.path=--module-pathオプションは--add-modules ALL-MODULE-PATHで指定する必要があります err.empty.module.path=モジュール・パス''{0}''に--add-modules ALL-MODULE-PATHを使用したモジュールが見つかりません err.limit.modules=--limit-modulesは--add-modules ALL-MODULE-PATHとともに指定できません -err.jlink.version.mismatch=jlinkバージョン{0}.{1}がターゲットのjava.baseバージョン{2}.{3}と一致しません +err.jlink.version.mismatch=jlinkビルド''{0}''がターゲットのjava.baseビルド''{1}''と一致しません +err.jlink.version.missing=jlinkビルド''{0}''では、モジュール・パスで指定されたjava.baseにビルド署名が見つかりません(おそらく以前のビルドから)。 err.automatic.module:jlinkでは自動モジュールは使用できません: {1}からの{0} err.unknown.byte.order:不明なバイト順{0} err.launcher.main.class.empty:起動ツールのメイン・クラス名は空にできません: {0} diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/jlink_zh_CN.properties b/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/jlink_zh_CN.properties index b7526c9f57a..81af170ae7f 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/jlink_zh_CN.properties +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/jlink_zh_CN.properties @@ -78,7 +78,8 @@ err.runtime.link.patched.module=当使用 --patch-module 在打补丁的运行 err.no.module.path=--module-path 选项必须与 --add-modules ALL-MODULE-PATH 一起指定 err.empty.module.path=在随 --add-modules ALL-MODULE-PATH 提供的模块路径 ''{0}'' 中找不到模块 err.limit.modules=不允许将 --limit-modules 与 --add-modules ALL-MODULE-PATH 一起使用 -err.jlink.version.mismatch=jlink 版本 {0}.{1} 与目标 java.base 版本 {2}.{3} 不匹配 +err.jlink.version.mismatch=jlink 工作版本 ''{0}'' 与目标 java.base 工作版本 ''{1}'' 不匹配 +err.jlink.version.missing=jlink 工作版本 ''{0}'' 在模块路径中指定的 java.base 中找不到工作版本签名,可能来自早期工作版本。 err.automatic.module:自动模块不能用于来自 {1} 的 jlink: {0} err.unknown.byte.order:未知的字节顺序 {0} err.launcher.main.class.empty:启动程序主类名不能为空: {0} diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins_de.properties b/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins_de.properties index 4713eabed85..80d1ba6e05f 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins_de.properties +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins_de.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2015, 2025, 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,9 +31,9 @@ add-options.usage=\ --add-options Stellt die angegebene release-info.argument=|add:=:=:...|del: -release-info.description=-Option lädt Releaseeigenschaften aus der angegebenen Datei.\nadd: fügt der Datei "release" Eigenschaften hinzu.\nEine beliebige Anzahl von =-Paaren kann übergeben werden.\ndel: löscht die Liste der Schlüssel in der Releasedatei. +release-info.description=Option lädt Releaseeigenschaften aus der angegebenen Datei.\n Die angegebene Datei soll erwartungsgemäß in UTF-8 codiert sein.\nadd: fügt der Datei "release" Eigenschaften hinzu.\nEine beliebige Anzahl von =-Paaren kann übergeben werden.\ndel: löscht die Liste der Schlüssel in der Releasedatei. -release-info.usage=\ --release-info |add:=:=:...|del:\n Option löscht Releaseeigenschaften aus\n der angegebenen Datei.\n add: fügt Eigenschaften der Datei "release" hinzu.\n Eine beliebige Anzahl =-Paare kann übergeben werden.\n del: löscht die Liste der Schlüssel in der Releasedatei. +release-info.usage=\ --release-info |add:=:=:...|del:\n Option lädt Releaseeigenschaften aus\n der angegebenen Datei. Die angegebene Datei soll erwartungsgemäß\n in UTF-8 codiert sein.\n add: fügt der Datei "release" Eigenschaften hinzu.\n Eine beliebige Anzahl =-Paare kann übergeben werden.\n del: löscht die Liste der Schlüssel in der Releasedatei. class-for-name.argument= @@ -41,11 +41,11 @@ class-for-name.description=Klassenoptimierung: Konvertiert Class.forName-Aufrufe class-for-name.usage=\ --class-for-name Klassenoptimierung: Konvertiert Class.forName-Aufrufe in Konstantenladevorgänge. -compress.argument=[:filter=] +compress.argument=[:filter=] compress.description= Zu verwendende Komprimierung für Ressourcen. -compress.usage=\ --compress Zu verwendende Komprimierung für Ressourcen:\n Zulässige Werte:\n zip-[0-9], wobei "zip-0" für keine Komprimierung\n und "zip-9" für die beste Komprimierung steht.\n Standardwert ist "zip-6". +compress.usage=\ --compress Zu verwendende Komprimierung für Ressourcen:\n Zulässige Werte:\n zip-'{0-9}', wobei "zip-0" für keine Komprimierung\n und "zip-9" für die beste Komprimierung steht.\n Standardwert ist "zip-6". compress.warn.argumentdeprecated=Warnung: Das Argument {0} für --compress ist veraltet und wird möglicherweise in einem zukünftigen Release entfernt @@ -170,7 +170,7 @@ plugin.opt.resources-last-sorter=\ --resources-last-sorter Das le plugin.opt.disable-plugin=\ --disable-plugin Deaktiviert das angegebene Plug-in -plugin.opt.compress=\ --compress Zu verwendende Komprimierung für Ressourcen:\n Zulässige Werte:\n zip-[0-9], wobei "zip-0" für keine Komprimierung\n und "zip-9" für die beste Komprimierung steht.\n Standardwert ist "zip-6".\n Veraltete Werte, die in einem zukünftigen Release entfernt werden:\n 0: Keine Komprimierung. Entspricht "zip-0".\n 1: Gemeinsame Verwendung konstanter Zeichenfolgen\n 2: Entspricht "zip-6". +plugin.opt.compress=\ --compress Komprimiert alle Ressourcen im Ausgabeimage:\n Zulässige Werte:\n zip-'{0-9}', wobei "zip-0" für keine Komprimierung\n und "zip-9" für die beste Komprimierung steht.\n Standardwert ist "zip-6."\n Veraltete Werte, die in einem zukünftigen Release entfernt werden:\n 0: Keine Komprimierung. Verwenden Sie stattdessen "zip-0".\n 1: Gemeinsame Verwendung konstanter Zeichenfolgen\n 2: ZIP. Verwenden Sie stattdessen "zip-6". plugin.opt.strip-debug=\ -G, --strip-debug Entfernt Debuginformationen diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins_ja.properties b/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins_ja.properties index 1cf3ba5b0c0..6ed0a486132 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins_ja.properties +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins_ja.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2015, 2025, 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,9 +31,9 @@ add-options.usage=\ --add-options 指定した文字列を release-info.argument=|add:=:=:...|del: -release-info.description=オプションは指定されたファイルからリリース・プロパティをロードします。\nadd:はリリース・ファイルにプロパティを追加します。\n任意の数の=のペアを渡すことができます。\ndel:はリリース・ファイルのキーのリストを削除します。 +release-info.description=オプションは指定されたファイルからリリース・プロパティをロードします。\n 指定されたファイルはUTF-8でエンコードされる必要があります。\nadd:はリリース・ファイルにプロパティを追加します。\n任意の数の=のペアを渡すことができます。\ndel:はリリース・ファイルのキーのリストを削除します。 -release-info.usage=\ --release-info |add:=:=:...|del:\n オプションは指定されたファイルからリリース・プロパティを\n ロードします。\n add:はリリース・ファイルにプロパティを追加します。\n 任意の数の=ペアを渡すことができます。\n del:はリリース・ファイルのキーのリストを削除します。 +release-info.usage=\ --release-info |add:=:=:...|del:\n オプションは指定されたファイルからリリース・プロパティを\n ロードします。指定されたファイルはUTF-8で\n エンコードされる必要があります。\n add:はリリース・ファイルにプロパティを追加します。\n 任意の数の=ペアを渡すことができます。\n del:はリリース・ファイルのキーのリストを削除します。 class-for-name.argument= @@ -41,11 +41,11 @@ class-for-name.description=クラスの最適化: Class.forName呼出しを定 class-for-name.usage=\ --class-for-name クラスの最適化: Class.forName呼出しを定数のロードに変換します。 -compress.argument=[:filter=] +compress.argument=[:filter=] compress.description= リソースの圧縮に使用する圧縮。 -compress.usage=\ --compress リソースの圧縮に使用する圧縮:\n 使用可能な値は\n zip-[0-9]です。zip-0では圧縮は行われず、\n zip-9では最適な圧縮が行われます。\n デフォルトはzip-6です。 +compress.usage=\ --compress リソースの圧縮に使用する圧縮:\n 使用可能な値は\n zip-'{0-9}'です。zip-0では圧縮は行われず、\n zip-9では最適な圧縮が行われます。\n デフォルトはzip-6です。 compress.warn.argumentdeprecated=警告: --compressの{0}引数は非推奨であり、今後のリリースで削除される可能性があります @@ -170,7 +170,7 @@ plugin.opt.resources-last-sorter=\ --resources-last-sorter 最後 plugin.opt.disable-plugin=\ --disable-plugin 指定したプラグインを無効にします -plugin.opt.compress=\ --compress リソースの圧縮に使用する圧縮:\n 使用可能な値は\n zip-[0-9]です。zip-0では圧縮は行われず、\n zip-9では最適な圧縮が行われます。\n デフォルトはzip-6です。\n 今後のリリースで削除される非推奨の値:\n 0: 圧縮なし。zip-0と同等。\n 1: 定数文字列の共有\n 2: zip-6と同等。 +plugin.opt.compress=\ --compress 出力イメージ内のすべてのリソースを圧縮します:\n 使用可能な値は\n zip-'{0-9}'です。zip-0では圧縮は行われず、\n zip-9では最適な圧縮が行われます。\n デフォルトはzip-6です。\n 今後のリリースで削除される非推奨の値:\n 0: 圧縮なし。かわりにzip-0を使用。\n 1: 定数文字列の共有\n 2: ZIP。かわりにzip-6を使用。 plugin.opt.strip-debug=\ -G, --strip-debug デバッグ情報を削除します diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins_zh_CN.properties b/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins_zh_CN.properties index 819238e7d04..a0480a31fc3 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins_zh_CN.properties +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins_zh_CN.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2015, 2025, 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,9 +31,9 @@ add-options.usage=\ --add-options 在生成的映像中调用虚拟 release-info.argument=|add:=:=:...|del: -release-info.description= 选项:从提供的文件加载 release 属性。\nadd:向 'release' 文件中添加属性。\n可以传递任意数量的 = 对。\ndel:删除 release 文件中的关键字列表。 +release-info.description= 选项:从提供的文件加载 release 属性。\n 指定的文件应采用 UTF-8 编码。\nadd:向 'release' 文件中添加属性。\n可以传递任意数量的 = 对。\ndel:删除 release 文件中的关键字列表。 -release-info.usage=\ --release-info |add:=:=:...|del:\n 选项:从提供的文件\n 加载 release 属性。\n add:向 'release' 文件中添加属性。\n 可以传递任意数量的 = 对。\n del:删除 release 文件中的关键字列表。 +release-info.usage=\ --release-info |add:=:=:...|del:\n 选项:从提供的文件\n 加载 release 属性。指定的文件\n 应采用 UTF-8 编码。\n add:向 'release' 文件中添加属性。\n 可以传递任意数量的 = 对。\n del:删除 release 文件中的关键字列表。 class-for-name.argument= @@ -41,11 +41,11 @@ class-for-name.description=类优化:将 Class.forName 调用转换为常量 class-for-name.usage=\ --class-for-name 类优化:将 Class.forName 调用转换为常量负载。 -compress.argument=[:filter=] +compress.argument=[:filter=] compress.description= 要在压缩资源时使用的压缩。 -compress.usage=\ --compress 要在压缩资源时使用的压缩:\n 接受的值为:\n zip-[0-9],其中 zip-0 表示无压缩,\n zip-9 表示最佳压缩。\n 默认值为 zip-6。 +compress.usage=\ --compress 要在压缩资源时使用的压缩:\n 接受的值为:\n zip-'{0-9}',其中 zip-0 表示无压缩,\n zip-9 表示最佳压缩。\n 默认值为 zip-6。 compress.warn.argumentdeprecated=警告:--compress 的 {0} 参数已过时,可能会在未来发行版中删除 @@ -170,7 +170,7 @@ plugin.opt.resources-last-sorter=\ --resources-last-sorter 允许 plugin.opt.disable-plugin=\ --disable-plugin 禁用所提及的插件 -plugin.opt.compress=\ --compress 要在压缩资源时使用的压缩:\n 接受的值为:\n zip-[0-9],其中 zip-0 表示无压缩,\n zip-9 表示最佳压缩。\n 默认值为 zip-6。\n 要在未来发行版中删除的已过时值:\n 0:无压缩。等同于 zip-0。\n 1:常量字符串共享\n 2:等同于 zip-6。 +plugin.opt.compress=\ --compress 在输出映像中压缩所有资源:\n 接受的值包括:\n zip-'{0-9}',其中 zip-0 表示无压缩,\n zip-9 表示最佳压缩。\n 默认值为 zip-6。\n 要在未来发行版中删除的已过时值:\n 0:无压缩。改为使用 zip-0。\n 1:常量字符串共享\n 2:ZIP。改为使用 zip-6。 plugin.opt.strip-debug=\ -G, --strip-debug 去除调试信息 diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/resources/LinuxResources_de.properties b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/resources/LinuxResources_de.properties index 2f8fcddff73..345ed36b7be 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/resources/LinuxResources_de.properties +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/resources/LinuxResources_de.properties @@ -23,12 +23,7 @@ # questions. # # -app.bundler.name=Linux-Anwendungsimage -deb.bundler.name=DEB-Bundle -rpm.bundler.name=RPM-Bundle - param.license-type.default=Unbekannt -param.menu-group.default=Unbekannt resource.deb-control-file=DEB-Kontrolldatei resource.deb-preinstall-script=DEB-Preinstall-Skript @@ -59,7 +54,6 @@ message.output-to-location=Package (.deb) gespeichert in: {0}. message.debs-like-licenses=Debian-Packages müssen eine Lizenz angeben. Bei fehlender Lizenz geben einige Linux-Distributionen eine Meldung über eine Beeinträchtigung der Anwendungsqualität aus. message.outputting-bundle-location=RPM für Installationsprogramm wird generiert in: {0}. message.output-bundle-location=Package (.rpm) gespeichert in: {0}. -message.creating-association-with-null-extension=Verknüpfung mit Nullerweiterung wird erstellt. message.ldd-not-available=ldd-Befehl nicht gefunden. Packageabhängigkeiten werden nicht generiert. message.deb-ldd-not-available.advice=Installieren Sie das DEB-Package "libc-bin", um ldd abzurufen. diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/resources/LinuxResources_ja.properties b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/resources/LinuxResources_ja.properties index be2cd00b42c..d0bc4f73407 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/resources/LinuxResources_ja.properties +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/resources/LinuxResources_ja.properties @@ -23,12 +23,7 @@ # questions. # # -app.bundler.name=Linuxアプリケーション・イメージ -deb.bundler.name=DEBバンドル -rpm.bundler.name=RPMバンドル - param.license-type.default=不明 -param.menu-group.default=不明 resource.deb-control-file=DEB制御ファイル resource.deb-preinstall-script=DEBインストール前スクリプト @@ -59,7 +54,6 @@ message.output-to-location=パッケージ(.deb)は次に保存されました: message.debs-like-licenses=Debianパッケージではライセンスを指定する必要があります。ライセンスがない場合、一部のLinuxディストリビューションでアプリケーションの品質に問題が発生する場合があります。 message.outputting-bundle-location=インストーラのRPMを次に生成しています: {0} message.output-bundle-location=パッケージ(.rpm)は次に保存されました: {0} -message.creating-association-with-null-extension=null拡張子との関連付けを作成しています。 message.ldd-not-available=lddコマンドが見つかりませんでした。パッケージ依存性は生成されません。 message.deb-ldd-not-available.advice="libc-bin" DEBパッケージをインストールしてlddを取得します。 diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/resources/LinuxResources_zh_CN.properties b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/resources/LinuxResources_zh_CN.properties index 5b583062ab6..f3d62675c4d 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/resources/LinuxResources_zh_CN.properties +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/resources/LinuxResources_zh_CN.properties @@ -23,12 +23,7 @@ # questions. # # -app.bundler.name=Linux 应用程序映像 -deb.bundler.name=DEB 包 -rpm.bundler.name=RPM 包 - param.license-type.default=未知 -param.menu-group.default=未知 resource.deb-control-file=DEB 控制文件 resource.deb-preinstall-script=DEB 安装前脚本 @@ -59,7 +54,6 @@ message.output-to-location=程序包 (.deb) 已保存到: {0}。 message.debs-like-licenses=Debian 程序包应指定许可证。缺少许可证将导致某些 Linux 分发投诉应用程序质量。 message.outputting-bundle-location=正在为安装程序生成 RPM, 位置: {0}。 message.output-bundle-location=程序包 (.rpm) 已保存到: {0}。 -message.creating-association-with-null-extension=正在使用空扩展名创建关联。 message.ldd-not-available=未找到 ldd 命令。将不生成程序包被依赖对象。 message.deb-ldd-not-available.advice=安装 "libc-bin" DEB 程序包以获取 ldd。 diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_de.properties b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_de.properties index 7e36a260c3f..3cc56bb6cdf 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_de.properties +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_de.properties @@ -23,24 +23,19 @@ # questions. # # - -app.bundler.name=Mac-Anwendungsimage -store.bundler.name=Mac App Store-fähiger Bundler -dmg.bundler.name=Mac-DMG-Package -pkg.bundler.name=Mac-PKG-Package - error.invalid-cfbundle-version.advice=Legen Sie einen kompatiblen Wert für "app-version" fest. Gültige Versionsnummern sind ein bis drei durch Punkte getrennte Ganzzahlen. error.explicit-sign-no-cert=Signatur wurde explizit angefordert, doch es wurde kein Signaturzertifikat gefunden error.explicit-sign-no-cert.advice=Geben Sie gültige Werte für mac-signing-key-user-name und mac-signing-keychain an -error.must-sign-app-store=Mac App Store-Apps müssen signiert werden. Die Signierung wurde von der Bundler-Konfiguration deaktiviert -error.must-sign-app-store.advice=Verwenden Sie die Option --mac-sign mit entsprechenden Werten für user-name und keychain -error.certificate.expired=Fehler: Zertifikat abgelaufen {0} +error.certificate.expired=Zertifikat abgelaufen {0} error.cert.not.found=Kein Zertifikat gefunden, das [{0}] mit Schlüsselbund [{1}] entspricht -error.multiple.certs.found=WARNUNG: Mehrere Zertifikate gefunden, die [{0}] mit Schlüsselbund [{1}] entsprechen. Es wird das erste Zertifikat verwendet -error.app-image.mac-sign.required=Fehler: Die Option "--mac-sign" ist mit einem vordefinierten Anwendungsimage und Typ [app-image] erforderlich -error.tool.failed.with.output=Fehler: "{0}" nicht erfolgreich mit folgender Ausgabe: -resource.bundle-config-file=Bundle-Konfigurationsdatei +error.multiple.certs.found=Mehrere Zertifikate mit Namen [{0}] in Schlüsselbund [{1}] gefunden +error.app-image.mac-sign.required=Die Option --mac-sign ist mit einem vordefinierten Anwendungsimage und Typ [app-image] erforderlich +error.tool.failed.with.output="{0}" war mit folgender Ausgabe nicht erfolgreich: +error.invalid-runtime-image-missing-file=Im Laufzeitimage "{0}" fehlt die Datei "{1}" +error.invalid-runtime-image-bin-dir=Laufzeitimage "{0}" darf keinen Ordner "bin" enthalten +error.invalid-runtime-image-bin-dir.advice=Verwenden Sie die jlink-Option --strip-native-commands, wenn das Laufzeitimage mit Option {0} generiert wird resource.app-info-plist=Info.plist der Anwendung +resource.app-runtime-info-plist=Eingebettete Info.plist von Java Runtime resource.runtime-info-plist=Info.plist von Java Runtime resource.entitlements=Mac-Berechtigungen resource.dmg-setup-script=DMG-Setupskript @@ -56,21 +51,15 @@ resource.pkg-background-image=PKG-Hintergrundbild resource.pkg-pdf=Projektdefinitionsdatei resource.launchd-plist-file=launchd-PLIST-Datei - message.bundle-name-too-long-warning={0} ist auf "{1}" gesetzt. Dies ist länger als 16 Zeichen. Kürzen Sie den Wert, um die Mac-Nutzungserfahrung zu verbessern. message.preparing-info-plist=Info.plist wird vorbereitet: {0}. message.icon-not-icns= Das angegebene Symbol "{0}" ist keine ICNS-Datei und wird nicht verwendet. Stattdessen wird das Standardsymbol verwendet. message.version-string-too-many-components="app-version" darf ein bis drei Zahlen aufweisen: 1, 1.2, 1.2.3. message.version-string-first-number-not-zero=Die erste Zahl in app-version darf nicht null oder negativ sein. -message.creating-association-with-null-extension=Verknüpfung mit Nullerweiterung wird erstellt. -message.ignoring.symlink=Warnung: codesign überspringt den Symlink {0}. -message.already.signed=Datei ist bereits signiert: {0}. -message.keychain.error=Fehler: Schlüsselbundliste kann nicht abgerufen werden. -message.building-bundle=Mac App Store-Package für {0} wird erstellt. +message.keychain.error=Schlüsselbundliste kann nicht abgerufen werden. message.invalid-identifier=Ungültige Mac-Bundle-ID [{0}]. message.invalid-identifier.advice=Geben Sie die ID mit "--mac-package-identifier" an. message.building-dmg=DMG-Package für {0} wird erstellt. -message.running-script=Shellskript wird auf Anwendungsimage [{0}] ausgeführt. message.preparing-dmg-setup=DMG-Setup wird vorbereitet: {0}. message.creating-dmg-file=DMG-Datei wird erstellt: {0}. message.dmg-cannot-be-overwritten=DMG-Datei [{0}] ist vorhanden und kann nicht entfernt werden. @@ -84,3 +73,5 @@ message.codesign.failed.reason.app.content="codesign" war nicht erfolgreich, und message.codesign.failed.reason.xcode.tools=Möglicher Grund für "codesign"-Fehler ist fehlender Xcode mit Befehlszeilen-Entwicklertools. Installieren Sie Xcode mit Befehlszeilen-Entwicklertools, und prüfen Sie, ob das Problem dadurch beseitigt wird. warning.unsigned.app.image=Warnung: Nicht signiertes app-image wird zum Erstellen von signiertem {0} verwendet. warning.per.user.app.image.signed=Warnung: Konfiguration der installierten Anwendung pro Benutzer wird nicht unterstützt, da "{0}" im vordefinierten signierten Anwendungsimage fehlt. +warning.non.standard.contents.sub.dir=Warnung: Der Dateiname des Verzeichnisses "{0}", das für die Option --app-content angegeben wurde, ist kein Standardunterverzeichnisname im Verzeichnis "Contents" des Anwendungs-Bundles. Möglicherweise verläuft die Codesignierung und/oder Notarisierung im Ergebnisanwendungs-Bundle nicht erfolgreich. +warning.app.content.is.not.dir=Warnung: Der Wert "{0}" der Option --app-content ist kein Verzeichnis. Möglicherweise verläuft die Codesignierung und/oder Notarisierung im Ergebnisanwendungs-Bundle nicht erfolgreich. diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_ja.properties b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_ja.properties index 4384d6507f9..d3150a34a86 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_ja.properties +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_ja.properties @@ -23,24 +23,19 @@ # questions. # # - -app.bundler.name=Macアプリケーション・イメージ -store.bundler.name=Mac App Storeの準備完了バンドラ -dmg.bundler.name=Mac DMGパッケージ -pkg.bundler.name=Mac PKGパッケージ - error.invalid-cfbundle-version.advice=互換性のある'app-version'値を設定します。有効なバージョンは、ドットで区切られた1から3つの整数です。 error.explicit-sign-no-cert=署名が明示的に要求されましたが、署名証明書が見つかりません error.explicit-sign-no-cert.advice=有効なmac-signing-key-user-nameおよびmac-signing-keychainを指定してください -error.must-sign-app-store=Mac App Storeアプリケーションは署名されている必要がありますが、署名はバンドラ構成によって無効化されています -error.must-sign-app-store.advice=--mac-signオプションを適切なuser-nameおよびkeychain付きで使用してください -error.certificate.expired=エラー: 証明書は{0}に期限が切れました +error.certificate.expired=証明書が期限切れです{0} error.cert.not.found=キーチェーン[{1}]を使用する[{0}]と一致する証明書が見つかりません -error.multiple.certs.found=警告: キーチェーン[{1}]を使用する[{0}]と一致する複数の証明書が見つかりました。最初のものを使用します -error.app-image.mac-sign.required=エラー: --mac-signオプションは、事前定義済アプリケーション・イメージおよびタイプ[app-image]で必要です -error.tool.failed.with.output=エラー: "{0}"は次の出力で失敗しました: -resource.bundle-config-file=バンドル構成ファイル +error.multiple.certs.found=名前[{0}]に一致する複数の証明書がキーチェーン[{1}]で見つかりました +error.app-image.mac-sign.required=--mac-signオプションは、事前定義済アプリケーション・イメージおよびタイプ[app-image]で必要です +error.tool.failed.with.output="{0}"は次の出力で失敗しました: +error.invalid-runtime-image-missing-file=ランタイム・イメージ"{0}"に"{1}"ファイルがありません +error.invalid-runtime-image-bin-dir=ランタイム・イメージ"{0}"に"bin"フォルダを含めることはできません +error.invalid-runtime-image-bin-dir.advice={0}オプションとともに使用されるランタイム・イメージを生成する場合は、--strip-native-commands jlinkオプションを使用します resource.app-info-plist=アプリケーションのInfo.plist +resource.app-runtime-info-plist=埋込みJavaランタイムのInfo.plist resource.runtime-info-plist=JavaランタイムのInfo.plist resource.entitlements=Mac権限 resource.dmg-setup-script=DMG設定スクリプト @@ -56,21 +51,15 @@ resource.pkg-background-image=pkg背景イメージ resource.pkg-pdf=プロジェクト定義ファイル resource.launchd-plist-file=launchd plistファイル - message.bundle-name-too-long-warning={0}が16文字を超える''{1}''に設定されています。Macでの操作性をより良くするために短くすることを検討してください。 message.preparing-info-plist=Info.plistを準備しています: {0}。 message.icon-not-icns= 指定したアイコン"{0}"はICNSファイルではなく、使用されません。デフォルト・アイコンがその位置に使用されます。 message.version-string-too-many-components='app-version'には、1、1.2、1.2.3など1から3の数字を使用できます。 message.version-string-first-number-not-zero=pp-versionの最初の数字は、ゼロまたは負の値にできません。 -message.creating-association-with-null-extension=null拡張子との関連付けを作成しています。 -message.ignoring.symlink=警告: codesignがsymlink {0}をスキップしています -message.already.signed=ファイルはすでに署名されています: {0}。 -message.keychain.error=エラー: キーチェーン・リストを取得できません。 -message.building-bundle={0}のMac App Storeパッケージを作成しています。 +message.keychain.error=キーチェーン・リストを取得できません。 message.invalid-identifier=macバンドル識別子[{0}]が無効です。 message.invalid-identifier.advice="--mac-package-identifier"で識別子を指定してください。 message.building-dmg={0}のDMGパッケージを作成しています -message.running-script=アプリケーション・イメージ[{0}]でシェル・スクリプトを実行しています。 message.preparing-dmg-setup=dmgの設定を準備しています: {0} message.creating-dmg-file=DMGファイルを作成しています: {0} message.dmg-cannot-be-overwritten=Dmgファイルは存在し[{0}]、削除できません。 @@ -84,3 +73,5 @@ message.codesign.failed.reason.app.content="codesign"が失敗したため、追 message.codesign.failed.reason.xcode.tools="codesign"失敗の考えられる理由は、Xcodeとコマンドライン・デベロッパ・ツールの欠落です。Xcodeとコマンドライン・デベロッパ・ツールをインストールして、問題が解決されるかを確認してください。 warning.unsigned.app.image=警告: 署名されていないapp-imageを使用して署名された{0}を作成します。 warning.per.user.app.image.signed=警告: 事前定義済の署名付きアプリケーション・イメージに"{0}"がないため、インストール済アプリケーションのユーザーごとの構成はサポートされません。 +warning.non.standard.contents.sub.dir=警告: --app-contentオプションに指定されたディレクトリ"{0}"のファイル名が、アプリケーション・バンドルの"Contents"ディレクトリ内の標準サブディレクトリ名ではありません。結果アプリケーション・バンドルは、コード署名および/または公証に失敗することがあります。 +warning.app.content.is.not.dir=警告: --app-contentオプションの値"{0}"はディレクトリではありません。結果アプリケーション・バンドルは、コード署名または公証(あるいはその両方)に失敗することがあります。 diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_zh_CN.properties b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_zh_CN.properties index 09c6d77694a..8ca2219b72f 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_zh_CN.properties +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_zh_CN.properties @@ -23,24 +23,19 @@ # questions. # # - -app.bundler.name=Mac 应用程序映像 -store.bundler.name=支持 Mac App Store 的打包程序 -dmg.bundler.name=Mac DMG 程序包 -pkg.bundler.name=Mac PKG 程序包 - error.invalid-cfbundle-version.advice=设置兼容的 'app-version' 值。有效版本包含一到三个用点分隔的整数。 error.explicit-sign-no-cert=已明确请求签名,但找不到签名证书 error.explicit-sign-no-cert.advice=指定有效的 mac-signing-key-user-name 和 mac-signing-keychain -error.must-sign-app-store=Mac App Store 应用程序必须签名, 而打包程序配置已禁用签名 -error.must-sign-app-store.advice=将 --mac-sign 选项用于适当的用户名和密钥链 -error.certificate.expired=错误: 证书已失效 {0} +error.certificate.expired=证书已到期 {0} error.cert.not.found=使用密钥链 [{1}] 找不到与 [{0}] 匹配的证书 -error.multiple.certs.found=警告:使用密钥链 [{1}] 找到多个与 [{0}] 匹配的证书,将使用第一个证书 -error.app-image.mac-sign.required=错误:预定义的应用程序映像和类型 [app image] 需要 --mac-sign 选项 -error.tool.failed.with.output=错误:"{0}" 失败,显示以下输出: -resource.bundle-config-file=包配置文件 +error.multiple.certs.found=在密钥链 [{1}] 中找到多个与名称 [{0}] 匹配的证书 +error.app-image.mac-sign.required=预定义的应用程序映像和类型 [app-image] 需要 --mac-sign 选项 +error.tool.failed.with.output="{0}" 失败,显示以下输出: +error.invalid-runtime-image-missing-file=运行时映像 "{0}" 缺少 "{1}" 文件 +error.invalid-runtime-image-bin-dir=运行时映像 "{0}" 不应包含 "bin" 文件夹 +error.invalid-runtime-image-bin-dir.advice=生成与 {0} 选项一起使用的运行时映像时,使用 --strip-native-commands jlink 选项 resource.app-info-plist=应用程序 Info.plist +resource.app-runtime-info-plist=嵌入式 Java 运行时 Info.plist resource.runtime-info-plist=Java 运行时 Info.plist resource.entitlements=Mac 权利 resource.dmg-setup-script=DMG 设置脚本 @@ -56,21 +51,15 @@ resource.pkg-background-image=pkg 背景图像 resource.pkg-pdf=项目定义文件 resource.launchd-plist-file=launchd plist 文件 - message.bundle-name-too-long-warning={0}已设置为 ''{1}'', 其长度超过了 16 个字符。为了获得更好的 Mac 体验, 请考虑将其缩短。 message.preparing-info-plist=正在准备 Info.plist: {0}。 message.icon-not-icns= 指定的图标 "{0}" 不是 ICNS 文件, 不会使用。将使用默认图标代替。 message.version-string-too-many-components='app-version' 可以包含 1 到 3 个数字:1、1.2、1.2.3。 message.version-string-first-number-not-zero=app-version 中的第一个数字不能为零或负数。 -message.creating-association-with-null-extension=正在使用空扩展名创建关联。 -message.ignoring.symlink=警告: codesign 正在跳过符号链接 {0}。 -message.already.signed=文件已签名:{0}。 -message.keychain.error=错误:无法获取密钥链列表。 -message.building-bundle=正在为 {0} 构建 Mac App Store 程序包。 -message.invalid-identifier=无效的 Mac 包标识符 [{0}]。 +message.keychain.error=无法获取密钥链列表。 +message.invalid-identifier=mac 包标识符 [{0}] 无效。 message.invalid-identifier.advice=请使用 "--mac-package-identifier" 指定标识符。 message.building-dmg=正在为 {0} 构建 DMG 程序包。 -message.running-script=正在应用程序映像 [{0}] 上运行 shell 脚本。 message.preparing-dmg-setup=正在准备 dmg 设置: {0}。 message.creating-dmg-file=正在创建 DMG 文件: {0}。 message.dmg-cannot-be-overwritten=Dmg 文件已存在 [{0}] 且无法删除。 @@ -84,3 +73,5 @@ message.codesign.failed.reason.app.content="codesign" 失败,并通过 "--app- message.codesign.failed.reason.xcode.tools="codesign" 失败可能是因为缺少带命令行开发人员工具的 Xcode。请安装带命令行开发人员工具的 Xcode,看看是否可以解决问题。 warning.unsigned.app.image=警告:使用未签名的 app-image 生成已签名的 {0}。 warning.per.user.app.image.signed=警告:由于预定义的已签名应用程序映像中缺少 "{0}",不支持对已安装应用程序的每用户配置提供支持。 +warning.non.standard.contents.sub.dir=警告:为 --app-content 选项指定的目录 "{0}" 的文件名不是应用程序包的 "Contents" 目录中的标准子目录名称。结果应用程序包可能会使代码签名和/或公证失败。 +warning.app.content.is.not.dir=警告:--app-content 选项的值 "{0}" 不是目录。结果应用程序包可能会使代码签名和/或公证失败。 diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/HelpResources_de.properties b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/HelpResources_de.properties index c1cb5bf4283..5b9a5728912 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/HelpResources_de.properties +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/HelpResources_de.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2017, 2025, 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,19 +24,163 @@ # # -MSG_Help=Verwendung: jpackage \n\nBeispielverwendungen:\n--------------\n Generiert ein für das Hostsystem geeignetes Anwendungspackage:\n Für eine modulare Anwendung:\n jpackage -n name -p modulePath -m moduleName/className\n Für eine nicht modulare Anwendung:\n jpackage -i inputDir -n name \\\n --main-class className --main-jar myJar.jar\n Aus einem vorab erstellten Anwendungsimage:\n jpackage -n name --app-image appImageDir\n Generiert ein Anwendungsimage:\n Für eine modulare Anwendung:\n jpackage --type app-image -n name -p modulePath \\\n -m moduleName/className\n Für eine nicht modulare Anwendung:\n jpackage --type app-image -i inputDir -n name \\\n --main-class className --main-jar myJar.jar\n Um eigene Optionen für jlink anzugeben, führen Sie jlink separat aus:\n jlink --output appRuntimeImage -p modulePath \\\n --add-modules moduleName \\\n --no-header-files [...]\n jpackage --type app-image -n name \\\n -m moduleName/className --runtime-image appRuntimeImage\n Generiert ein Java Runtime-Package:\n jpackage -n name --runtime-image \n{6}\nAllgemeine Optionen:\n @ \n Liest Optionen und/oder Modus aus einer Datei \n Diese Option kann mehrmals verwendet werden.\n --type -t \n Der zu erstellende Packagetyp\n Gültige Werte: {1} \n Bei fehlender Angabe dieser Option wird ein plattformabhängiger\n Standardtyp erstellt.\n --app-version \n Version der Anwendung und/oder des Packages\n --copyright \n Copyright für die Anwendung\n --description \n Beschreibung der Anwendung\n --help -h \n Gibt den Verwendungstext mit einer Liste und Beschreibung jeder gültigen\n Option für die aktuelle Plattform an den Ausgabestream aus und beendet den Vorgang\n --icon \n Pfad des Symbols für das Anwendungspackage\n (absoluter Pfad oder relativ zum aktuellen Verzeichnis)\n --name -n \n Name der Anwendung und/oder des Packages\n --dest -d \n Pfad, in den die generierte Ausgabedatei abgelegt wird\n (absoluter Pfad oder relativ zum aktuellen Verzeichnis)\n Standardmäßig wird das aktuelle Arbeitsverzeichnis verwendet.\n --temp \n Pfad eines neuen oder leeren Verzeichnisses zum Erstellen temporärer Dateien\n (absoluter Pfad oder relativ zum aktuellen Verzeichnis)\n Falls angegeben, wird das temporäre Verzeichnis beim Abschließen der Aufgabe\n nicht entfernt und muss manuell entfernt werden.\n Bei fehlender Angabe wird ein temporäres Verzeichnis erstellt und\n beim Abschließen der Aufgabe entfernt.\n --vendor \n Anbieter der Anwendung\n --verbose\n Aktiviert Ausgabe im Verbose-Modus\n --version\n Gibt die Produktversion an den Outputstream aus und beendet den Vorgang.\n\nOptionen für das Erstellen des Laufzeitimages:\n --add-modules [,...]\n Eine per Komma (",") getrennte Liste hinzuzufügender Module\n Diese Modulliste wird zusammen mit dem Hauptmodul (sofern angegeben)\n als Argument --add-module an jlink übergeben.\n Bei fehlender Angabe wird entweder nur das Hauptmodul (sofern --module\n angegeben ist) oder das Standardset an Modulen (sofern --main-jar \n angegeben ist) verwendet.\n Diese Option kann mehrmals verwendet werden.\n --module-path -p ...\n \ -Eine per {0} getrennte Pfadliste\n Jeder Pfad ist entweder ein Verzeichnis mit Modulen oder der Pfad zu einer\n JAR-Datei eines Moduls.\n (Jeder Pfad ist absolut oder relativ zum aktuellen Verzeichnis.)\n Diese Option kann mehrmals verwendet werden.\n --jlink-options \n Eine per Leerzeichen getrennte Liste mit an jlink zu übergebenden Optionen \n Bei fehlender Angabe wird standardmäßig "--strip-native-commands \n --strip-debug --no-man-pages --no-header-files" verwendet. \n Diese Option kann mehrmals verwendet werden.\n --runtime-image \n Pfad des vordefinierten Laufzeitimages, das in\n das Anwendungsimage kopiert wird\n (absoluter Pfad oder relativ zum aktuellen Verzeichnis)\n Wenn --runtime-image nicht angegeben wird, führt jpackage jlink aus, um\n das Laufzeitimage mit folgenden Optionen zu erstellen:\n --strip-debug, --no-header-files, --no-man-pages und\n --strip-native-commands.\n\nOptionen für das Erstellen des Anwendungsimages:\n --input -i \n Pfad des Eingabeverzeichnisses mit den zu verpackenden Dateien\n (absoluter Pfad oder relativ zum aktuellen Verzeichnis)\n Alle Dateien im Eingabeverzeichnis werden verpackt für das\n Anwendungsimage integriert.\n --app-content [,...]\n Eine per Komma getrennte Liste mit Pfaden zu Dateien und/oder Verzeichnissen,\n die zur Anwendungs-Payload hinzugefügt werden sollen.\n Diese Option kann mehrmals verwendet werden.\n\nOptionen für das Erstellen des Anwendungs-Launchers:\n --add-launcher =\n Name des Launchers sowie ein Pfad zu einer Eigenschaftendatei mit\n einer Liste von Schlüssel/Wert-Paaren\n (absoluter Pfad oder relativ zum aktuellen Verzeichnis)\n Die Schlüssel "module", "main-jar", "main-class", "description",\n "arguments", "java-options", "app-version", "icon",\n "launcher-as-service",\n "win-console", "win-shortcut", "win-menu",\n "linux-app-category" und "linux-shortcut" können verwendet werden.\n Diese Optionen werden den ursprünglichen Befehlszeilenoptionen hinzugefügt\n (oder überschreiben diese), um einen zusätzlichen, alternativen Launcher zu erstellen.\n Der Hauptanwendungs-Launcher wird aus den Befehlszeilenoptionen\n erstellt. Mit dieser Option können zusätzliche alternative Launcher\n erstellt werden. Außerdem kann diese Option mehrmals verwendet werden,\n um mehrere zusätzliche Launcher zu erstellen. \n --arguments \n Befehlszeilenargumente, die an die Hauptklasse übergeben werden, falls\n keine Befehlszeilenargumente an den Launcher übergeben werden\n Diese Option kann mehrmals verwendet werden.\n --java-options \n Optionen, die an Java Runtime übergeben werden\n Diese Option kann mehrmals verwendet werden.\n --main-class \n Qualifizierter Name der auszuführenden Anwendungshauptklasse\n Diese Option kann nur bei Angabe von --main-jar verwendet werden.\n --main-jar \n Die Haupt-JAR-Datei der Anwendung, die die Hauptklasse enthält\n (angegeben als Pfad relativ zum Eingabepfad)\n Es kann entweder die Option --module oder die Option --main-jar angegeben werden, nicht jedoch\n beides.\n --module -m [/]\n Das Hauptmodul (und optional die Hauptklasse) der Anwendung\n Dieses Modul muss unter dem Modulpfad gespeichert sein.\n Bei Angabe dieser Option wird das Hauptmodul\n \ -im Java Runtime-Image verknüpft. Es kann entweder die Option --module oder die Option --main-jar\n angegeben werden, nicht jedoch beides.\n{2}\nOptionen für das Erstellen des Anwendungspackages:\n --about-url \n URL der Homepage der Anwendung\n --app-image \n {5} (absoluter Pfad oder relativ zum aktuellen Verzeichnis)\n --file-associations \n Pfad zu einer Eigenschaftendatei mit einer Liste von Schlüssel/Wert-Paaren\n (absoluter Pfad oder relativ zum aktuellen Verzeichnis)\n Mit den Schlüsseln "extension", "mime-type", "icon" und "description"\n kann die Verknüpfung beschrieben werden.\n Diese Option kann mehrmals verwendet werden.\n --install-dir \n {4} --license-file \n Pfad zur Lizenzdatei\n (absoluter Pfad oder relativ zum aktuellen Verzeichnis)\n --resource-dir \n Pfad zum Überschreiben von jpackage-Ressourcen\n Symbole, Vorlagendateien und weitere Ressourcen von jpackage können\n durch Hinzufügen von Ersetzungsressourcen zu diesem Verzeichnis überschrieben werden.\n (absoluter Pfad oder relativ zum aktuellen Verzeichnis)\n --runtime-image \n Pfad des zu installierenden vordefinierten Laufzeitimages\n (absoluter Pfad oder relativ zum aktuellen Verzeichnis)\n Option muss beim Erstellen eines Laufzeitpackages angegeben werden.\n --launcher-as-service\n Anforderung zum Erstellen eines Installationsprogramms, das den\n Hauptanwendungs-Launcher als Hintergrundserviceanwendung registriert.\n\nPlattformabhängige Optionen für das Erstellen des Anwendungspackages:\n{3} +help.header=Verwendung: jpackage + +help.short=Verwenden Sie jpackage --help (oder -h), um eine Liste möglicher Optionen aufzurufen + +help.option-group.sample.create-native-package=\ Generieren Sie ein Anwendungspackage, das für das Hostsystem geeignet ist:\n Für eine modulare Anwendung:\n jpackage -n name -p modulePath -m moduleName/className\n Für eine nicht modulare Anwendung:\n jpackage -i inputDir -n name \\\n --main-class className --main-jar myJar.jar\n Aus einem vordefinierten Anwendungsimage:\n jpackage -n name --app-image appImageDir + +help.option-group.sample.create-app-image=\ Generieren Sie ein Anwendungspackage:\n Für eine modulare Anwendung:\n jpackage --type app-image -n name -p modulePath \\\n -m moduleName/className\n Für eine nicht modulare Anwendung:\n jpackage --type app-image -i inputDir -n name \\\n --main-class className --main-jar myJar.jar\n Um eigene Optionen für jlink anzugeben, führen Sie jlink separat aus:\n jlink --output appRuntimeImage -p modulePath \\\n --add-modules moduleName \\\n --no-header-files [...]\n jpackage --type app-image -n name \\\n -m moduleName/className --runtime-image appRuntimeImage + +help.option-group.sample.create-runtime-installer=\ Generieren Sie ein Java-Laufzeitpackage:\n jpackage -n name --runtime-image + +help.option-group.sample.sign-app-image=\ Vordefiniertes Anwendungsimage signieren:\n jpackage --type app-image --app-image \\\n --mac-sign [...]\n Hinweis: In diesem Modus sind nur die folgenden zusätzlichen Optionen zulässig:\n Das Set der zusätzlichen Mac-Signaturoptionen und --verbose + +help.option-group.sample=Beispielverwendungen +help.option-group.generic=Allgemeine Optionen +help.option-group.runtime-image=Optionen für das Erstellen des Laufzeitimages +help.option-group.app-image=Optionen für das Erstellen des Anwendungsimages +help.option-group.launcher=Optionen für das Erstellen der Anwendungslauncher: +help.option-group.launcher-platform=Plattformabhängige Option für das Erstellen des Anwendungslaunchers +help.option-group.package=Optionen für das Erstellen des Anwendungspackages +help.option-group.package-platform=Plattformabhängige Optionen für das Erstellen des Anwendungspackages + +help.option.argument-file=\ Leseoptionen und/oder -modus aus einer Datei\n Diese Option kann mehrmals verwendet werden. + +help.option.about-url=\ URL der Homepage der Anwendung + +help.option.add-launcher.win=\ Name des Launchers sowie ein Pfad zu einer Eigenschaftendatei mit\n einer Liste von Schlüssel/Wert-Paaren\n (absoluter Pfad oder relativ zum aktuellen Verzeichnis)\n Die Schlüssel "arguments", "description", "icon", "java-options",\n "launcher-as-service", "main-class", "main-jar", "module",\n "win-console", "win-menu" und "win-shortcut" können verwendet werden. \n Diese Optionen werden den ursprünglichen\n Befehlszeilenoptionen hinzugefügt (oder überschreiben diese), um einen zusätzlichen, alternativen Launcher zu erstellen.\n Der Hauptanwendungslauncher wird aus den Befehlszeilenoptionen\n erstellt. Mit dieser Option können zusätzliche alternative Launcher\n erstellt werden. Außerdem kann diese Option mehrmals verwendet werden,\n um mehrere zusätzliche Launcher zu erstellen. + +help.option.add-launcher.linux=\ Name des Launchers sowie ein Pfad zu einer Eigenschaftendatei mit\n einer Liste von Schlüssel/Wert-Paaren\n (absoluter Pfad oder relativ zum aktuellen Verzeichnis)\n Die Schlüssel "arguments", "description", "icon", "java-options",\n "launcher-as-service", "linux-shortcut", "main-class", "main-jar"\n und "module" können verwendet werden. \n Diese Optionen werden den ursprünglichen Befehlszeilenoptionen hinzugefügt\n (oder überschreiben diese), um einen zusätzlichen, alternativen Launcher zu erstellen. \n Der Hauptanwendungslauncher wird aus den Befehlszeilenoptionen\n erstellt. Mit dieser Option können zusätzliche alternative Launcher\n erstellt werden. Außerdem kann diese Option mehrmals verwendet werden,\n um mehrere zusätzliche Launcher zu erstellen. + +help.option.add-launcher.mac=\ Name des Launchers sowie ein Pfad zu einer Eigenschaftendatei mit\n einer Liste von Schlüssel/Wert-Paaren\n (absoluter Pfad oder relativ zum aktuellen Verzeichnis)\n Die Schlüssel "arguments", "description", "icon", "java-options",\n "launcher-as-service", "main-class", "main-jar"\n und "module" können verwendet werden. \n Diese Optionen werden den ursprünglichen Befehlszeilenoptionen hinzugefügt\n (oder überschreiben diese), um einen zusätzlichen, alternativen Launcher zu erstellen. \n Der Hauptanwendungslauncher wird aus den Befehlszeilenoptionen\n erstellt. Mit dieser Option können zusätzliche alternative Launcher\n erstellt werden. Außerdem kann diese Option mehrmals verwendet werden,\n um mehrere zusätzliche Launcher zu erstellen. + +help.option.add-modules=\ Eine per Komma (",") getrennte Liste hinzuzufügender Module\n Diese Modulliste wird zusammen mit dem Hauptmodul (sofern angegeben)\n als Argument --add-module an jlink übergeben. \n Bei fehlender Angabe wird entweder nur das Hauptmodul (sofern --module\n angegeben ist) oder das Standardset an Modulen (sofern --main-jar\n angegeben ist) verwendet. \n Diese Option kann mehrmals verwendet werden. + +help.option.app-content=\ Eine per Komma getrennte Liste mit Pfaden zu Dateien und/oder Verzeichnissen,\n die zur Anwendungs-Payload hinzugefügt werden sollen.\n Diese Option kann mehrmals verwendet werden. + +help.option.app-content.mac=\ Eine per Komma getrennte Liste mit Pfaden zu Dateien und/oder Verzeichnissen,\n die zur Anwendungs-Payload hinzugefügt werden sollen. \n Diese Option kann mehrmals verwendet werden. \n Hinweis: Der Wert muss ein Verzeichnis mit dem Unterverzeichnis "Resources" sein\n Unterverzeichnis (oder ein anderes Verzeichnis, das im Verzeichnis "Contents"\n des Anwendungs-Bundles gültig ist). Andernfalls produziert jpackage möglicherweise ein\n ungültiges Anwendungs-Bundle, bei dem die Codesignatur und/oder Notarisierung nicht erfolgreich\n verläuft. + +help.option.app-image=\ Speicherort des vordefinierten Anwendungsimages, mit dem\n ein installierbares Package erstellt wird\n (absoluter Pfad oder relativ zum aktuellen Verzeichnis) + +help.option.app-image.mac=\ Speicherort des vordefinierten Anwendungsimages, mit dem\n ein installierbares Package erstellt oder das vordefinierte\n Anwendungsimage signiert wird\n (absoluter Pfad bzw. relativ zum aktuellen Verzeichnis) + +help.option.app-version=\ Version der Anwendung und/oder des Packages + +help.option.arguments=\ Befehlszeilenargumente, die an die Hauptklasse übergeben werden, falls\n keine Befehlszeilenargumente an den Launcher übergeben werden\n Diese Option kann mehrmals verwendet werden. + +help.option.copyright=\ Copyright für die Anwendung + +help.option.description=\ Beschreibung der Anwendung + +help.option.dest=\ Pfad, in dem die generierte Ausgabedatei abgelegt wird\n (absoluter Pfad oder relativ zum aktuellen Verzeichnis)\n Standardmäßig wird das aktuelle Arbeitsverzeichnis verwendet. + +help.option.file-associations=\ Pfad zu einer Eigenschaftendatei mit einer Liste von Schlüssel/Wert-Paaren\n (absoluter Pfad oder relativ zum aktuellen Verzeichnis)\n Mit den Schlüsseln "extension", "mime-type", "icon" und "description"\n kann die Verknüpfung beschrieben werden.\n Diese Option kann mehrmals verwendet werden. + +help.option.help=\ Gibt den Verwendungstext mit einer Liste und Beschreibung jeder gültigen\n Option für die aktuelle Plattform an den Outputstream aus und beendet den Vorgang + +help.option.icon=\ Pfad des Symbols für das Anwendungspackage\n (absoluter Pfad oder relativ zum aktuellen Verzeichnis) + +help.option.input=\ Pfad des Eingabeverzeichnisses mit den zu verpackenden Dateien\n (absoluter Pfad oder relativ zum aktuellen Verzeichnis)\n Alle Dateien im Eingabeverzeichnis werden als Package in das\n Anwendungsimage integriert. + +help.option.install-dir=\ Absoluter Pfad des Installationsverzeichnisses der Anwendung + +help.option.install-dir.win=\ Relativer Unterpfad des Installationsverzeichnisses der\n Anwendung, wie "Programme" oder "AppData". + +help.option.installer-runtime-image=\ Pfad des zu installierenden vordefinierten Laufzeitimages\n (absoluter Pfad oder relativ zum aktuellen Verzeichnis)\n Option muss beim Erstellen eines Laufzeitpackages angegeben werden. + +help.option.java-options=\ Optionen, die an Java Runtime übergeben werden\n Diese Option kann mehrmals verwendet werden. + +help.option.jlink-options=\ Eine per Leerzeichen getrennte Liste mit an jlink zu übergebenden Optionen\n Bei fehlender Angabe wird standardmäßig "--strip-native-commands\n --strip-debug --no-man-pages --no-header-files" verwendet. \n Diese Option kann mehrmals verwendet werden. + +help.option.launcher-as-service=\ Anforderung zum Erstellen eines Installationsprogramms, das den\n Hauptanwendungslauncher als Hintergrundserviceanwendung registriert. + +help.option.license-file=\ Pfad zur Lizenzdatei\n (absoluter Pfad oder relativ zum aktuellen Verzeichnis) + +help.option.linux-app-category=\ Gruppenwert der RPM-Datei .spec oder\n Abschnittswert der DEB-Kontrolldatei + +help.option.linux-app-release=\ Releasewert der RPM-Datei .spec oder\n Debian-Revisionswert der DEB-Kontrolldatei + +help.option.linux-deb-maintainer=\ Maintainer für DEB-Package + +help.option.linux-menu-group=\ Menügruppe, in der diese Anwendung abgelegt wird + +help.option.linux-package-deps=\ Erforderliche Packages oder Funktionen für die Anwendung + +help.option.linux-package-name=\ Name für das Linux-Package, Standardwert: Anwendungsname + +help.option.linux-rpm-license-type=\ Lizenztyp ("Lizenz: " der RPM-SPEC-Datei) + +help.option.linux-shortcut=\ Erstellt eine Verknüpfung für die Anwendung. + +help.option.mac-app-category=\ Zeichenfolge für das Erstellen von LSApplicationCategoryType in\n Anwendungs-plist. Standardwert: "utilities". + +help.option.mac-app-image-sign-identity=\ Zum Signieren des Anwendungsimages verwendete Identität. Dieser Wert wird direkt\n an die Option --sign des Tools "codesign" übergeben. Diese Option kann nicht\n mit --mac-signing-key-user-name kombiniert werden. + +help.option.mac-app-store=\ Gibt an, dass die jpackage-Ausgabe für den\n Mac App Store vorgesehen ist. + +help.option.mac-dmg-content=\ Nimmt den gesamten referenzierten Inhalt in die DMG-Datei auf.\n Diese Option kann mehrmals verwendet werden. + +help.option.mac-entitlements=\ Pfad zu einer Datei mit Berechtigungen, die beim Signieren von ausführbaren\n Dateien und Librarys im Bundle verwendet werden sollen. + +help.option.mac-installer-sign-identity=\ Zum Signieren des Installationsprogramms "pkg" verwendete Identität. Dieser Wert wird direkt\n an die Option --sign des Tools "productbuild"-übergeben. Diese Option\n kann nicht mit --mac-signing-key-user-name kombiniert werden. + +help.option.mac-package-identifier=\ Eine ID, die die Anwendung für macOS eindeutig identifiziert\n Standardwert ist der Hauptklassenname. \n Es dürfen nur alphanumerische Zeichen (A-Z, a-z, 0-9), Bindestriche (-)\n und Punkte (.) verwendet werden. + +help.option.mac-package-name=\ Name der Anwendung, wie in der Menüleiste angezeigt\n Dieser kann vom Anwendungsnamen abweichen.\n Er darf maximal 15 Zeichen enthalten und muss für die Anzeige\n in der Menüleiste und im Infofenster der Anwendung geeignet sein.\n Standardwert: Anwendungsname. + +help.option.mac-package-signing-prefix=\ Beim Signieren des Anwendungspackages wird dieser Wert\n allen zu signierenden Komponenten ohne vorhandene\n Package-ID als Präfix vorangestellt. + +help.option.mac-sign=\ Anforderung zum Signieren des Packages oder des vordefinierten\n Anwendungsimages. + +help.option.mac-signing-keychain=\ Name des Schlüsselbundes für die Suche nach der Signaturidentität\n Bei fehlender Angabe werden die Standardschlüsselbunde verwendet. + +help.option.mac-signing-key-user-name=\ Team- oder Benutzernamensteil der Apple-Signaturidentitäten. Um direkt zu steuern,\n welche Signaturidentität zum Signieren eines Anwendungsimages oder\n Installationsprogramms verwendet wird, verwenden Sie --mac-app-image-sign-identity und/oder\n --mac-installer-sign-identity. Diese Option kann nicht mit\n --mac-app-image-sign-identity oder --mac-installer-sign-identity kombiniert werden. + +help.option.main-class=\ Qualifizierter Name der auszuführenden Anwendungshauptklasse\n Diese Option kann nur bei Angabe von --main-jar verwendet werden. + +help.option.main-jar=\ Die Haupt-JAR-Datei der Anwendung, die die Hauptklasse enthält\n (angegeben als Pfad relativ zum Eingabepfad)\n Es kann entweder die Option --module oder die Option --main-jar angegeben werden, nicht jedoch\n beides. + +help.option.module=\ Das Hauptmodul (und optional die Hauptklasse) der Anwendung\n Dieses Modul muss unter dem Modulpfad gespeichert sein. \n Bei Angabe dieser Option wird das Hauptmodul\n im Java Runtime-Image verknüpft. Es kann entweder die Option --module oder die Option --main-jar\n angegeben werden, nicht jedoch beides. + +help.option.module-path=\ Eine per Doppelpunkt (:) getrennte Pfadliste\n Jeder Pfad ist entweder ein Verzeichnis mit Modulen oder der Pfad zu einer\n modularen JAR-Datei.\n (Jeder Pfad ist absolut oder relativ zum aktuellen Verzeichnis.)\n Diese Option kann mehrmals verwendet werden. +help.option.module-path.win=\ Eine per Semikolon (;) getrennte Pfadliste\n Jeder Pfad ist entweder ein Verzeichnis mit Modulen oder der Pfad zu einer\n modularen JAR-Datei.\n (Jeder Pfad ist absolut oder relativ zum aktuellen Verzeichnis.)\n Diese Option kann mehrmals verwendet werden. + +help.option.name=\ Name der Anwendung und/oder des Packages + +help.option.resource-dir=\ Pfad zum Überschreiben von jpackage-Ressourcen\n Symbole, Vorlagendateien und weitere Ressourcen von jpackage können\n durch Hinzufügen von Ersetzungsressourcen zu diesem Verzeichnis überschrieben werden.\n (absoluter Pfad oder relativ zum aktuellen Verzeichnis) + +help.option.runtime-image=\ Pfad des vordefinierten Laufzeitimages, das in\n das Anwendungsimage kopiert wird\n (absoluter Pfad oder relativ zum aktuellen Verzeichnis)\n Wenn --runtime-image nicht angegeben wird, führt jpackage jlink aus, um\n das Laufzeitimage mit folgenden Optionen zu erstellen:\n --strip-debug, --no-header-files, --no-man-pages und\n --strip-native-commands. + +help.option.temp=\ Pfad eines neuen oder leeren Verzeichnisses zum Erstellen temporärer Dateien\n (absoluter Pfad oder relativ zum aktuellen Verzeichnis)\n Falls angegeben, wird das temporäre Verzeichnis beim Abschließen der Aufgabe\n nicht entfernt und muss manuell entfernt werden. \n Bei fehlender Angabe wird ein temporäres Verzeichnis erstellt und\n beim Abschließen der Aufgabe entfernt. + +help.option.type.win=\ Der zu erstellende Packagetyp\n Gültige Werte sind: {"app-image", "exe", "msi"}\n Bei fehlender Angabe dieser Option wird ein plattformabhängiger\n Standardtyp erstellt. +help.option.type.linux=\ Der zu erstellende Packagetyp\n Gültige Werte sind: {"app-image", "deb", "rpm"}\n Bei fehlender Angabe dieser Option wird ein plattformabhängiger\n Standardtyp erstellt. +help.option.type.mac=\ Der zu erstellende Packagetyp\n Gültige Werte sind: {"app-image", "dmg", "pkg"}\n Bei fehlender Angabe dieser Option wird ein plattformabhängiger\n Standardtyp erstellt. + +help.option.vendor=\ Anbieter der Anwendung + +help.option.verbose=\ Aktiviert Ausgabe im Verbose-Modus + +help.option.version=\ Gibt die Produktversion an den Outputstream aus und beendet den Vorgang. + +help.option.win-console=\ Erstellt einen Konsolenlauncher für die Anwendung. Sollte für\n Anwendungen angegeben werden, die Konsoleninteraktionen erfordern + +help.option.win-dir-chooser=\ Fügt ein Dialogfeld hinzu, in dem der Benutzer das Verzeichnis auswählen kann, in dem\n das Produkt installiert wird. + +help.option.win-help-url=\ URL, unter der der Benutzer weitere Informationen oder technische Unterstützung erhält + +help.option.win-menu=\ Anforderung zum Hinzufügen einer Startmenüverknüpfung für diese Anwendung + +help.option.win-menu-group=\ Startmenügruppe, in der diese Anwendung abgelegt wird + +help.option.win-per-user-install=\ Anforderung zum Ausführen einer Installation pro Benutzer + +help.option.win-shortcut=\ Anforderung zum Hinzufügen einer Desktopverknüpfung für diese Anwendung + +help.option.win-shortcut-prompt=\ Fügt ein Dialogfeld hinzu, in dem der Benutzer auswählen kann, ob Verknüpfungen\n vom Installationsprogramm erstellt werden. + +help.option.win-update-url=\ URL der verfügbaren Anwendungsaktualisierungsinformationen + +help.option.win-upgrade-uuid=\ UUID für Upgrades für dieses Package -MSG_Help_win_launcher=\nPlattformabhängige Option für das Erstellen des Anwendungs-Launchers:\n --win-console\n Erstellt einen Konsolen-Launcher für die Anwendung. Sollte für\n Anwendungen angegeben werden, die Konsoleninteraktionen erfordern\n -MSG_Help_win_install=\ --win-dir-chooser\n Fügt ein Dialogfeld hinzu, in dem der Benutzer das Verzeichnis auswählen kann, in dem\n das Produkt installiert wird.\n --win-help-url \n URL, unter der der Benutzer weitere Informationen oder technische Unterstützung erhält\n --win-menu\n Anforderung zum Hinzufügen einer Startmenüverknüpfung für diese Anwendung\n --win-menu-group \n Startmenügruppe, in der diese Anwendung abgelegt wird\n --win-per-user-install\n Anforderung zum Ausführen einer Installation pro Benutzer\n --win-shortcut\n Anforderung zum Hinzufügen einer Desktopverknüpfung für diese Anwendung\n --win-shortcut-prompt\n Fügt ein Dialogfeld hinzu, in dem der Benutzer auswählen kann, ob Verknüpfungen\n vom Installationsprogramm erstellt werden sollen.\n --win-update-url \n URL verfügbarer Anwendungsupdateinformationen\n --win-upgrade-uuid \n UUID, die mit Upgrades für dieses Package verknüpft ist\n -MSG_Help_win_install_dir=Relativer Unterpfad unter dem Standardinstallationsverzeichnis\n -MSG_Help_mac_install=\ --mac-dmg-content [,...]\n Nimmt den gesamten referenzierten Inhalt in die DMG-Datei auf.\n Diese Option kann mehrmals verwendet werden. \n -MSG_Help_mac_launcher=\ --mac-package-identifier \n Eine ID, die die Anwendung für macOS eindeutig identifiziert\n Standardwert ist der Hauptklassenname.\n Es dürfen nur alphanumerische Zeichen (A-Z, a-z, 0-9), Bindestriche (-)\n und Punkte (.) verwendet werden.\n --mac-package-name \n Name der Anwendung, wie in der Menüleiste angezeigt\n Dieser kann vom Anwendungsnamen abweichen.\n Er darf maximal 15 Zeichen enthalten und muss für die Anzeige\n in der Menüleiste und im Infofenster der Anwendung geeignet sein.\n Standardwert: Anwendungsname.\n --mac-package-signing-prefix \n Beim Signieren des Anwendungspackages wird dieser Wert\n allen zu signierenden Komponenten ohne vorhandene\n Package-ID als Präfix vorangestellt.\n --mac-sign\n Anforderung zum Signieren des Packages oder des vordefinierten\nAnwendungsimages\n --mac-signing-keychain \n Name des Schlüsselbundes für die Suche nach der Signaturidentität\n Bei fehlender Angabe werden die Standardschlüsselbunde verwendet.\n --mac-signing-key-user-name \n Team- oder Benutzernamensteil der Apple-Signaturidentitäten. Um direkt zu steuern,\n welche Signaturidentität zum Signieren eines Anwendungsimages oder\n Installationsprogramms verwendet wird, verwenden Sie --mac-app-image-sign-identity und/oder\n --mac-installer-sign-identity. Diese Option kann nicht mit\n --mac-app-image-sign-identity oder --mac-installer-sign-identity kombiniert werden.\n --mac-app-image-sign-identity \n Zum Signieren des Anwendungsimages verwendete Identität. Dieser Wert wird\n direkt an die Option --sign des Tools "codesign" übergeben. Diese Option kann nicht\n mit --mac-signing-key-user-name kombiniert werden.\n --mac-installer-sign-identity \n Zum Signieren des Installationsprogramms "pkg" verwendete Identität. Dieser Wert wird\n direkt an die Option --sign des Tools "productbuild" übergeben. Diese Option\n kann nicht mit --mac-signing-key-user-name kombiniert werden.\n --mac-app-store\n Gibt an, dass die jpackage-Ausgabe für den\n Mac App Store bestimmt ist.\n --mac-entitlements \n Pfad zu einer Datei mit Berechtigungen, die beim Signieren\n von ausführbaren Dateien und Librarys im Bundle verwendet werden sollen.\n --mac-app-category \n Zeichenfolge für das Erstellen von LSApplicationCategoryType in\n Anwendungs-plist. Standardwert: "utilities".\n -MSG_Help_linux_install=\ --linux-package-name \n Name für das Linux-Package, Standardwert: Anwendungsname\n --linux-deb-maintainer \n Maintainer für .deb-Package\n --linux-menu-group \n Menügruppe, in der diese Anwendung abgelegt wird\n --linux-package-deps \n Erforderliche Packages oder Funktionen für die Anwendung\n --linux-rpm-license-type \n Typ der Lizenz ("License: " der RPM-SPEC-Datei)\n --linux-app-release \n Releasewert der RPM-Datei .spec oder \n Debian-Revisionswert der DEB-Kontrolldatei\n --linux-app-category \n Gruppenwert der RPM-Datei .spec oder \n Abschnittswert der DEB-Kontrolldatei\n --linux-shortcut\n Erstellt einen Shortcut für die Anwendung.\n -MSG_Help_mac_linux_install_dir=Absoluter Pfad des Installationsverzeichnisses der Anwendung\n -MSG_Help_default_install_dir=Absoluter Pfad des Installationsverzeichnisses der Anwendung auf OS X\n oder Linux. Relativer Unterpfad des Installationsverzeichnisses der\n Anwendung wie "Programme" oder "AppData" unter Windows.\n -MSG_Help_no_args=Verwendung: jpackage \nVerwenden Sie jpackage --help (oder -h), um eine Liste möglicher Optionen aufzurufen -MSG_Help_default_app_image=Speicherort des vordefinierten Anwendungsimages, mit dem\n ein installierbares Package erstellt wird\n -MSG_Help_mac_app_image=Speicherort des vordefinierten Anwendungsimages, mit dem\n ein installierbares Package erstellt oder das vordefinierte\n Anwendungsimage signiert wird\n -MSG_Help_mac_sign_sample_usage=\ Vordefiniertes Anwendungsimage signieren:\n jpackage --type app-image --app-image \\\n --mac-sign [...]\n Hinweis: In diesem Modus sind nur die folgenden zusätzlichen Optionen zulässig:\n Das Set der zusätzlichen Mac-Signaturoptionen und --verbose\n diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/HelpResources_ja.properties b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/HelpResources_ja.properties index cae6ae216d3..ca606dda9f8 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/HelpResources_ja.properties +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/HelpResources_ja.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2017, 2025, 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,22 +24,163 @@ # # -MSG_Help=使用方法: jpackage \n\n使用例:\n--------------\n ホスト・システムに適したアプリケーション・パッケージを生成します。\n モジュラ・アプリケーションの場合:\n jpackage -n name -p modulePath -m moduleName/className\n 非モジュラ・アプリケーションの場合:\n jpackage -i inputDir -n name \\\n --main-class className --main-jar myJar.jar\n 事前作成されたアプリケーション・イメージから:\n jpackage -n name --app-image appImageDir\n アプリケーション・イメージの生成:\n モジュラ・アプリケーションの場合:\n jpackage --type app-image -n name -p modulePath \\\n -m moduleName/className\n 非モジュラ・アプリケーションの場合:\n jpackage --type app-image -i inputDir -n name \\\n --main-class className --main-jar myJar.jar\n jlinkに独自のオプションを指定するには、jlinkを別個に実行します。\n jlink --output appRuntimeImage -p modulePath \\\n --add-modules moduleName \\\n --no-header-files [...]\n jpackage --type app-image -n name \\\n -m moduleName/className --runtime-image appRuntimeImage\n Javaランタイム・パッケージを生成します。\n jpackage -n name --runtime-image \n{6}\n一般的なオプション:\n @ \n ファイルからの読取りオプションおよびモード \n このオプションは複数回使用できます。\n --type -t \n 作成するパッケージのタイプ\n 有効な値: {1} \n このオプションが指定されていない場合、プラットフォーム依存の\n デフォルト・タイプが作成されます\n --app-version \n アプリケーションおよびパッケージのバージョン\n --copyright \n アプリケーションのコピーライト\n --description \n アプリケーションの説明\n --help -h \n 使用方法テキストと現在のプラットフォームの有効なオプションのリストと説明を\n 出力ストリームに出力して、終了します\n --icon \n アプリケーション・パッケージのアイコンのパス\n (絶対パスまたは現在のディレクトリからの相対パス)\n \ ---name -n \n アプリケーションおよびパッケージの名前\n --dest -d \n 生成された出力ファイルが配置されるパス\n (絶対パスまたは現在のディレクトリからの相対パス)\n デフォルトは現在の作業ディレクトリです。\n --temp \n 一時ファイルの作成に使用される新規または空のディレクトリのパス\n (絶対パスまたは現在のディレクトリからの相対パス)\n 指定した場合、タスク完了時に一時ディレクトリは削除されないため\n 手動で削除する必要があります\n 指定しなかった場合、一時ディレクトリが作成され\n タスク完了時に削除されます。\n --vendor \n アプリケーションのベンダー\n --verbose\n 詳細な出力を有効にします\n --version\n 製品バージョンを出力ストリームに出力して終了します\n\nランタイム・イメージを作成するためのオプション:\n --add-modules [,...]\n 追加するモジュールのカンマ(",")区切りリスト\n このモジュール・リストとメイン・モジュール(指定した場合)\n が--add-module引数としてjlinkに渡されます。\n 指定しなかった場合、メイン・モジュールのみ(--moduleが\n 指定された場合)、またはデフォルトのモジュール・セット(--main-jarが \n 指定された場合)が使用されます。\n このオプションは複数回使用できます。\n --module-path -p ...\n パスの{0}区切りリスト\n 各パスは、モジュールのディレクトリまたは\n モジュラjarへのパスです。\n (各パスは、絶対パスまたは現在のディレクトリからの相対パスです。)\n このオプションは複数回使用できます。\n --jlink-options \n jlinkに渡すオプションのスペース区切りのリスト \n 指定しない場合、"--strip-native-commands \n --strip-debug \ ---no-man-pages --no-header-files"。 \n このオプションは複数回使用できます。\n --runtime-image \n アプリケーション・イメージにコピーされる、事前定義済みのランタイム・イメージ\n のパス\n (絶対パスまたは現在のディレクトリからの相対パス)\n --runtime-imageが指定されていない場合、jpackageはjlinkを実行し、\n 次のオプションを使用してランタイム・イメージを作成します:\n --strip-debug、--no-header-files、--no-man-pagesおよび\n --strip-native-commands。\n\nアプリケーション・イメージを作成するためのオプション:\n --input -i \n パッケージ化するファイルを含む入力ディレクトリへのパス\n (絶対パスまたは現在のディレクトリからの相対パス)\n 入力ディレクトリのすべてのファイルは、アプリケーション・イメージに\n パッケージ化されます。\n --app-content [,...]\n ファイルまたはディレクトリ(あるいは両方)のパスのカンマ区切りのリスト\n アプリケーション・ペイロードに追加します。\n このオプションは複数回使用できます。\n\nアプリケーション・ランチャを作成するためのオプション:\n --add-launcher =\n ランチャの名前、およびキー、値のペアのリスト\n を含むプロパティ・ファイルへのパス\n (絶対パスまたは現在のディレクトリからの相対パス)\n キー"module"、"main-jar"、"main-class"、"description"、\n "arguments"、"java-options"、"app-version"、"icon"、\n "launcher-as-service"、\n "win-console"、"win-shortcut"、"win-menu"、\n "linux-app-category"および"linux-shortcut"を使用できます。\n これらのオプションを元のコマンドライン・オプションに追加するか、これらのオプションを\n 使用して元のコマンドライン・オプションを上書きして、追加の代替ランチャを作成します。\n \ -メイン・アプリケーション・ランチャはコマンドライン・オプションから作成されます。\n このオプションを使用して追加の代替ランチャを作成でき、\n このオプションを複数回使用して\n 複数の追加のランチャを作成できます。 \n --arguments

      \n ランチャにコマンド・ライン引数が指定されていない場合にメイン・クラスに渡す\n コマンド・ライン引数\n このオプションは複数回使用できます。\n --java-options \n Javaランタイムに渡すオプション\n このオプションは複数回使用できます。\n --main-class \n 実行するアプリケーション・メイン・クラスの修飾名\n このオプションを使用できるのは、--main-jarが指定されている場合だけです。\n --main-jar
      \n メイン・クラスを含む、アプリケーションのメインJAR\n (入力パスからの相対パスとして指定)\n --moduleまたは--main-jarオプションを指定できますが、両方は\n 指定できません。\n --module -m [/
      ]\n アプリケーションのメイン・モジュール(およびオプションでメイン・クラス)\n このモジュールは、モジュール・パスに置かれている必要があります。\n このオプションが指定されている場合、メイン・モジュールは\n Javaランタイム・イメージ内でリンクされます。--moduleまたは--main-jar\n オプションを指定できますが、両方は指定できません。\n{2}\nアプリケーション・パッケージを作成するためのオプション:\n --about-url \n アプリケーションのホームページのURL\n --app-image \n {5} (絶対パスまたは現在のディレクトリからの相対パス)\n --file-associations \n キー、値のペアのリストを含むプロパティ・ファイルへのパス\n \ -(絶対パスまたは現在のディレクトリからの相対パス)\n キー"extension"、"mime-type"、"icon"、"description"\n を使用して関連付けを記述できます。\n このオプションは複数回使用できます。\n --install-dir \n {4} --license-file \n ライセンス・ファイルへのパス\n (絶対パスまたは現在のディレクトリからの相対パス)\n --resource-dir \n オーバーライドjpackageリソースへのパス\n アイコン、テンプレート・ファイルおよびjpackageのその他のリソースは、\n このディレクトリに置換リソースを追加することでオーバーライドできます。\n (絶対パスまたは現在のディレクトリからの相対パス)\n --runtime-image \n インストールする事前定義済みのランタイム・イメージのパス\n (絶対パスまたは現在のディレクトリからの相対パス)\n ランタイム・パッケージの作成時には、オプションが必要です。\n --launcher-as-service\n 次として登録するインストーラの作成をリクエストします: \n バックグラウンド・サービス・タイプ・アプリケーションとしてのメイン・アプリケーション・ランチャ。\n\nアプリケーション・パッケージを作成するためのプラットフォーム依存オプション:\n{3} +help.header=使用方法: jpackage + +help.short=利用可能なオプションのリストについては、jpackage --help (or -h)を使用します + +help.option-group.sample.create-native-package=\ ホスト・システムに適したアプリケーション・パッケージを生成します:\n モジュラ・アプリケーションの場合:\n jpackage -n name -p modulePath -m moduleName/className\n 非モジュラ・アプリケーションの場合:\n jpackage -i inputDir -n name \\\n --main-class className --main-jar myJar.jar\n 事前作成されたアプリケーション・イメージから:\n jpackage -n name --app-image appImageDir + +help.option-group.sample.create-app-image=\ アプリケーション・イメージの生成:\n モジュラ・アプリケーションの場合:\n jpackage --type app-image -n name -p modulePath \\\n -m moduleName/className\n 非モジュラ・アプリケーションの場合:\n jpackage --type app-image -i inputDir -n name \\\n --main-class className --main-jar myJar.jar\n jlinkに独自のオプションを指定するには、jlinkを別個に実行します:\n jlink --output appRuntimeImage -p modulePath \\\n --add-modules moduleName \\\n --no-header-files [...]\n jpackage --type app-image -n name \\\n -m moduleName/className --runtime-image appRuntimeImage + +help.option-group.sample.create-runtime-installer=\ Javaランタイム・パッケージを生成します:\n jpackage -n name --runtime-image + +help.option-group.sample.sign-app-image=\ 事前定義済みアプリケーション・イメージへの署名:\n jpackage --type app-image --app-image \\\n --mac-sign [...]\n ノート: このモードで許可される唯一の追加オプション:\n 追加のmac署名オプションのセットおよび--verbose + +help.option-group.sample=使用例 +help.option-group.generic=一般的なオプション +help.option-group.runtime-image=ランタイム・イメージを作成するためのオプション +help.option-group.app-image=アプリケーション・イメージを作成するためのオプション +help.option-group.launcher=アプリケーション・ランチャを作成するためのオプション +help.option-group.launcher-platform=アプリケーション・ランチャを作成するためのプラットフォーム依存オプション +help.option-group.package=アプリケーション・パッケージを作成するためのオプション +help.option-group.package-platform=アプリケーション・パッケージを作成するためのプラットフォーム依存オプション + +help.option.argument-file=\ ファイルからの読取りオプションまたはモード(あるいはその両方)\n このオプションは複数回使用できます。 + +help.option.about-url=\ アプリケーションのホームページのURL + +help.option.add-launcher.win=\ ランチャの名前、およびキー、値のペアのリスト\n を含むプロパティ・ファイルへのパス\n (絶対パスまたは現在のディレクトリからの相対パス)\n キー"arguments"、"description"、"icon"、"java-options"、\n "launcher-as-service"、"main-class"、"main-jar"、"module"、\n "win-console"、"win-menu"、"win-shortcut"が使用できます。\n これらのオプションを元のコマンドライン・オプションに追加するか、これらのオプションを\n 使用して元のコマンドライン・オプションを上書きして、追加の代替ランチャを作成します。\n メイン・アプリケーション・ランチャはコマンドライン・オプションから作成されます。\n このオプションを使用して追加の代替ランチャを作成でき、\n このオプションを複数回使用して\n 複数の追加のランチャを作成できます。 + +help.option.add-launcher.linux=\ ランチャの名前、およびキー、値のペアのリスト\n を含むプロパティ・ファイルへのパス\n (絶対パスまたは現在のディレクトリからの相対パス)\n キー"arguments"、"description"、"icon"、"java-options"、\n "launcher-as-service"、"linux-shortcut"、"main-class"、"main-jar"、\n "module"が使用できます。\n これらのオプションを元のコマンドライン・オプションに追加するか、これらのオプションを\n 使用して元のコマンドライン・オプションを上書きして、追加の代替ランチャを作成します。\n メイン・アプリケーション・ランチャはコマンドライン・オプションから作成されます。\n このオプションを使用して追加の代替ランチャを作成でき、\n このオプションを複数回使用して\n 複数の追加のランチャを作成できます。 + +help.option.add-launcher.mac=\ ランチャの名前、およびキー、値のペアのリスト\n を含むプロパティ・ファイルへのパス\n (絶対パスまたは現在のディレクトリからの相対パス)\n キー"arguments"、"description"、"icon"、"java-options"、\n "launcher-as-service"、"main-class"、"main-jar"、"module"\n が使用できます。\n これらのオプションを元のコマンドライン・オプションに追加するか、これらのオプションを\n 使用して元のコマンドライン・オプションを上書きして、追加の代替ランチャを作成します。\n メイン・アプリケーション・ランチャはコマンドライン・オプションから作成されます。\n このオプションを使用して追加の代替ランチャを作成でき、\n このオプションを複数回使用して\n 複数の追加のランチャを作成できます。 + +help.option.add-modules=\ 追加するモジュールのカンマ(",")区切りリスト\n このモジュール・リストとメイン・モジュール(指定した場合)\n が--add-module引数としてjlinkに渡されます。\n 指定しなかった場合、メイン・モジュールのみ(--moduleが\n 指定された場合)、またはデフォルトのモジュール・セット(--main-jarが\n 指定された場合)が使用されます。\n このオプションは複数回使用できます。 + +help.option.app-content=\ アプリケーション・ペイロードに追加するファイルまたはディレクトリ(あるいはその両方)\n のパスのカンマ区切りのリスト。\n このオプションは複数回使用できます。 + +help.option.app-content.mac=\ アプリケーション・ペイロードに追加するファイルまたはディレクトリ(あるいはその両方)\n のパスのカンマ区切りのリスト。\n このオプションは複数回使用できます。\n ノート: 値は"Resources"サブディレクトリ\n (またはアプリケーション・バンドルの"Contents"ディレクトリで有効なその他のディレクトリ)\n を含むディレクトリである必要があります。それ以外の場合は、jpackageによって無効なアプリケーション・バンドルが生成される場合があり、\n コード署名または公証(あるいはその両方)に失敗する\n 場合があります。 + +help.option.app-image=\ インストール可能なパッケージの作成に使用する、事前定義済\n アプリケーション・イメージの場所\n (絶対パスまたは現在のディレクトリからの相対パス) + +help.option.app-image.mac=\ インストール可能なパッケージの作成または事前定義済\n アプリケーション・イメージの署名に使用する、事前定義済\n アプリケーション・イメージの場所\n (絶対パスまたは現在のディレクトリからの相対パス) + +help.option.app-version=\ アプリケーションおよびパッケージのバージョン + +help.option.arguments=\ コマンドライン引数がランチャに指定されていない場合に、\n メイン・クラスに渡されるコマンドライン引数\n このオプションは複数回使用できます。 + +help.option.copyright=\ アプリケーションのコピーライト + +help.option.description=\ アプリケーションの説明 + +help.option.dest=\ 生成された出力ファイルが配置されるパス\n (絶対パスまたは現在のディレクトリからの相対パス)\n 現在の作業ディレクトリにデフォルト設定されています。 + +help.option.file-associations=\ キー、値のペアのリストを含むプロパティ・ファイルへのパス\n (絶対パスまたは現在のディレクトリからの相対パス)\n キー"extension"、"mime-type"、"icon"、"description"\n を使用して関連付けを記述できます。\n このオプションは複数回使用できます。 + +help.option.help=\ 使用方法テキストと現在のプラットフォームの有効なオプションのリストと説明を\n 出力ストリームに出力して、終了します + +help.option.icon=\ アプリケーション・パッケージのアイコンのパス\n (絶対パスまたは現在のディレクトリからの相対パス) + +help.option.input=\ パッケージ化するファイルを含む入力ディレクトリのパス\n (絶対パスまたは現在のディレクトリからの相対パス)\n 入力ディレクトリのすべてのファイルは、アプリケーション・イメージに\n パッケージ化されます。 + +help.option.install-dir=\ アプリケーションのインストール・ディレクトリの絶対パス + +help.option.install-dir.win=\ "プログラム・ファイル"または"AppData"など、\n アプリケーションのインストール場所の相対サブパス。 + +help.option.installer-runtime-image=\ インストールする事前定義済のランタイム・イメージのパス\n (絶対パスまたは現在のディレクトリからの相対パス)\n ランタイム・パッケージの作成時には、オプションが必要です。 + +help.option.java-options=\ Javaランタイムに渡すオプション\n このオプションは複数回使用できます。 + +help.option.jlink-options=\ jlinkに渡すオプションのスペース区切りのリスト\n 指定しない場合、"--strip-native-commands\n --strip-debug --no-man-pages --no-header-files"にデフォルト設定されます。\n このオプションは複数回使用できます。 + +help.option.launcher-as-service=\ バックグラウンド・サービス・タイプ・アプリケーションとしてメイン・\n アプリケーション・ランチャを登録するインストーラの作成をリクエストします。 + +help.option.license-file=\ ライセンス・ファイルへのパス\n (絶対パスまたは現在のディレクトリからの相対パス) + +help.option.linux-app-category=\ RPM .specファイルのグループ値または\n DEB制御ファイルのセクション値 + +help.option.linux-app-release=\ RPM .specファイルのリリース値または\n DEB制御ファイルのDebianリビジョン値 + +help.option.linux-deb-maintainer=\ .debパッケージのメンテナ + +help.option.linux-menu-group=\ このアプリケーションを配置するメニュー・グループ + +help.option.linux-package-deps=\ アプリケーションに必要なパッケージまたは機能 + +help.option.linux-package-name=\ Linuxパッケージの名前。アプリケーション名にデフォルト設定されています + +help.option.linux-rpm-license-type=\ ライセンスのタイプ(RPM .specの"License: ") + +help.option.linux-shortcut=\ アプリケーションのショートカットを作成します。 + +help.option.mac-app-category=\ アプリケーションplistのLSApplicationCategoryTypeの構築に\n 使用する文字列。デフォルト値は"utilities"です。 + +help.option.mac-app-image-sign-identity=\ アプリケーション・イメージの署名に使用するアイデンティティ。この値は直接\n "codesign"ツールの--signオプションに渡されます。このオプションは\n --mac-signing-key-user-nameと組み合せることはできません。 + +help.option.mac-app-store=\ jpackage出力がMac App Store用であること\n を示します。 + +help.option.mac-dmg-content=\ dmgに参照されたコンテンツをすべて含めます。\n このオプションは複数回使用できます。 + +help.option.mac-entitlements=\ バンドルの実行可能ファイルおよびライブラリの署名時に\n 使用する権限を含むファイルのパス。 + +help.option.mac-installer-sign-identity=\ "pkg"インストーラの署名に使用するアイデンティティ。この値は直接\n "productbuild"ツールの--signオプションに渡されます。このオプションは\n --mac-signing-key-user-nameと組み合せることはできません。 + +help.option.mac-package-identifier=\ MacOSのアプリケーションを一意に識別する識別子。\n メイン・クラス名にデフォルト設定されています。\n 英数字(A-Z、a-z、0-9)、ハイフン(-)、\n およびピリオド(.)のみを使用できます。 + +help.option.mac-package-name=\ メニュー・バーに表示されるアプリケーションの名前\n アプリケーション名とは異なります。\n この名前は16文字未満にする必要があり、メニュー・バー\n およびアプリケーション情報ウィンドウに表示するのに適している必要があります。\n アプリケーション名にデフォルト設定されています。 + +help.option.mac-package-signing-prefix=\ アプリケーション・パッケージに署名する際、既存のパッケージIDのない\n 署名が必要なすべてのコンポーネントに、\n この値が接頭辞として付けられます。 + +help.option.mac-sign=\ パッケージまたは事前定義済アプリケーション・イメージに署名するよう\n リクエストします。 + +help.option.mac-signing-keychain=\ 署名アイデンティティを検索するキーチェーンの名前\n 指定しなかった場合、標準のキーチェーンが使用されます。 + +help.option.mac-signing-key-user-name=\ Apple署名アイデンティティのチームまたはユーザー名部分。\n アプリケーション・イメージまたはインストーラの署名に使用する署名アイデンティティの\n 直接制御には、--mac-app-image-sign-identityまたは\n --mac-installer-sign-identity(あるいはその両方)を使用します。このオプションは\n --mac-app-image-sign-identityまたは--mac-installer-sign-identityと組み合せることはできません。 + +help.option.main-class=\ 実行するアプリケーション・メイン・クラスの修飾名\n このオプションを使用できるのは、--main-jarが指定されている場合だけです。 + +help.option.main-jar=\ メイン・クラスを含む、アプリケーションのメインJAR\n (入力パスからの相対パスとして指定)\n --moduleまたは--main-jarオプションを指定できますが、両方は\n 指定できません。 + +help.option.module=\ アプリケーションのメイン・モジュール(およびオプションでメイン・クラス)\n このモジュールは、モジュール・パスに置かれている必要があります。\n このオプションが指定されている場合、メイン・モジュールは\n Javaランタイム・イメージ内でリンクされます。--moduleまたは--main-jar\n オプションを指定できますが、両方は指定できません。 + +help.option.module-path=\ :で区切られたパスのリスト\n 各パスは、モジュールのディレクトリまたは\n モジュラjarへのパスです。\n (各パスは、絶対パスまたは現在のディレクトリからの相対パスです。)\n このオプションは複数回使用できます。 +help.option.module-path.win=\ ;で区切られたパスのリスト\n 各パスは、モジュールのディレクトリまたは\n モジュラjarへのパスです。\n (各パスは、絶対パスまたは現在のディレクトリからの相対パスです。)\n このオプションは複数回使用できます。 + +help.option.name=\ アプリケーションおよびパッケージの名前 + +help.option.resource-dir=\ オーバーライドjpackageリソースへのパス\n アイコン、テンプレート・ファイルおよびjpackageのその他のリソースは、\n このディレクトリに置換リソースを追加することでオーバーライドできます。\n (絶対パスまたは現在のディレクトリからの相対パス) + +help.option.runtime-image=\ アプリケーション・イメージにコピーされる、事前定義済のランタイム・イメージ\n のパス\n (絶対パスまたは現在のディレクトリからの相対パス)\n --runtime-imageが指定されていない場合、jpackageはjlinkを実行し、\n 次のオプションを使用してランタイム・イメージを作成します:\n --strip-debug、--no-header-files、--no-man-pagesおよび\n --strip-native-commands。 + +help.option.temp=\ 一時ファイルの作成に使用される新規または空のディレクトリのパス\n (絶対パスまたは現在のディレクトリからの相対パス)\n 指定した場合、タスク完了時に一時ディレクトリは削除されないため\n 手動で削除する必要があります。\n 指定しなかった場合、一時ディレクトリが作成され\n タスク完了時に削除されます。 + +help.option.type.win=\ 作成するパッケージのタイプ\n 有効な値: {"app-image", "exe", "msi"}\n このオプションを指定しない場合、プラットフォーム依存の\n デフォルト・タイプが作成されます。 +help.option.type.linux=\ 作成するパッケージのタイプ\n 有効な値: {"app-image", "deb", "rpm"}\n このオプションを指定しない場合、プラットフォーム依存の\n デフォルト・タイプが作成されます。 +help.option.type.mac=\ 作成するパッケージのタイプ\n 有効な値: {"app-image", "dmg", "pkg"}\n このオプションを指定しない場合、プラットフォーム依存の\n デフォルト・タイプが作成されます。 + +help.option.vendor=\ アプリケーションのベンダー + +help.option.verbose=\ 詳細な出力を有効にします + +help.option.version=\ 製品バージョンを出力ストリームに出力して終了します + +help.option.win-console=\ アプリケーションのコンソール・ランチャを作成します。コンソール・\n インタラクションが必要なアプリケーションに指定する必要があります + +help.option.win-dir-chooser=\ 製品をインストールするディレクトリをユーザーが\n 選択できるダイアログを追加します。 + +help.option.win-help-url=\ ユーザーが詳細情報または技術サポートを取得できるURL + +help.option.win-menu=\ このアプリケーションのスタート・メニューのショートカットを追加するリクエスト + +help.option.win-menu-group=\ このアプリケーションを配置するスタート・メニュー・グループ + +help.option.win-per-user-install=\ ユーザーごとにインストールを実行するリクエスト + +help.option.win-shortcut=\ このアプリケーションのデスクトップのショートカットを追加するリクエスト + +help.option.win-shortcut-prompt=\ ショートカットをインストーラで作成するかどうかをユーザーが\n 選択できるダイアログを追加します。 + +help.option.win-update-url=\ 使用可能なアプリケーション更新情報のURL + +help.option.win-upgrade-uuid=\ このパッケージのアップグレードに関連付けられているUUID -MSG_Help_win_launcher=\nアプリケーション・ランチャを作成するためのプラットフォーム依存オプション:\n --win-console\n アプリケーションのコンソール・ランチャを作成します。コンソール・\n インタラクションが必要なアプリケーションに指定する必要があります\n -MSG_Help_win_install=\ --win-dir-chooser\n ユーザーが製品をインストールするディレクトリを選択するための\n ダイアログを追加します。\n --win-help-url \n ユーザーが詳細情報または技術的なサポートを取得できるURL\n --win-menu\n このアプリケーションのスタート・メニュー・ショートカットを追加するようにリクエストします\n --win-menu-group \n このアプリケーションを配置するスタート・メニュー・グループ\n --win-per-user-install\n ユーザーごとにインストールを実行するようにリクエストします\n --win-shortcut\n このアプリケーションのデスクトップ・ショートカットを追加するようにリクエストします\n --win-shortcut-prompt\n ショートカットをインストーラで作成するかどうかをユーザーが選択できるようにする\n ダイアログを追加します。\n --win-update-url \n 使用可能なアプリケーションの更新情報のURL\n --win-upgrade-uuid \n このパッケージのアップグレードに関連付けられたUUID\n -MSG_Help_win_install_dir=デフォルトのインストール場所の下の相対サブパス\n -MSG_Help_mac_install=\ --mac-dmg-content [,...]\n dmgに参照されたコンテンツをすべて含めます。\n このオプションは複数回使用できます。 \n -MSG_Help_mac_launcher=\ --mac-package-identifier \n macOSのアプリケーションを一意に識別するID\n メイン・クラス名にデフォルト設定されています。\n 英数字(A-Z、a-z、0-9)、ハイフン(-)およびピリオド(.)文字のみ\n 使用できます。\n --mac-package-name \n メニュー・バーに表示されるアプリケーションの名前\n アプリケーション名とは異なります。\n この名前は16文字未満にする必要があり、メニュー・バーおよびアプリケーション情報ウィンドウに\n 表示するのに適している必要があります。\n アプリケーション名にデフォルト設定されています。\n --mac-package-signing-prefix \n アプリケーション・パッケージに署名する際、\n 既存のパッケージIDのない署名が必要なすべてのコンポーネントに、\n この値が接頭辞として付けられます。\n --mac-sign\n パッケージまたは事前定義済アプリケーション・イメージに署名するよう\n リクエストします。\n --mac-signing-keychain \n 署名アイデンティティを検索するキーチェーンの名前\n 指定しなかった場合、標準のキーチェーンが使用されます。\n --mac-signing-key-user-name \n Apple署名アイデンティティのチームまたはユーザー名部分。\n アプリケーション・イメージまたはインストーラの署名に使用する署名アイデンティティの\n 直接制御には、--mac-app-image-sign-identityまたは\n --mac-installer-sign-identity(あるいは両方)を使用します。このオプションは\n --mac-app-image-sign-identityまたは--mac-installer-sign-identityと組み合せることはできません。\n --mac-app-image-sign-identity \n アプリケーション・イメージの署名に使用するアイデンティティ。この値は直接\n "codesign"ツールの--signオプションに渡されます。このオプションは\n \ ---mac-signing-key-user-nameと組み合せることはできません。\n --mac-installer-sign-identity \n "pkg"インストーラの署名に使用するアイデンティティ。この値は直接\n "productbuild"ツールの--signオプションに渡されます。このオプションは\n --mac-signing-key-user-nameと組み合せることはできません。\n --mac-app-store\n jpackage出力がMac App Store用であること\n を示します。\n --mac-entitlements \n バンドルの実行可能ファイルおよびライブラリの署名時に\n 使用する権限を含むファイルのパス。\n --mac-app-category \n アプリケーションのplistのLSApplicationCategoryTypeを生成する際に使用する文字列。\n デフォルト値は"utilities"です。\n -MSG_Help_linux_install=\ --linux-package-name \n Linuxパッケージの名前。アプリケーション名にデフォルト設定されています\n --linux-deb-maintainer \n .debパッケージのMaintainer\n --linux-menu-group \n このアプリケーションが配置されているメニュー・グループ\n --linux-package-deps \n アプリケーションに必要なパッケージまたは機能\n --linux-rpm-license-type \n ライセンスのタイプ(RPM .specの"License: ")\n --linux-app-release \n RPM .specファイルのリリース値または\n DEBコントロール・ファイルのDebianリビジョン値。\n --linux-app-category \n RPM .specファイルのグループ値または \n DEBコントロール・ファイルのセクション値\n --linux-shortcut\n アプリケーションのショートカットを作成します。\n -MSG_Help_mac_linux_install_dir=アプリケーションのインストール・ディレクトリの絶対パス\n -MSG_Help_default_install_dir=OS XまたはLinux上のアプリケーションのインストール・ディレクトリの絶対パス。\n "プログラム・ファイル"や"AppData"など、Windows上のアプリケーションの\n インストール場所の相対サブパス。\n -MSG_Help_no_args=使用方法: jpackage \n利用可能なオプションのリストについては、jpackage --help (or -h)を使用します -MSG_Help_default_app_image=インストール可能なパッケージの作成に使用する、事前定義済み\n アプリケーション・イメージの場所\n -MSG_Help_mac_app_image=インストール可能なパッケージの作成または事前定義済みアプリケーション・\n イメージへの署名に使用する、事前定義済みアプリケーション・\n イメージの場所\n -MSG_Help_mac_sign_sample_usage=\ 事前定義済みアプリケーション・イメージへの署名:\n jpackage --type app-image --app-image \\\n --mac-sign [...]\n ノート: このモードで許可される唯一の追加オプション:\n 追加のmac署名オプションのセットおよび--verbose\n diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/HelpResources_zh_CN.properties b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/HelpResources_zh_CN.properties index 6adf62ef1f8..ac72c67ee2f 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/HelpResources_zh_CN.properties +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/HelpResources_zh_CN.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2017, 2025, 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,20 +24,163 @@ # # -MSG_Help=用法:jpackage \n\n示例用法:\n--------------\n 生成适合主机系统的应用程序包:\n 对于模块化应用程序:\n jpackage -n name -p modulePath -m moduleName/className\n 对于非模块化应用程序:\n jpackage -i inputDir -n name \\\n --main-class className --main-jar myJar.jar\n 从预构建的应用程序映像:\n jpackage -n name --app-image appImageDir\n 生成应用程序映像:\n 对于模块化应用程序:\n jpackage --type app-image -n name -p modulePath \\\n -m moduleName/className\n 对于非模块化应用程序:\n jpackage --type app-image -i inputDir -n name \\\n --main-class className --main-jar myJar.jar\n 要为 jlink 提供您自己的选项,请单独运行 jlink:\n jlink --output appRuntimeImage -p modulePath \\\n --add-modules moduleName \\\n --no-header-files [...]\n jpackage --type app-image -n name \\\n -m moduleName/className --runtime-image appRuntimeImage\n 生成 Java 运行时程序包:\n jpackage -n name --runtime-image \n{6}\n一般选项:\n @ \n 从文件读取选项和/或模式 \n 可以多次使用此选项。\n --type -t \n 要创建的程序包的类型\n 有效值为:{1} \n 如果未指定此选项,则将创建与平台相关的\n 默认类型。\n --app-version \n 应用程序和/或程序包的版本\n --copyright \n 应用程序的版权\n --description \n 应用程序的说明\n --help -h \n 将用法文本输出到输出流并退出,用法文本中包含\n 适用于当前平台的每个有效选项的列表和说明\n --icon \n 应用程序包图标的路径\n (绝对路径或相对于当前目录的路径)\n --name -n \n 应用程序和/或程序包的名称\n --dest -d \n 用来放置所生成的输出文件的路径\n (绝对路径或相对于当前目录的路径)\n 默认为当前的工作目录。\n --temp \n 用来创建临时文件的新目录或空白目录的路径\n (绝对路径或相对于当前目录的路径)\n 如果指定,则在任务完成时将不删除临时目录,\n 必须手动删除临时目录。\n 如果未指定,则将创建一个临时目录,\n \ -并在任务完成时删除该临时目录。\n --vendor \n 应用程序的供应商\n --verbose\n 启用详细的输出\n --version\n 将产品版本输出到输出流并退出。\n\n用来创建运行时映像的选项:\n --add-modules <模块名称>[,<模块名称>...]\n 要添加的模块的逗号 (",") 分隔列表\n 此模块列表连同主模块(如果指定)\n 将作为 --add-module 参数传递到 jlink。\n 如果未指定,则仅使用主模块(如果指定了 --module),\n 或者使用默认的模块集(如果指定了 \n --main-jar)。\n 可以多次使用此选项。\n --module-path -p ...\n 路径的 {0} 分隔列表\n 每个路径要么是模块的目录,要么是\n 模块化 jar 的路径。\n (每个路径可以是绝对路径,也可以是相对于当前目录的路径。)\n 可以多次使用此选项。\n --jlink-options \n 要传递给 jlink 的选项列表(用空格分隔) \n 如果未指定,则默认为 "--strip-native-commands \n --strip-debug --no-man-pages --no-header-files"。 \n 可以多次使用此选项。\n --runtime-image \n 将复制到应用程序映像的预定义\n 运行时映像的路径\n (绝对路径或相对于当前目录的路径)\n 如果未指定 --runtime-image,jpackage 将运行 jlink 以\n 使用如下选项创建运行时映像:\n --strip-debug、--no-header-files、--no-man-pages 和 \n --strip-native-commands。\n\n用来创建应用程序映像的选项:\n --input -i \n 包含要打包的文件的输入目录的路径\n (绝对路径或相对于当前目录的路径)\n 输入目录中的所有文件将打包到\n 应用程序映像中。\n --app-content [,...]\n 要添加到应用程序有效负载中的文件和/或\n 目录的逗号分隔路径列表。\n 此选项可以多次使用。\n\n用来创建应用程序启动程序的选项:\n --add-launcher =\n 启动程序的名称和包含关键字-值对列表的\n 属性文件的路径\n (绝对路径或相对于当前目录的路径)\n \ -可以使用关键字 "module"、"main-jar"、"main-class"、"description"、\n "arguments"、"java-options"、"app-version"、"icon"、\n "launcher-as-service"、\n "win-console"、"win-shortcut"、"win-menu"、\n "linux-app-category" 和 "linux-shortcut"。\n 这些选项将添加到原始命令行选项中或者用来覆盖\n 原始命令行选项,以构建额外的替代启动程序。\n 将从命令行选项构建主应用程序启动程序。\n 可以使用此选项构建额外的替代启动程序,\n 可以多次使用此选项来构建\n 多个额外的启动程序。 \n --arguments
      \n 在没有为启动程序提供命令行参数时,\n 要传递到主类的命令行参数\n 可以多次使用此选项。\n --java-options \n 要传递到 Java 运行时的选项\n 可以多次使用此选项。\n --main-class \n 要执行的应用程序主类的限定名称\n 只有在指定了 --main-jar 时才能使用此选项。\n --main-jar
      \n 应用程序的主 JAR;包含主类\n (指定为相对于输入路径的路径)\n 可以指定 --module 或 --main-jar 选项,但是不能同时指定\n 两者。\n --module -m [/
      ]\n 应用程序的主模块(以及可选的主类)\n 此模块必须位于模块路径中。\n 如果指定了此选项,则将在 Java 运行时映像中\n 链接主模块。可以指定 --module 或 --main-jar 选项,\n 但是不能同时指定这两个选项。\n{2}\n用来创建应用程序包的选项:\n --about-url \n 应用程序主页的 URL\n --app-image \n {5} (绝对路径或相对于当前目录的路径)\n --file-associations \n 包含关键字-值对列表的属性文件的路径\n (绝对路径或相对于当前目录的路径)\n 可以使用关键字 "extension"、"mime-type"、"icon" 和 "description" \n 来描述此关联。\n 可以多次使用此选项。\n --install-dir \n {4} --license-file \n 许可证文件的路径\n (绝对路径或相对于当前目录的路径)\n --resource-dir \n 覆盖 jpackage 资源的路径\n \ -可以通过向该目录中添加替代资源来覆盖 jpackage 的\n 图标、模板文件和其他资源。\n (绝对路径或相对于当前目录的路径)\n --runtime-image \n 要安装的预定义运行时映像的路径\n (绝对路径或相对于当前目录的路径)\n 在创建运行时程序包时需要使用选项。\n --launcher-as-service\n 请求创建安装程序,以将主\n 应用程序启动程序注册为后台服务类型应用程序。\n\n用来创建应用程序包的与平台相关的选项:\n{3} +help.header=用法:jpackage + +help.short=使用 jpackage --help(或 -h)可获取可能选项的列表 + +help.option-group.sample.create-native-package=\ 生成适用于主机系统的应用程序包:\n 对于模块化应用程序:\n jpackage -n name -p modulePath -m moduleName/className\n 对于非模块化应用程序:\n jpackage -i inputDir -n name \\\n --main-class className --main-jar myJar.jar\n 从预构建的应用程序映像:\n jpackage -n name --app-image appImageDir + +help.option-group.sample.create-app-image=\ 生成应用程序映像:\n 对于模块化应用程序:\n jpackage --type app-image -n name -p modulePath \\\n -m moduleName/className\n 对于非模块化应用程序:\n jpackage --type app-image -i inputDir -n name \\\n --main-class className --main-jar myJar.jar\n 要向 jlink 提供您自己的选项,请分别运行 jlink:\n jlink --output appRuntimeImage -p modulePath \\\n --add-modules moduleName \\\n --no-header-files [...]\n jpackage --type app-image -n name \\\n -m moduleName/className --runtime-image appRuntimeImage + +help.option-group.sample.create-runtime-installer=\ 生成 Java 运行时程序包:\n jpackage -n name --runtime-image + +help.option-group.sample.sign-app-image=\ 对预定义应用程序映像进行签名:\n jpackage --type app-image --app-image \\\n --mac-sign [...]\n 注:此模式下允许的其他选项只有:\n 一组其他 mac 签名选项和 --verbose + +help.option-group.sample=示例用法 +help.option-group.generic=一般选项 +help.option-group.runtime-image=用来创建运行时映像的选项 +help.option-group.app-image=用来创建应用程序映像的选项 +help.option-group.launcher=用来创建应用程序启动程序的选项 +help.option-group.launcher-platform=用来创建应用程序启动程序的平台相关选项 +help.option-group.package=用来创建应用程序包的选项 +help.option-group.package-platform=用来创建应用程序包的与平台相关的选项 + +help.option.argument-file=\ 从文件读取选项和/或模式\n 可以多次使用此选项。 + +help.option.about-url=\ 应用程序主页的 URL + +help.option.add-launcher.win=\ 启动程序的名称,以及包含\n 键值对列表的属性文件的路径\n (绝对路径或相对于当前目录的路径)\n 可以使用键 "arguments"、"description"、"icon"、"java-options"、\n "launcher-as-service"、"main-class"、"main-jar"、"module"、\n "win-console"、"win-menu" 和 "win-shortcut"。\n 这些选项添加到或用于覆盖原始\n 命令行选项以构建其他替代启动程序。\n 将从命令行选项构建主应用程序启动程序。\n 可以使用此选项构建其他替代启动程序,\n 并且可以多次使用此选项\n 构建多个其他启动程序。 + +help.option.add-launcher.linux=\ 启动程序的名称,以及包含\n 键值对列表的属性文件的路径\n (绝对路径或相对于当前目录的路径)\n 可以使用键 "arguments"、"description"、"icon"、"java-options"、\n "launcher-as-service"、"linux-shortcut"、"main-class"、"main-jar" \n 和 "module"。\n 这些选项添加到或用于覆盖原始\n 命令行选项以构建其他替代启动程序。\n 将从命令行选项构建主应用程序启动程序。\n 可以使用此选项构建其他替代启动程序,\n 并且可以多次使用此选项\n 构建多个其他启动程序。 + +help.option.add-launcher.mac=\ 启动程序的名称,以及包含\n 键值对列表的属性文件的路径\n (绝对路径或相对于当前目录的路径)\n 可以使用键 "arguments"、"description"、"icon"、"java-options"、\n "launcher-as-service"、"main-class"、"main-jar" 和\n "module"。\n 这些选项添加到或用于覆盖原始\n 命令行选项以构建其他替代启动程序。\n 将从命令行选项构建主应用程序启动程序。\n 可以使用此选项构建其他替代启动程序,\n 并且可以多次使用此选项\n 构建多个其他启动程序。 + +help.option.add-modules=\ 要添加的模块列表(以逗号 (",") 分隔)\n 此模块列表以及主模块(如果指定)\n 将作为 --add-module 参数传递到 jlink。\n 如果未指定,则仅使用主模块\n (如果指定 --module)或默认模块集\n (如果指定 --main-jar)。\n 可以多次使用此选项。 + +help.option.app-content=\ 要添加到应用程序有效负载中的文件\n 和/或目录路径的逗号分隔列表。\n 可以多次使用此选项。 + +help.option.app-content.mac=\ 要添加到应用程序有效负载中的文件\n 和/或目录路径的逗号分隔列表。\n 可以多次使用此选项。\n 注:该值应为具有 "Resources" 子目录的\n 目录(或应用程序包的 "Contents" 目录中\n 有效的任何其他目录)。否则,jpackage \n 可能会生成无效的应用程序包,此应用程序包\n 可能会使代码签名和/或公证失败。 + +help.option.app-image=\ 用来构建可安装程序包的\n 预定义应用程序映像的位置\n (绝对路径或相对于当前目录的路径) + +help.option.app-image.mac=\ 用来构建可安装程序包或对预定义应用程序\n 映像进行签名的预定义应用程序\n 映像的位置\n (绝对路径或相对于当前目录的路径) + +help.option.app-version=\ 应用程序和/或程序包的版本 + +help.option.arguments=\ 在没有为启动程序提供命令行参数时,\n 要传递到主类的命令行参数\n 可以多次使用此选项。 + +help.option.copyright=\ 应用程序的版权 + +help.option.description=\ 应用程序的说明 + +help.option.dest=\ 放置生成的输出文件的路径\n (绝对路径或相对于当前目录的路径)\n 默认为当前工作目录。 + +help.option.file-associations=\ 包含键值对列表的属性文件的路径\n (绝对路径或相对于当前目录的路径)\n 键 "extension"、"mime-type"、"icon" 和 "description"\n 可用于描述关联。\n 可以多次使用此选项。 + +help.option.help=\ 将用法文本输出到输出流并退出,用法文本中包含\n 适用于当前平台的每个有效选项的列表和说明 + +help.option.icon=\ 应用程序包图标的路径\n (绝对路径或相对于当前目录的路径) + +help.option.input=\ 包含要打包的文件的输入目录的路径\n (绝对路径或相对于当前目录的路径)\n 输入目录中的所有文件将打包到\n 应用程序映像中。 + +help.option.install-dir=\ 应用程序安装目录的绝对路径 + +help.option.install-dir.win=\ 应用程序安装位置的相对子路径\n 例如 "Program Files" 或 "AppData"。 + +help.option.installer-runtime-image=\ 要安装的预定义运行时映像的路径\n (绝对路径或相对于当前目录的路径)\n 创建运行时程序包时需要提供选项。 + +help.option.java-options=\ 传递到 Java 运行时的选项\n 可以多次使用此选项。 + +help.option.jlink-options=\ 要传递到 jlink 的选项列表(以空格分隔)\n 如果未指定,则默认为 "--strip-native-commands\n --strip-debug --no-man-pages --no-header-files"。\n 可以多次使用此选项。 + +help.option.launcher-as-service=\ 请求创建安装程序,以将主应用程序\n 启动程序注册为后台服务类型应用程序。 + +help.option.license-file=\ 许可证文件的路径\n (绝对路径或相对于当前目录的路径) + +help.option.linux-app-category=\ RPM .spec 文件的组值或\n DEB 控制文件的节值 + +help.option.linux-app-release=\ RPM .spec 文件的发行版值或\n DEB 控制文件的 Debian 修订版值 + +help.option.linux-deb-maintainer=\ .deb 程序包的维护程序 + +help.option.linux-menu-group=\ 此应用程序所在的菜单组 + +help.option.linux-package-deps=\ 应用程序所需的程序包或功能 + +help.option.linux-package-name=\ Linux 程序包的名称,默认为应用程序名称 + +help.option.linux-rpm-license-type=\ 许可证类型(RPM .spec 的 "License: ") + +help.option.linux-shortcut=\ 为应用程序创建快捷方式。 + +help.option.mac-app-category=\ 用于构造应用程序 plist 中的 LSApplicationCategoryType 的\n 字符串。默认值为 "utilities"。 + +help.option.mac-app-image-sign-identity=\ 用于对应用程序映像进行签名的身份。此值将\n 直接传递到 "codesign" 工具的 --sign 选项。此选项\n 不能与 --mac-signing-key-user-name 结合使用。 + +help.option.mac-app-store=\ 指示 jpackage 输出面向\n Mac App Store。 + +help.option.mac-dmg-content=\ 包括 dmg 中引用的所有内容。\n 可以多次使用此选项。 + +help.option.mac-entitlements=\ 包含对包中的可执行文件和库进行签名时\n 要使用的权利的文件路径。 + +help.option.mac-installer-sign-identity=\ 用于对 "pkg" 安装程序进行签名的身份。此值将\n 直接传递到 "productbuild" 工具的 --sign 选项。此选项\n 不能与 --mac-signing-key-user-name 结合使用。 + +help.option.mac-package-identifier=\ 唯一标识 macOS 应用程序的标识符\n 默认为主类名称。\n 只能使用字母数字 (A-Z,a-z,0-9)、连字符 (-)\n 和句点 (.) 字符。 + +help.option.mac-package-name=\ 应用程序在菜单栏中显示的名称\n 此名称可以与应用程序名称不同。\n 此名称的长度必须少于 16 个字符,并且\n 适合显示在菜单栏和应用程序“信息”窗口中。\n 默认为应用程序名称。 + +help.option.mac-package-signing-prefix=\ 对应用程序包进行签名时,此值将作为\n 前缀添加到需要签名但当前没有程序包\n 标识符的所有组件。 + +help.option.mac-sign=\ 请求对程序包或预定义的应用程序映像\n 进行签名。 + +help.option.mac-signing-keychain=\ 要用来搜索签名身份的密钥链的名称\n 如果未指定,则使用标准密钥链。 + +help.option.mac-signing-key-user-name=\ Apple 签名身份的团队或用户名称部分。为了直接\n 控制用于对应用程序映像或安装程序进行签名的\n 签名身份,请使用 --mac-app-image-sign-identity 和/或\n --mac-installer-sign-identity。此选项不能与\n --mac-app-image-sign-identity 或 --mac-installer-sign-identity 结合使用。 + +help.option.main-class=\ 要执行的应用程序主类的限定名称\n 只有在指定了 --main-jar 时才能使用此选项。 + +help.option.main-jar=\ 应用程序的主 JAR;包含主类\n (指定为相对于输入路径的路径)\n 可以指定 --module 或 --main-jar 选项,\n 但不能同时指定这两个选项。 + +help.option.module=\ 应用程序的主模块(以及可选的主类)\n 此模块必须位于模块路径中。\n 指定了此选项时,将在 Java 运行时映像中\n 链接主模块。可以指定 --module 或 --main-jar \n 选项,但不能同时指定这两个选项。 + +help.option.module-path=\ 以 : 分隔的路径列表\n 每个路径是模块的目录或\n 模块化 jar 的路径。\n (每个路径可以是绝对路径,也可以是相对于当前目录的路径。)\n 可以多次使用此选项。 +help.option.module-path.win=\ 以 ; 分隔的路径列表\n 每个路径是模块的目录或\n 模块化 jar 的路径。\n (每个路径可以是绝对路径,也可以是相对于当前目录的路径。)\n 可以多次使用此选项。 + +help.option.name=\ 应用程序和/或程序包的名称 + +help.option.resource-dir=\ 覆盖 jpackage 资源的路径\n 可以通过向此目录中添加替换资源来覆盖 jpackage 的\n 图标、模板文件和其他资源。\n (绝对路径或相对于当前目录的路径) + +help.option.runtime-image=\ 将复制到应用程序映像中的预定义\n 运行时映像的路径\n (绝对路径或相对于当前目录的路径)\n 如果未指定 --runtime-image,jpackage 将运行 jlink 以\n 使用以下选项创建运行时映像:\n --strip-debug、--no-header-files、--no-man-pages 和\n --strip-native-commands。 + +help.option.temp=\ 用于创建临时文件的新目录或空目录的路径\n (绝对路径或相对于当前目录的路径)\n 如果指定,则在任务完成时将不删除\n 临时目录,必须手动删除临时目录。\n 如果未指定,将创建临时目录并\n 并在任务完成时删除该临时目录。 + +help.option.type.win=\ 要创建的程序包的类型\n 有效值为:{"app-image", "exe", "msi"}\n 如果未指定此选项,则将创建与平台相关的\n 默认类型。 +help.option.type.linux=\ 要创建的程序包的类型\n 有效值为:{"app-image", "deb", "rpm"}\n 如果未指定此选项,则将创建与平台相关的\n 默认类型。 +help.option.type.mac=\ 要创建的程序包的类型\n 有效值为:{"app-image", "dmg", "pkg"}\n 如果未指定此选项,则将创建与平台相关的\n 默认类型。 + +help.option.vendor=\ 应用程序的供应商 + +help.option.verbose=\ 启用详细的输出 + +help.option.version=\ 将产品版本输出到输出流并退出。 + +help.option.win-console=\ 为应用程序创建控制台启动程序,应当为\n 需要控制台交互的应用程序指定 + +help.option.win-dir-chooser=\ 添加一个对话框以允许用户选择\n 产品的安装目录。 + +help.option.win-help-url=\ 用户可以从中获取更多信息或技术支持的 URL + +help.option.win-menu=\ 请求为此应用程序添加“开始”菜单快捷方式 + +help.option.win-menu-group=\ 此应用程序所在的“开始”菜单组 + +help.option.win-per-user-install=\ 请求基于每个用户执行安装 + +help.option.win-shortcut=\ 请求为此应用程序添加桌面快捷方式 + +help.option.win-shortcut-prompt=\ 添加一个对话框以允许用户选择是否将由安装程序\n 创建快捷方式。 + +help.option.win-update-url=\ 可用应用程序更新信息的 URL + +help.option.win-upgrade-uuid=\ 与此程序包的升级关联的 UUID -MSG_Help_win_launcher=\n用来创建应用程序启动程序的与平台相关的选项:\n --win-console\n 为应用程序创建控制台启动程序,应当为\n 需要控制台交互的应用程序指定\n -MSG_Help_win_install=\ --win-dir-chooser\n 添加一个对话框以允许用户选择\n 产品的安装目录。\n --win-help-url \n 用户可以从中获取更多信息或技术支持的 URL\n --win-menu\n 请求为此应用程序添加开始菜单快捷方式\n --win-menu-group \n 此应用程序所在的开始菜单组\n --win-per-user-install\n 请求基于每个用户执行安装\n --win-shortcut\n 请求为此应用程序添加桌面快捷方式\n --win-shortcut-prompt\n 添加一个对话框以允许用户选择是否将由安装程序\n 创建快捷方式。\n --win-update-url \n 可用应用程序更新信息的 URL\n --win-upgrade-uuid \n 与此程序包的升级相关联的 UUID\n -MSG_Help_win_install_dir=默认安装位置下面的相对子路径\n -MSG_Help_mac_install=\ --mac-dmg-content [,...]\n 包括 DMG 中引用的所有内容。\n 此选项可以使用多次。\n -MSG_Help_mac_launcher=\ --mac-package-identifier \n 用来唯一地标识 macOS 应用程序的标识符\n 默认为主类名称。\n 只能使用字母数字 (A-Z,a-z,0-9)、连字符 (-) 和\n 句点 (.) 字符。\n --mac-package-name \n 出现在菜单栏中的应用程序名称\n 这可以与应用程序名称不同。\n 此名称的长度必须小于 16 个字符,适合\n 显示在菜单栏中和应用程序“信息”窗口中。\n 默认为应用程序名称。\n --mac-package-signing-prefix \n 在对应用程序包签名时,会在所有需要签名\n 但当前没有程序包标识符的组件的\n 前面加上此值。\n --mac-sign\n 请求对程序包或预定义的应用程序映像\n 进行签名。\n --mac-signing-keychain \n 要用来搜索签名身份的密钥链的名称\n 如果未指定,则使用标准的密钥链。\n --mac-signing-key-user-name \n Apple 签名身份的团队或用户名称部分。为了直接\n 控制用于对应用程序映像或安装程序进行签名的\n 签名身份,请使用 --mac-app-image-sign-identity 和/或\n --mac-installer-sign-identity。此选项不能与\n --mac-app-image-sign-identity 或 --mac-installer-sign-identity 结合使用。\n --mac-app-image-sign-identity \n 用于对应用程序映像进行签名的身份。此值将直接\n 传递至 "codesign" 工具的 --sign 选项。此选项不能\n 与 --mac-signing-key-user-name 结合使用。\n --mac-installer-sign-identity \n 用于对 "pkg" 安装程序进行签名的身份。此值将直接\n 传递至 "productbuild" 工具的 --sign 选项。此选项不能\n 与 --mac-signing-key-user-name 结合使用。\n --mac-app-store\n 指示 jpackage 输出面向\n Mac App Store。\n --mac-entitlements \n 包含一些权利的文件的路径,在对捆绑包中的可执行文件\n 和库进行签名时会使用这些权利。\n --mac-app-category \n 用于构造应用程序 plist 中 LSApplicationCategoryType 的\n 字符串。默认值为 "utilities"。\n -MSG_Help_linux_install=\ --linux-package-name \n Linux 程序包的名称,默认为应用程序名称\n --linux-deb-maintainer \n .deb 程序包的维护程序\n --linux-menu-group \n 此应用程序所在的菜单组\n --linux-package-deps \n 应用程序所需的程序包或功能\n --linux-rpm-license-type \n 许可证的类型(RPM .spec 的 "License: ")\n --linux-app-release \n RPM .spec 文件的发行版值或 \n DEB 控制文件的 Debian 修订版值\n --linux-app-category \n RPM .spec 文件的组值或 \n DEB 控制文件的节值\n --linux-shortcut\n 为应用程序创建快捷方式。\n -MSG_Help_mac_linux_install_dir=应用程序安装目录的绝对路径\n -MSG_Help_default_install_dir=OS X 或 Linux 上应用程序安装目录的绝对路径。\n Windows 上应用程序安装位置的相对子路径\n (如 "Program Files" 或 "AppData")。\n -MSG_Help_no_args=用法:jpackage \n使用 jpackage --help(或 -h)可获取可能选项的列表 -MSG_Help_default_app_image=用来构建可安装程序包的\n 预定义应用程序映像的位置\n -MSG_Help_mac_app_image=用来构建可安装程序包的\n 或对预定义应用程序映像进行签名的\n 预定义应用程序映像的位置\n -MSG_Help_mac_sign_sample_usage=\ 对预定义应用程序映像进行签名:\n jpackage --type app-image --app-image \\\n --mac-sign [...]\n 注:此模式下允许的其他选项只有:\n 一组其他 mac 签名选项和 --verbose\n diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources_de.properties b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources_de.properties index 2426b97c7e2..7816f8ee71a 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources_de.properties +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources_de.properties @@ -24,25 +24,32 @@ # # -jpackage.description=Eigenständige Java-Anwendung verpacken - param.copyright.default=Copyright (C) {0,date,YYYY} -param.description.default=Kein Wert param.vendor.default=Unbekannt +bundle-type.win-app=Windows-Anwendungsimage +bundle-type.win-exe=EXE-Installationsprogrammpackage +bundle-type.win-msi=MSI-Installationsprogrammpackage +bundle-type.mac-app=Mac-Anwendungsimage +bundle-type.mac-dmg=Mac-DMG-Package +bundle-type.mac-pkg=Mac-PKG-Package +bundle-type.linux-app=Linux-Anwendungsimage +bundle-type.linux-deb=DEB-Bundle +bundle-type.linux-rpm=RPM-Bundle + resource.post-app-image-script=Auszuführendes Skript nach dem Auffüllen des Anwendungsimages message.using-default-resource=Standardpackageressource {0} {1} wird verwendet (durch Hinzufügen von {2} zu resource-dir ist eine Anpassung möglich). -message.no-default-resource=Keine Standardpackageressource {0} {1} (durch Hinzufügen von {2} zu resource-dir ist eine Anpassung möglich). +message.no-default-resource=Keine Standardpackageressource {0} (durch Hinzufügen von {1} zu resource-dir ist eine Anpassung möglich). message.using-custom-resource-from-file=Benutzerdefinierte Packageressource {0} wird verwendet (aus Datei {1} geladen). message.using-custom-resource=Benutzerdefinierte Packageressource {0} wird verwendet (aus {1} geladen). message.creating-app-bundle=Anwendungspackage {0} wird in {1} erstellt -message.runtime-image-dir-does-not-exist=Angegebenes Laufzeitimageverzeichnis {0}: {1} ist nicht vorhanden -message.resource-dir-does-not-exist=Angegebenes Ressourcenverzeichnis {0}: {1} ist nicht vorhanden message.debug-working-directory=Arbeitsverzeichnis für Debug beibehalten: {0} message.bundle-created={0}-Package wurde erfolgreich erstellt message.module-version=Version "{0}" aus Modul "{1}" wird als Anwendungsversion verwendet -message.module-class=Klasse "{0}" aus Modul "{1}" wird als Anwendungshauptklasse verwendet + +message.error-header={0} +message.advice-header=Empfehlung zur Behebung: {0} error.version-string-empty=Version darf keine leere Zeichenfolge sein error.version-string-zero-length-component=Version [{0}] enthält eine Komponente mit Nulllänge @@ -50,64 +57,69 @@ error.version-string-invalid-component=Version [{0}] enthält ungültige Kompone error.cannot-create-output-dir=Zielverzeichnis {0} kann nicht erstellt werden error.cannot-write-to-output-dir=Zielverzeichnis {0} ist schreibgeschützt -error.root-exists=Fehler: Anwendungszielverzeichnis {0} ist bereits vorhanden +error.root-exists=Anwendungszielverzeichnis {0} ist bereits vorhanden error.no-main-class-with-main-jar=Es wurde keine Hauptklasse angegeben oder in der JAR-Datei {0} gefunden error.no-main-class-with-main-jar.advice=Geben Sie eine Hauptklasse an, oder stellen Sie sicher, dass die JAR-Datei {0} eine Hauptklasse im Manifest angibt -error.no-main-class=Es wurde keine Hauptklasse angegeben oder in den angegebenen Anwendungsressourcen gefunden -error.no-main-class.advice=Geben Sie eine Anwendungsklasse an, oder stellen Sie sicher, dass die appResources eine JAR-Datei mit einer Anwendungsklasse im Manifest enthalten error.main-jar-does-not-exist=Die konfigurierte Haupt-JAR-Datei ist im Eingabeverzeichnis nicht vorhanden {0} error.main-jar-does-not-exist.advice=Die Haupt-JAR-Datei muss relativ zum Eingabeverzeichnis (nicht als absoluter Pfad) angegeben werden und muss in diesem Verzeichnis vorhanden sein error.no-module-in-path="{0}-Modul im Modulpfad nicht gefunden" -error.not-path-parameter="Ungültiger Wert für Parameter {0}: {1}" error.no-input-parameter="--input-Parameter für nicht modulare Anwendung fehlt" +error.non-option-arguments={0} Argumente, die keine Option sind, in der Befehlszeile gefunden. Argumente, die keine Option sind, sind nicht zulässig +error.undefined-default-bundling-operation=Standard-Bundling-Vorgang ist nicht definiert +error.undefined-default-bundling-operation.advice=Parameter {0} zur Befehlszeile hinzufügen +error.parameter-not-uuid=Der für Parameter {1} angegebene Wert "{0}" ist keine gültige UUID +error.parameter-not-path=Der für Parameter {1} angegebene Wert "{0}" ist kein gültiger Pfad +error.parameter-not-file=Der für Parameter {1} angegebene Wert "{0}" ist keine Datei +error.parameter-not-directory=Der für Parameter {1} angegebene Wert "{0}" ist kein Verzeichnis +error.parameter-not-empty-directory=Der für Parameter {1} angegebene Wert "{0}" ist kein leeres Verzeichnis oder kein vorhandener Pfad +error.parameter-not-url=Der für Parameter {1} angegebene Wert "{0}" ist keine gültige URL +error.parameter-not-launcher-shortcut-dir=Der für Parameter {1} angegebene Wert "{0}" ist kein gültiges Verknüpfungsstartverzeichnis +error.path-parameter-ioexception=I/O-Fehler beim Zugriff auf Pfadwert "{0}" von Parameter {1} +error.parameter-add-launcher-malformed=Der für Parameter {1} angegebene Wert "{0}" stimmt nicht mit dem Muster = überein +error.parameter-add-launcher-not-file=Der Wert des Pfades zu einer Eigenschaftendatei "{0}", der für den zusätzlichen Launcher "{1}" bereitgestellt wird, ist kein gültiger Dateipfad +error.properties-parameter-not-path=Der für Eigenschaft "{1}" in Datei "{2}" angegebene Wert "{0}" ist kein gültiger Pfad +error.properties-parameter-not-file=Der für Eigenschaft "{1}" in Datei "{2}" angegebene Wert "{0}" ist keine Datei +error.properties-parameter-not-launcher-shortcut-dir=Der für Eigenschaft "{1}" in Datei "{2}" angegebene Wert "{0}" ist kein gültiges Verknüpfungsstartverzeichnis + error.no-content-types-for-file-association=Für Dateiverknüpfungsnummer {0} wurden keine MIME-Typen angegeben error.no-content-types-for-file-association.advice=Geben Sie einen MIME-Typ für Dateiverknüpfungsnummer {0} an error.too-many-content-types-for-file-association=Für Dateiverknüpfungsnummer {0} wurde mehr als ein MIME-Typ angegeben error.too-many-content-types-for-file-association.advice=Geben Sie nur einen MIME-Typ für Dateiverknüpfungsnummer {0} an -error.tool-not-found={0} kann nicht gefunden werden. Grund: {1} -error.tool-not-found.advice=Installieren Sie {0} -error.tool-old-version={0} {1} oder eine neuere Version kann nicht gefunden werden -error.tool-old-version.advice=Installieren Sie {0} {1} oder eine neuere Version +error.launcher-duplicate-name=Mehrere Launcher haben denselben Namen "{0}". Launcher müssen eindeutige Namen haben + +error.tool-error=Validieren von "{0}" nicht möglich. Grund: {1} +error.tool-not-executable="{0}" ist nicht ausführbar +error.tool-not-found="{0}" kann nicht gefunden werden +error.tool-not-found.advice=Installieren Sie "{0}" +error.tool-old-version="{0}" {1} oder eine neuere Version kann nicht gefunden werden +error.tool-old-version.advice=Installieren Sie "{0}" {1} oder eine neuere Version + error.jlink.failed=jlink nicht erfolgreich mit: {0} error.blocked.option=jlink-Option [{0}] ist in --jlink-options nicht zulässig error.no.name=Name nicht mit --name angegeben. Es kann auch kein Name aus app-image abgeleitet werden error.no.name.advice=Geben Sie den Namen mit --name an -warning.no.jdk.modules.found=Warnung: Keine JDK-Module gefunden - -error.foreign-app-image=Fehler : Fehlende .jpackage.xml-Datei in app-image-Verzeichnis "{0}" -error.invalid-app-image=Fehler: app-image-Verzeichnis "{0}" wurde von einer anderen jpackage-Version generiert, oder Datei "{1}" ist nicht wohlgeformt +error.missing-app-image-file=Datei "{0}" fehlt im vordefinierten Anwendungsimage "{1}" +error.invalid-app-image-file=Datei "{0}" im vordefinierten Anwendungsimage "{1}" ist beschädigt oder wurde von einer anderen Version von jpackage erstellt +error.malformed-app-image-file=Datei "{0}" im vordefinierten Anwendungsimage "{1}" enthält nicht wohlgeformte XML-Daten +error.reading-app-image-file=Datei "{0}" konnte im vordefinierten Anwendungsimage "{1}" nicht gelesen werden error.invalid-install-dir=Ungültiges Installationsverzeichnis "{0}" -MSG_BundlerFailed=Fehler: Bundler "{1}" ({0}) konnte kein Package generieren -MSG_BundlerConfigException=Bundler {0} aufgrund eines Konfigurationsproblems übersprungen: {1} \nEmpfehlung zur Behebung: {2} -MSG_BundlerConfigExceptionNoAdvice=Bundler {0} aufgrund eines Konfigurationsproblems übersprungen: {1} -MSG_BundlerRuntimeException=Bundler {0} nicht erfolgreich. Grund: {1} +ERR_NoMainClass=Hauptanwendungsklasse fehlt +ERR_UnsupportedOption=Option [{0}] ist auf dieser Plattform ungültig +ERR_InvalidTypeOption=Option [{0}] ist nicht gültig mit Typ [{1}] +ERR_NoInstallerEntryPoint=Option [{0}] ist nicht gültig ohne Einstiegspunktoption --module oder --main-jar +ERR_MutuallyExclusiveOptions=Sich gegenseitig ausschließende Optionen: [{0}] und [{1}] +ERR_InvalidOptionWithAppImageSigning=Option [{0}] ist nicht gültig beim Signieren eines Anwendungsimages -ERR_NoMainClass=Fehler: Hauptanwendungsklasse fehlt -ERR_UnsupportedOption=Fehler: Option [{0}] ist auf dieser Plattform ungültig -ERR_InvalidTypeOption=Fehler: Option [{0}] ist nicht gültig mit Typ [{1}] -ERR_NoInstallerEntryPoint=Fehler: Option [{0}] ist nicht gültig ohne Einstiegspunktoption --module oder --main-jar -ERR_MutuallyExclusiveOptions=Fehler: Optionen [{0}] und [{1}] schließen sich gegenseitig aus -ERR_InvalidOptionWithAppImageSigning=Fehler: Option [{0}] ist nicht gültig beim Signieren eines Anwendungsimages - -ERR_MissingArgument=Fehler: Fehlendes Argument: {0} -ERR_MissingRequiredArgument=Fehler: Für das Argument {0} ist mindestens eines der folgenden Argumente erforderlich: [{1}] -ERR_AppImageNotExist=Fehler: Anwendungsimageverzeichnis "{0}" ist nicht vorhanden -ERR_NoAddLauncherName=Fehler: Für Option --add-launcher müssen ein Name und ein Dateipfad angegeben werden (--add-launcher =) -ERR_NoUniqueName=Fehler: Für --add-launcher = ist ein eindeutiger Name erforderlich -ERR_InvalidAppName=Fehler: Ungültiger Anwendungsname: {0} -ERR_InvalidSLName=Fehler: Ungültiger Name für hinzuzufügenden Launcher: {0} -ERR_IconFileNotExit=Fehler: Die angegebene Symboldatei [{0}] ist nicht vorhanden -ERR_LicenseFileNotExit=Fehler: Die angegebene Lizenzdatei ist nicht vorhanden -ERR_BuildRootInvalid=Fehler: Das temporäre Verzeichnis ({0}) darf nicht vorhanden sein oder muss leer sein -ERR_InvalidOption=Fehler: Ungültige Option: [{0}] -ERR_InvalidInstallerType=Fehler: Ungültiger oder nicht unterstützter Typ: [{0}] -ERR_BothMainJarAndModule=Fehler: Die Optionen --main-jar und --module dürfen nicht beide vorhanden sein -ERR_NoEntryPoint=Fehler: Für das Erstellen des Anwendungsimages muss entweder die Option --main-jar oder die Option --module angegeben werden -ERR_CannotParseOptions=Fehler: Option @filename wird verarbeitet: {0} -ERR_MissingJLinkOptMacAppStore=Fehler: Argument "--mac-app-store" erfordert eine {0}-Option für Argument "--jlink-options" -ERR_MacAppStoreRuntimeBinExists=Fehler: Laufzeitimage "{0}" darf nicht den Ordner "bin" enthalten. Verwenden Sie die jlink-Option "--strip-native-commands" beim Generieren des Laufzeitimages mit dem Argument "--mac-app-store". +ERR_MissingArgument2=Fehlendes Argument: {0} oder {1} +ERR_InvalidAppName=Ungültiger Anwendungsname: {0} +ERR_InvalidSLName=Ungültiger Name für hinzuzufügenden Launcher: {0} +ERR_InvalidOption=Ungültige Option: [{0}] +ERR_InvalidInstallerType=Ungültiger oder nicht unterstützter Typ: [{0}] +ERR_NoEntryPoint=Für das Erstellen des Anwendungsimages muss entweder die Option --main-jar oder die Option --module angegeben werden +ERR_CannotParseOptions=Option @filename wird verarbeitet: {0} +ERR_MissingJLinkOptMacAppStore=Argument "--mac-app-store" erfordert eine {0}-Option für Argument "--jlink-options" diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources_ja.properties b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources_ja.properties index e0faf346973..5db5ead7577 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources_ja.properties +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources_ja.properties @@ -24,25 +24,32 @@ # # -jpackage.description=自己完結型Javaアプリケーションをパッケージ化します - param.copyright.default=Copyright (C) {0,date,YYYY} -param.description.default=なし param.vendor.default=不明 +bundle-type.win-app=Windowsアプリケーション・イメージ +bundle-type.win-exe=EXEインストーラ・パッケージ +bundle-type.win-msi=MSIインストーラ・パッケージ +bundle-type.mac-app=Macアプリケーション・イメージ +bundle-type.mac-dmg=Mac DMGパッケージ +bundle-type.mac-pkg=Mac PKGパッケージ +bundle-type.linux-app=Linuxアプリケーション・イメージ +bundle-type.linux-deb=DEBバンドル +bundle-type.linux-rpm=RPMバンドル + resource.post-app-image-script=アプリケーション・イメージを移入した後に実行するスクリプト message.using-default-resource=デフォルトのパッケージ・リソース{0} {1}の使用({2}をresource-dirに追加してカスタマイズ)。 -message.no-default-resource=デフォルトのパッケージ・リソース{0} {1}なし({2}をresource-dirに追加してカスタマイズ)。 +message.no-default-resource=デフォルトのパッケージ・リソース{0}なし({1}をresource-dirに追加してカスタマイズ)。 message.using-custom-resource-from-file=カスタム・パッケージ・リソース{0}の使用(ファイル{1}からロード済) message.using-custom-resource=カスタム・パッケージ・リソース{0}の使用({1}からロード済) message.creating-app-bundle=アプリケーション・パッケージを作成しています: {1}内の{0} -message.runtime-image-dir-does-not-exist=指定されたランタイム・イメージ・ディレクトリ{0}: {1}は存在しません -message.resource-dir-does-not-exist=指定されたリソース・ディレクトリ{0}: {1}は存在しません message.debug-working-directory=デバッグの作業ディレクトリが保持されました: {0} message.bundle-created={0}パッケージの作成に成功しました message.module-version=モジュール"{1}"のバージョン"{0}"をアプリケーション・バージョンとして使用 -message.module-class=モジュール"{1}"のクラス"{0}"をアプリケーション・メイン・クラスとして使用 + +message.error-header={0} +message.advice-header=修正のアドバイス: {0} error.version-string-empty=バージョンを空の文字列にすることはできません error.version-string-zero-length-component=バージョン[{0}]に長さゼロのコンポーネントが含まれます @@ -50,64 +57,69 @@ error.version-string-invalid-component=バージョン[{0}]に無効なコンポ error.cannot-create-output-dir=宛先ディレクトリ{0}を作成できません。 error.cannot-write-to-output-dir=宛先ディレクトリ{0}は書込み不可です -error.root-exists=エラー: アプリケーションの宛先ディレクトリ{0}はすでに存在します +error.root-exists=アプリケーションの宛先ディレクトリ{0}はすでに存在します error.no-main-class-with-main-jar=メイン・クラスが指定されていなかったか、jar {0}に見つかりませんでした error.no-main-class-with-main-jar.advice=メイン・クラスを指定するか、jar {0}がマニフェストで指定していることを確認してください -error.no-main-class=メイン・クラスが指定されていなかったか、指定されたアプリケーション・リソースに見つかりませんでした -error.no-main-class.advice=アプリケーション・クラスを指定するか、マニフェストでappResourcesにアプリケーション・クラスを含むjarがあることを確認してください error.main-jar-does-not-exist=入力ディレクトリで、構成されたメインjarが{0}に存在しません error.main-jar-does-not-exist.advice=入力ディレクトリに対して相対的に(絶対パスではない)メインjarを指定する必要があり、そのディレクトリ内に存在する必要があります error.no-module-in-path="モジュール・パスに{0}モジュールが見つかりませんでした" -error.not-path-parameter="{0}パラメータの無効な値: {1}" error.no-input-parameter="非モジュラ・アプリケーションに--inputパラメータがありません" +error.non-option-arguments=コマンドラインで{0}個の非オプション引数が見つかりました。非オプション引数は使用できません +error.undefined-default-bundling-operation=デフォルトのバンドル操作は未定義です +error.undefined-default-bundling-operation.advice=コマンドラインに{0}パラメータを追加します +error.parameter-not-uuid=パラメータ{1}に指定された値"{0}"は有効なUUIDではありません +error.parameter-not-path=パラメータ{1}に指定された値"{0}"は有効なパスではありません +error.parameter-not-file=パラメータ{1}に指定された値"{0}"はファイルではありません +error.parameter-not-directory=パラメータ{1}に指定された値"{0}"はディレクトリではありません +error.parameter-not-empty-directory=パラメータ{1}に指定された値"{0}"が空のディレクトリでないか、存在しないパスです +error.parameter-not-url=パラメータ{1}に指定された値"{0}"は有効なURLではありません +error.parameter-not-launcher-shortcut-dir=パラメータ{1}に指定された値"{0}"は、有効なショートカット起動ディレクトリではありません +error.path-parameter-ioexception=パラメータ{1}のパス値"{0}"へのアクセス中にI/Oエラーが発生しました +error.parameter-add-launcher-malformed=パラメータ{1}に指定された値"{0}"がパターン=と一致しません +error.parameter-add-launcher-not-file=追加のランチャ"{1}"に指定されたプロパティ・ファイル"{0}"へのパスの値は有効なファイル・パスではありません +error.properties-parameter-not-path="{2}"ファイルのプロパティ"{1}"に指定された値"{0}"は有効なパスではありません +error.properties-parameter-not-file="{2}"ファイルのプロパティ"{1}"に指定された値"{0}"はファイルではありません +error.properties-parameter-not-launcher-shortcut-dir="{2}"ファイルのプロパティ"{1}"に指定された値"{0}"は、有効なショートカット起動ディレクトリではありません + error.no-content-types-for-file-association=ファイル・アソシエーション番号{0}にMIMEタイプが指定されませんでした error.no-content-types-for-file-association.advice=ファイル・アソシエーション番号{0}にMIMEタイプを指定してください error.too-many-content-types-for-file-association=ファイル・アソシエーション番号{0}に複数のMIMEタイプが指定されました error.too-many-content-types-for-file-association.advice=ファイル・アソシエーション番号{0}にMIMEタイプを1つのみ指定してください -error.tool-not-found={0}が見つかりません。理由: {1} -error.tool-not-found.advice={0}をインストールしてください -error.tool-old-version={0} {1}以降が見つかりません -error.tool-old-version.advice={0} {1}以降をインストールしてください +error.launcher-duplicate-name=複数のランチャに同じ名前"{0}"が付いています。ランチャには一意の名前が必要です + +error.tool-error="{0}"を検証できません。理由: {1} +error.tool-not-executable="{0}"は実行可能ではありません +error.tool-not-found="{0}"が見つかりません +error.tool-not-found.advice="{0}"をインストールしてください +error.tool-old-version="{0}" {1}以降が見つかりません +error.tool-old-version.advice="{0}" {1}以降をインストールしてください + error.jlink.failed=jlinkが次で失敗しました: {0} error.blocked.option=jlinkオプション[{0}]は--jlink-optionsでは許可されません error.no.name=名前が--nameで指定されておらず、app-imageから推論できません error.no.name.advice=--nameで名前を指定します -warning.no.jdk.modules.found=警告: JDKモジュールが見つかりません - -error.foreign-app-image=エラー: app-imageディレクトリ"{0}"に.jpackage.xmlファイルがありません -error.invalid-app-image=エラー: app-imageディレクトリ"{0}"は、別のjpackageバージョンまたは不正な"{1}"ファイルで生成されました +error.missing-app-image-file=事前定義済アプリケーション・イメージ"{1}"に"{0}"ファイルがありません +error.invalid-app-image-file=事前定義済アプリケーション・イメージ"{1}"の"{0}"ファイルが破損しているか、別のバージョンのjpackageによって作成されました +error.malformed-app-image-file=事前定義済アプリケーション・イメージ"{1}"の"{0}"ファイルに不正なXMLデータが含まれています +error.reading-app-image-file=事前定義済アプリケーション・イメージ"{1}"の"{0}"ファイルの読取りに失敗しました error.invalid-install-dir=無効なインストール・ディレクトリ"{0}" -MSG_BundlerFailed=エラー: バンドラ"{1}" ({0})がパッケージの生成に失敗しました -MSG_BundlerConfigException=構成の問題のため、バンドラ{0}がスキップされました: {1} \n次の修正を行ってください: {2} -MSG_BundlerConfigExceptionNoAdvice=構成の問題のため、バンドラ{0}がスキップされました: {1} -MSG_BundlerRuntimeException={1}のため、バンドラ{0}が失敗しました +ERR_NoMainClass=メイン・アプリケーション・クラスがありません +ERR_UnsupportedOption=オプション[{0}]は、このプラットフォームでは無効です +ERR_InvalidTypeOption=オプション[{0}]は、タイプ[{1}]では無効です +ERR_NoInstallerEntryPoint=オプション[{0}]は、--moduleまたは--main-jarエントリ・ポイント・オプションなしでは無効です +ERR_MutuallyExclusiveOptions=相互排他的なオプション[{0}]と[{1}] +ERR_InvalidOptionWithAppImageSigning=アプリケーション・イメージへの署名時にオプション[{0}]が有効ではありません -ERR_NoMainClass=エラー: メイン・アプリケーション・クラスがありません -ERR_UnsupportedOption=エラー: オプション[{0}]は、このプラットフォームでは無効です -ERR_InvalidTypeOption=エラー: オプション[{0}]は、タイプ[{1}]では無効です -ERR_NoInstallerEntryPoint=エラー: オプション[{0}]は、--moduleまたは--main-jarエントリ・ポイント・オプションなしでは無効です -ERR_MutuallyExclusiveOptions=エラー: 相互排他的なオプション[{0}]と[{1}] -ERR_InvalidOptionWithAppImageSigning=エラー: アプリケーション・イメージへの署名時にオプション[{0}]が有効ではありません - -ERR_MissingArgument=エラー: 引数がありません: {0} -ERR_MissingRequiredArgument=エラー: {0}引数には少なくとも1つの[{1}]引数が必要です -ERR_AppImageNotExist=エラー: アプリケーション・イメージ・ディレクトリ"{0}"は存在しません -ERR_NoAddLauncherName=エラー: --add-launcherオプションには名前およびファイル・パスが必要です(--add-launcher =) -ERR_NoUniqueName=エラー: --add-launcher =には一意の名前が必要です -ERR_InvalidAppName=エラー: 無効なアプリケーション名: {0} -ERR_InvalidSLName=エラー: 無効な追加ランチャ名: {0} -ERR_IconFileNotExit=エラー: 指定されたアイコン・ファイル[{0}]は存在しません -ERR_LicenseFileNotExit=エラー: 指定されたライセンス・ファイルは存在しません -ERR_BuildRootInvalid=エラー: 一時({0})は存在しないか、空のディレクトリである必要があります -ERR_InvalidOption=エラー: 無効なオプション: [{0}] -ERR_InvalidInstallerType=エラー: 無効またはサポートされていないタイプ: [{0}] -ERR_BothMainJarAndModule=エラー: --main-jarオプションと--moduleオプションの両方を指定することはできません -ERR_NoEntryPoint=エラー: アプリケーション・イメージの作成には--main-jarまたは--moduleオプションが必要です -ERR_CannotParseOptions=エラー: @filenameオプションの処理: {0} -ERR_MissingJLinkOptMacAppStore=エラー: --mac-app-store引数では、--jlink-options引数に{0}オプションが必要です -ERR_MacAppStoreRuntimeBinExists=エラー: ランタイム・イメージ"{0}"に"bin"フォルダを含めることはできません。--mac-app-store引数で使用されるランタイム・イメージを生成する際に、--strip-native-commands jlinkオプションを使用します。 +ERR_MissingArgument2=引数がありません: {0}または{1} +ERR_InvalidAppName=無効なアプリケーション名: {0} +ERR_InvalidSLName=無効な追加ランチャ名: {0} +ERR_InvalidOption=無効なオプション: [{0}] +ERR_InvalidInstallerType=無効またはサポートされていないタイプ: [{0}] +ERR_NoEntryPoint=アプリケーション・イメージの作成には--main-jarまたは--moduleオプションが必要です +ERR_CannotParseOptions=@filenameオプションの処理: {0} +ERR_MissingJLinkOptMacAppStore=--mac-app-store引数では、--jlink-options引数に{0}オプションが必要です diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources_zh_CN.properties b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources_zh_CN.properties index 0236ef34077..23540af7db2 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources_zh_CN.properties +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources_zh_CN.properties @@ -24,25 +24,32 @@ # # -jpackage.description=打包自包含 Java 应用程序 - param.copyright.default=版权所有 (C) {0,date,YYYY} -param.description.default=无 param.vendor.default=未知 +bundle-type.win-app=Windows 应用程序映像 +bundle-type.win-exe=EXE 安装程序包 +bundle-type.win-msi=MSI 安装程序包 +bundle-type.mac-app=Mac 应用程序映像 +bundle-type.mac-dmg=Mac DMG 程序包 +bundle-type.mac-pkg=Mac PKG 程序包 +bundle-type.linux-app=Linux 应用程序映像 +bundle-type.linux-deb=DEB 包 +bundle-type.linux-rpm=RPM 包 + resource.post-app-image-script=要在填充应用程序映像之后运行的脚本 message.using-default-resource=使用默认程序包资源 {0} {1}(将 {2} 添加到 resource-dir 中以进行定制)。 -message.no-default-resource=无默认程序包资源 {0} {1}(将 {2} 添加到 resource-dir 中以进行定制)。 +message.no-default-resource=无默认程序包资源 {0}(将 {1} 添加到 resource-dir 中以进行定制)。 message.using-custom-resource-from-file=使用定制程序包资源 {0} (从文件 {1} 加载)。 message.using-custom-resource=使用定制程序包资源 {0} (从 {1} 加载)。 message.creating-app-bundle=正在 {1} 中创建应用程序包 {0} -message.runtime-image-dir-does-not-exist=指定的运行时映像目录 {0}:{1} 不存在 -message.resource-dir-does-not-exist=指定的资源目录 {0}:{1} 不存在 message.debug-working-directory=用于调试的已保留工作目录: {0} message.bundle-created=已成功地构建 {0} 程序包 message.module-version=正在将模块 "{1}" 中的版本 "{0}" 用作应用程序版本 -message.module-class=正在将模块 "{1}" 中的类 "{0}" 用作应用程序主类 + +message.error-header={0} +message.advice-header=修复建议:{0} error.version-string-empty=版本不能为空字符串 error.version-string-zero-length-component=版本 [{0}] 包含长度为零的组件 @@ -50,64 +57,69 @@ error.version-string-invalid-component=版本 [{0}] 包含无效组件 [{1}] error.cannot-create-output-dir=无法创建目标目录 {0} error.cannot-write-to-output-dir=目标目录 {0} 不可写 -error.root-exists=错误:应用程序目标目录 {0} 已存在 +error.root-exists=应用程序目标目录 {0} 已存在 error.no-main-class-with-main-jar=未指定主类,在 jar {0} 中也未找到主类 error.no-main-class-with-main-jar.advice=请指定主类或确保 jar {0} 在清单中指定一个主类。 -error.no-main-class=未指定主类,在提供的应用程序资源中也未找到主类 -error.no-main-class.advice=请指定应用程序类,或者确保 appResources 中有一个 jar 在清单中包含应用程序类。 error.main-jar-does-not-exist=配置的主 jar 在输入目录中不存在 {0} error.main-jar-does-not-exist.advice=必须使用相对于输入目录的路径(不使用绝对路径)指定主 jar ,并且该目录中存在主 jar error.no-module-in-path="无法在模块路径中找到 {0} 模块" -error.not-path-parameter="{0} 参数的值无效:{1}" error.no-input-parameter="非模块化应用程序缺少 --input 参数" +error.non-option-arguments=在命令行上发现 {0} 个非选项参数。不允许使用非选项参数 +error.undefined-default-bundling-operation=未定义默认绑定操作 +error.undefined-default-bundling-operation.advice=将 {0} 参数添加到命令行 +error.parameter-not-uuid=为参数 {1} 提供的值 "{0}" 不是有效的 UUID +error.parameter-not-path=为参数 {1} 提供的值 "{0}" 不是有效路径 +error.parameter-not-file=为参数 {1} 提供的值 "{0}" 不是文件 +error.parameter-not-directory=为参数 {1} 提供的值 "{0}" 不是目录 +error.parameter-not-empty-directory=为参数 {1} 提供的值 "{0}" 不是空目录或是不存在的路径 +error.parameter-not-url=为参数 {1} 提供的值 "{0}" 不是有效的 URL +error.parameter-not-launcher-shortcut-dir=为参数 {1} 提供的值 "{0}" 不是有效的快捷方式启动目录 +error.path-parameter-ioexception=访问参数 {1} 的路径值 "{0}" 时出现 I/O 错误 +error.parameter-add-launcher-malformed=为参数 {1} 提供的值 "{0}" 与模式 = 不匹配 +error.parameter-add-launcher-not-file=为其他启动程序 "{1}" 提供的属性文件 "{0}" 的路径值不是有效的文件路径 +error.properties-parameter-not-path=为 "{2}" 文件中的属性 "{1}" 提供的值 "{0}" 不是有效路径 +error.properties-parameter-not-file=为 "{2}" 文件中的属性 "{1}" 提供的值 "{0}" 不是文件 +error.properties-parameter-not-launcher-shortcut-dir=为 "{2}" 文件中的属性 "{1}" 提供的值 "{0}" 不是有效的快捷方式启动目录 + error.no-content-types-for-file-association=没有为文件关联号{0}指定 MIME 类型 error.no-content-types-for-file-association.advice=为文件关联号 {0} 指定 MIME 类型 error.too-many-content-types-for-file-association=为文件关联号{0}指定了多个 MIME 类型 error.too-many-content-types-for-file-association.advice=仅为文件关联号 {0} 指定一个 MIME 类型 -error.tool-not-found=找不到 {0}。原因:{1} -error.tool-not-found.advice=请安装 {0} -error.tool-old-version=找不到 {0} {1}或更新版本 -error.tool-old-version.advice=请安装 {0} {1}或更新版本 +error.launcher-duplicate-name=多个启动程序具有相同的名称 "{0}"。启动程序应具有唯一名称 + +error.tool-error=无法验证 "{0}"。原因:{1} +error.tool-not-executable="{0}" 不可执行 +error.tool-not-found=找不到 "{0}" +error.tool-not-found.advice=请安装 "{0}" +error.tool-old-version=找不到 "{0}" {1} 或更新版本 +error.tool-old-version.advice=请安装 "{0}" {1} 或更新版本 + error.jlink.failed=jlink 失败,出现 {0} error.blocked.option=不允许在 --jlink-options 中使用 jlink 选项 [{0}] error.no.name=未使用 --name 指定名称,无法从 app-image 推断名称 error.no.name.advice=使用 --name 指定名称 -warning.no.jdk.modules.found=警告: 未找到 JDK 模块 - -error.foreign-app-image=错误:app-image 目录 "{0}" 中缺少 .jpackage.xml 文件 -error.invalid-app-image=错误:另一个 jpackage 版本或格式错误的 "{1}" 文件生成了 app-image 目录 "{0}" +error.missing-app-image-file=预定义的应用程序映像 "{1}" 中缺少 "{0}" 文件 +error.invalid-app-image-file=预定义的应用程序映像 "{1}" 中的 "{0}" 文件已损坏或由其他版本的 jpackage 创建 +error.malformed-app-image-file=预定义的应用程序映像 "{1}" 中的 "{0}" 文件包含格式错误的 XML 数据 +error.reading-app-image-file=无法在预定义的应用程序映像 "{1}" 中读取 "{0}" 文件 error.invalid-install-dir=安装目录 "{0}" 无效 -MSG_BundlerFailed=错误:打包程序 "{1}" ({0}) 无法生成程序包 -MSG_BundlerConfigException=由于配置问题, 跳过了打包程序{0}: {1} \n修复建议: {2} -MSG_BundlerConfigExceptionNoAdvice=由于配置问题, 跳过了打包程序{0}: {1} -MSG_BundlerRuntimeException=由于{1}, 打包程序{0}失败 +ERR_NoMainClass=缺少主应用程序类 +ERR_UnsupportedOption=选项 [{0}] 在此平台上无效 +ERR_InvalidTypeOption=选项 [{0}] 对于类型 [{1}] 无效 +ERR_NoInstallerEntryPoint=在没有 --module 或 --main-jar 入口点选项时,选项 [{0}] 无效 +ERR_MutuallyExclusiveOptions=选项 [{0}] 和 [{1}] 相互排斥 +ERR_InvalidOptionWithAppImageSigning=对应用程序映像进行签名时,选项 [{0}] 无效 -ERR_NoMainClass=错误:缺少主应用程序类 -ERR_UnsupportedOption=错误:选项 [{0}] 在此平台上无效 -ERR_InvalidTypeOption=错误:选项 [{0}] 对于类型 [{1}] 无效 -ERR_NoInstallerEntryPoint=错误:在没有 --module 或 --main-jar 入口点选项时,选项 [{0}] 无效 -ERR_MutuallyExclusiveOptions=错误:选项 [{0}] 和 [{1}] 相互排斥 -ERR_InvalidOptionWithAppImageSigning=错误:对应用程序映像签名时,选项 [{0}] 无效 - -ERR_MissingArgument=错误: 缺少参数: {0} -ERR_MissingRequiredArgument=错误:{0} 参数至少需要 [{1}] 参数之一 -ERR_AppImageNotExist=错误:应用程序映像目录 "{0}" 不存在 -ERR_NoAddLauncherName=错误:--add-launcher 选项需要一个名称和一个文件路径 (--add-launcher =) -ERR_NoUniqueName=错误:--add-launcher = 需要一个唯一的名称 -ERR_InvalidAppName=错误:应用程序名称 {0} 无效 -ERR_InvalidSLName=错误:添加启动程序名称 {0} 无效 -ERR_IconFileNotExit=错误:指定的图标文件 [{0}] 不存在 -ERR_LicenseFileNotExit=错误:指定的许可证文件不存在 -ERR_BuildRootInvalid=错误:临时目录 ({0}) 必须是不存在的目录或空白目录 -ERR_InvalidOption=错误:选项 [{0}] 无效 -ERR_InvalidInstallerType=错误:类型 [{0}] 无效或不受支持 -ERR_BothMainJarAndModule=错误:不能同时包含 --main-jar 和 --module 选项 -ERR_NoEntryPoint=错误:创建应用程序映像需要 --main-jar 或 --module 选项 -ERR_CannotParseOptions=错误:正在处理 @filename 选项:{0} -ERR_MissingJLinkOptMacAppStore=错误:对于 --jlink-options 参数,--mac-app-store 参数需要 {0} 选项 -ERR_MacAppStoreRuntimeBinExists=错误:运行时映像 "{0}" 不应包含 "bin" 文件夹。生成与 --mac-app-store 参数一起使用的运行时映像时,使用 --strip-native-commands jlink 选项。 +ERR_MissingArgument2=缺少参数:{0} 或 {1} +ERR_InvalidAppName=应用程序名称 {0} 无效 +ERR_InvalidSLName=添加启动程序名称 {0} 无效 +ERR_InvalidOption=选项 [{0}] 无效 +ERR_InvalidInstallerType=类型 [{0}] 无效或不受支持 +ERR_NoEntryPoint=创建应用程序映像需要 --main-jar 或 --module 选项 +ERR_CannotParseOptions=正在处理 @filename 选项:{0} +ERR_MissingJLinkOptMacAppStore=对于 --jlink-options 参数,--mac-app-store 参数需要 {0} 选项 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 3e6f8e30d6a..baaba64b398 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 @@ -23,15 +23,9 @@ # questions. # # - -app.bundler.name=Windows-Anwendungsimage -exe.bundler.name=EXE-Installationsprogrammpackage -msi.bundler.name=MSI-Installationsprogrammpackage - param.menu-group.default=Unbekannt resource.executable-properties-template=Vorlage für das Erstellen der ausführbaren Eigenschaftendatei -resource.setup-icon=Symbol für Dialogfeld "Setup" resource.post-msi-script=Auszuführendes Skript nach dem Erstellen der MSI-Datei für das EXE-Installationsprogramm resource.wxl-file=WiX-Lokalisierungsdatei resource.main-wix-file=Haupt-WiX-Projektdatei @@ -65,12 +59,10 @@ message.potential.windows.defender.issue=Warnung: Windows Defender verhindert ev message.outputting-to-location=EXE für Installationsprogramm wird generiert in: {0}. message.output-location=Installationsprogramm (.exe) gespeichert in: {0} message.tool-version=[{0}]-Version [{1}] erkannt. -message.creating-association-with-null-extension=Verknüpfung mit Nullerweiterung wird erstellt. message.wrong-tool-version=[{0}]-Version {1} wurde erkannt. Erforderlich ist jedoch Version {2}. message.use-wix36-features=WiX {0} erkannt. Erweiterte Bereinigungsaktion wird aktiviert. message.product-code=MSI-ProductCode: {0}. message.upgrade-code=MSI-UpgradeCode: {0}. message.preparing-msi-config=MSI-Konfiguration wird vorbereitet: {0}. message.generating-msi=MSI wird generiert: {0}. -message.invalid.install.dir=Warnung: Ungültiges Installationsverzeichnis {0}. Installationsverzeichnis muss ein relativer Unterpfad unter dem Standardinstallationsverzeichnis wie "Programme" sein. Der Anwendungsname "{1}" wird als Standardwert verwendet. 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 07604dc9980..119c7532b1f 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 @@ -23,15 +23,9 @@ # questions. # # - -app.bundler.name=Windowsアプリケーション・イメージ -exe.bundler.name=EXEインストーラ・パッケージ -msi.bundler.name=MSIインストーラ・パッケージ - param.menu-group.default=不明 resource.executable-properties-template=実行可能なプロパティ・ファイル作成用のテンプレート -resource.setup-icon=設定ダイアログ・アイコン resource.post-msi-script=exeインストーラのmsiファイルが作成された後に実行するスクリプト resource.wxl-file=WiXローカリゼーション・ファイル resource.main-wix-file=メインWiXプロジェクト・ファイル @@ -65,12 +59,10 @@ message.potential.windows.defender.issue=警告: Windows Defenderが原因でjpa message.outputting-to-location=インストーラのEXEを次に生成しています: {0} message.output-location=インストーラ(.exe)は次に保存されました: {0} message.tool-version=[{0}]バージョン[{1}]が検出されました。 -message.creating-association-with-null-extension=null拡張子との関連付けを作成しています。 message.wrong-tool-version=[{0}]バージョン{1}が検出されましたが、バージョン{2}が必要です。 message.use-wix36-features=WiX {0}が検出されました。拡張クリーンアップ・アクションを有効化しています。 message.product-code=MSI ProductCode: {0}。 message.upgrade-code=MSI UpgradeCode: {0}。 message.preparing-msi-config=MSI構成を準備しています: {0} message.generating-msi=MSIを生成しています: {0}。 -message.invalid.install.dir=警告: インストール・ディレクトリ{0}が無効です。インストール・ディレクトリはデフォルトのインストール場所("プログラム・ファイル"など)の下の相対サブパスである必要があります。アプリケーション名"{1}"にデフォルト設定されています。 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 7eae69fba2f..66d8a9d8b96 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 @@ -23,15 +23,9 @@ # questions. # # - -app.bundler.name=Windows 应用程序映像 -exe.bundler.name=EXE 安装程序包 -msi.bundler.name=MSI 安装程序包 - param.menu-group.default=未知 resource.executable-properties-template=用于创建可执行属性文件的模板 -resource.setup-icon=设置对话框图标 resource.post-msi-script=在为 exe 安装程序创建 msi 文件之后要运行的脚本 resource.wxl-file=WiX 本地化文件 resource.main-wix-file=主 WiX 项目文件 @@ -65,12 +59,10 @@ message.potential.windows.defender.issue=警告:Windows Defender 可能会阻 message.outputting-to-location=正在为安装程序生成 EXE, 位置: {0}。 message.output-location=安装程序 (.exe) 已保存到: {0} message.tool-version=检测到 [{0}] 版本 [{1}]。 -message.creating-association-with-null-extension=正在使用空扩展名创建关联。 message.wrong-tool-version=检测到 [{0}] 版本 {1}, 但需要版本 {2}。 message.use-wix36-features=检测到 WiX {0}。正在启用高级清除操作。 message.product-code=MSI ProductCode:{0}。 message.upgrade-code=MSI UpgradeCode:{0}。 message.preparing-msi-config=正在准备 MSI 配置: {0}。 message.generating-msi=正在生成 MSI: {0}。 -message.invalid.install.dir=警告:安装目录 {0} 无效。安装目录应当是默认安装位置(如 "Program Files")下面的相对子路径。默认为应用程序名称 "{1}"。 From 2241218ef64ed6cb51f962f3ab6db1a766f1744f Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 16 Dec 2025 21:25:41 +0000 Subject: [PATCH 324/706] 8373631: Improve classes in the "jdk.jpackage.internal.util.function" package Reviewed-by: almatvee --- .../jdk/jpackage/internal/MacFromOptions.java | 12 +- .../jdk/jpackage/internal/TempKeychain.java | 4 +- .../jdk/jpackage/internal/AppImageFile.java | 2 +- .../jpackage/internal/PackagingPipeline.java | 2 +- .../jdk/jpackage/internal/cli/Main.java | 2 +- .../internal/cli/OptionsProcessor.java | 2 +- .../jdk/jpackage/internal/util/FileUtils.java | 5 +- .../jdk/jpackage/internal/util/Result.java | 61 +- .../jdk/jpackage/internal/util/XmlUtils.java | 6 +- .../internal/util/function/ExceptionBox.java | 64 +- .../util/function/ThrowingBiConsumer.java | 12 +- .../util/function/ThrowingBiFunction.java | 12 +- .../util/function/ThrowingConsumer.java | 12 +- .../util/function/ThrowingFunction.java | 12 +- .../util/function/ThrowingRunnable.java | 12 +- .../util/function/ThrowingSupplier.java | 12 +- .../util/function/ThrowingUnaryOperator.java | 12 +- .../internal/WinSystemEnvironment.java | 2 +- .../jdk/jpackage/test/AnnotationsTest.java | 6 +- .../jdk/jpackage/test/PackageTestTest.java | 6 +- .../jdk/jpackage/test/TKitTest.java | 11 +- .../jdk/jpackage/test/AdditionalLauncher.java | 4 +- .../jdk/jpackage/test/JPackageCommand.java | 22 +- .../jpackage/test/JPackageStringBundle.java | 6 +- .../jdk/jpackage/test/LauncherVerifier.java | 2 +- .../jdk/jpackage/test/LinuxHelper.java | 2 +- .../helpers/jdk/jpackage/test/MacHelper.java | 2 +- .../helpers/jdk/jpackage/test/MacSign.java | 19 +- .../jdk/jpackage/test/MacSignVerify.java | 4 +- .../helpers/jdk/jpackage/test/Main.java | 9 +- .../helpers/jdk/jpackage/test/MethodCall.java | 4 +- .../jdk/jpackage/test/ObjectMapper.java | 8 +- .../jdk/jpackage/test/PackageTest.java | 26 +- .../helpers/jdk/jpackage/test/TKit.java | 39 +- .../jdk/jpackage/test/TestBuilder.java | 16 +- .../jdk/jpackage/test/TestInstance.java | 18 +- .../test/WinExecutableIconVerifier.java | 6 +- .../jdk/jpackage/test/WindowsHelper.java | 4 +- .../internal/PackagingPipelineTest.java | 4 +- .../cli/OptionsValidationFailTest.java | 2 +- .../jpackage/internal/util/ResultTest.java | 602 ++++++++++++++++++ .../util/function/ExceptionBoxTest.java | 246 +++++++ .../util/function/FunctionalTest.java | 189 ++++++ .../tools/jdk/jpackage/test/JUnitAdapter.java | 6 +- .../tools/jpackage/linux/AppAboutUrlTest.java | 4 +- .../jpackage/macosx/CustomInfoPListTest.java | 12 +- .../jpackage/macosx/EntitlementsTest.java | 2 +- .../tools/jpackage/share/AppContentTest.java | 3 +- test/jdk/tools/jpackage/share/AsyncTest.java | 27 +- test/jdk/tools/jpackage/share/BasicTest.java | 4 +- test/jdk/tools/jpackage/share/IconTest.java | 4 +- .../tools/jpackage/share/InOutPathTest.java | 23 +- .../tools/jpackage/share/PerUserCfgTest.java | 4 +- .../jpackage/share/RuntimePackageTest.java | 4 +- .../jdk/tools/jpackage/share/ServiceTest.java | 4 +- 55 files changed, 1339 insertions(+), 261 deletions(-) create mode 100644 test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/ResultTest.java create mode 100644 test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/function/ExceptionBoxTest.java create mode 100644 test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/function/FunctionalTest.java diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromOptions.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromOptions.java index 074014dede0..b1094331740 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromOptions.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromOptions.java @@ -49,7 +49,7 @@ import static jdk.jpackage.internal.cli.StandardOption.PREDEFINED_RUNTIME_IMAGE; import static jdk.jpackage.internal.model.MacPackage.RUNTIME_BUNDLE_LAYOUT; import static jdk.jpackage.internal.model.StandardPackageType.MAC_DMG; import static jdk.jpackage.internal.model.StandardPackageType.MAC_PKG; -import static jdk.jpackage.internal.util.function.ExceptionBox.rethrowUnchecked; +import static jdk.jpackage.internal.util.function.ExceptionBox.toUnchecked; import java.nio.file.Path; import java.util.Objects; @@ -106,7 +106,7 @@ final class MacFromOptions { final boolean sign = MAC_SIGN.findIn(options).orElse(false); final boolean appStore = MAC_APP_STORE.findIn(options).orElse(false); - final var appResult = Result.create(() -> createMacApplicationInternal(options)); + final var appResult = Result.of(() -> createMacApplicationInternal(options)); final Optional pkgBuilder; if (appResult.hasValue()) { @@ -146,18 +146,18 @@ final class MacFromOptions { final var expiredAppCertException = appResult.firstError().orElseThrow(); - final var pkgSignConfigResult = Result.create(signingIdentityBuilder::create); + final var pkgSignConfigResult = Result.of(signingIdentityBuilder::create); try { rethrowIfNotExpiredCertificateException(pkgSignConfigResult); // The certificate for the package signing config is also expired! } catch (RuntimeException ex) { // Some error occurred trying to configure the signing config for the package. // Ignore it, bail out with the first error. - rethrowUnchecked(expiredAppCertException); + throw toUnchecked(expiredAppCertException); } Log.error(pkgSignConfigResult.firstError().orElseThrow().getMessage()); - rethrowUnchecked(expiredAppCertException); + throw toUnchecked(expiredAppCertException); } } @@ -303,7 +303,7 @@ final class MacFromOptions { } } - rethrowUnchecked(ex); + throw toUnchecked(ex); } private static SigningIdentityBuilder createSigningIdentityBuilder(Options options) { diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/TempKeychain.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/TempKeychain.java index 97709678c67..b38faecd96f 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/TempKeychain.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/TempKeychain.java @@ -35,7 +35,7 @@ import jdk.jpackage.internal.util.function.ThrowingConsumer; final class TempKeychain implements Closeable { - static void withKeychains(ThrowingConsumer> keychainConsumer, List keychains) throws Throwable { + static void withKeychains(ThrowingConsumer, ? extends Exception> keychainConsumer, List keychains) throws Exception { keychains.forEach(Objects::requireNonNull); if (keychains.isEmpty() || OSVersion.current().compareTo(new OSVersion(10, 12)) < 0) { keychainConsumer.accept(keychains); @@ -47,7 +47,7 @@ final class TempKeychain implements Closeable { } } - static void withKeychain(ThrowingConsumer keychainConsumer, Keychain keychain) throws Throwable { + static void withKeychain(ThrowingConsumer keychainConsumer, Keychain keychain) throws Exception { Objects.requireNonNull(keychainConsumer); withKeychains(keychains -> { keychainConsumer.accept(keychains.getFirst()); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile.java index b6b4322302e..5f473b554be 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile.java @@ -198,7 +198,7 @@ final class AppImageFile { } catch (XPathExpressionException ex) { // This should never happen as XPath expressions should be correct - throw ExceptionBox.rethrowUnchecked(ex); + throw ExceptionBox.toUnchecked(ex); } catch (SAXException ex) { // Malformed input XML throw new JPackageException(I18N.format("error.malformed-app-image-file", relativeAppImageFilePath, appImageDir), ex); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagingPipeline.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagingPipeline.java index a2750fee260..2ee35b658ea 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagingPipeline.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagingPipeline.java @@ -508,7 +508,7 @@ final class PackagingPipeline { try { builder.create().call(); } catch (Exception ex) { - throw ExceptionBox.rethrowUnchecked(ex); + throw ExceptionBox.toUnchecked(ex); } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/Main.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/Main.java index af51bc9fd98..57f627b1548 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/Main.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/Main.java @@ -110,7 +110,7 @@ public final class Main { Log.fatalError(I18N.format("ERR_CannotParseOptions", ex.getMessage())); return 1; } catch (IOException ex) { - throw ExceptionBox.rethrowUnchecked(ex); + throw ExceptionBox.toUnchecked(ex); } final var bundlingEnv = ServiceLoader.load(CliBundlingEnvironment.class, diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionsProcessor.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionsProcessor.java index 1bc5c36989f..54003b714a2 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionsProcessor.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionsProcessor.java @@ -87,7 +87,7 @@ final class OptionsProcessor { final var untypedOptions = optionsBuilder.create(); // Create command line structure analyzer. - final var analyzerResult = Result.create(() -> new OptionsAnalyzer(untypedOptions, bundlingEnv)); + final var analyzerResult = Result.of(() -> new OptionsAnalyzer(untypedOptions, bundlingEnv)); if (analyzerResult.hasErrors()) { // Failed to derive the bundling operation from the command line. allErrors.addAll(analyzerResult.mapErrors().errors()); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/FileUtils.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/FileUtils.java index 49c395642f4..2f7f2682a71 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/FileUtils.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/FileUtils.java @@ -37,7 +37,6 @@ import java.util.ArrayList; import java.util.List; import java.util.Optional; import jdk.internal.util.OperatingSystem; -import jdk.jpackage.internal.util.function.ExceptionBox; import jdk.jpackage.internal.util.function.ThrowingConsumer; public final class FileUtils { @@ -170,15 +169,13 @@ public final class FileUtils { } } - private void runActionOnPath(ThrowingConsumer action, Path path) { + private void runActionOnPath(ThrowingConsumer action, Path path) { try { action.accept(path); } catch (IOException ex) { if (this.ex == null) { this.ex = ex; } - } catch (Throwable t) { - throw ExceptionBox.rethrowUnchecked(t); } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/Result.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/Result.java index 8a61acafe77..46e99f134df 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/Result.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/Result.java @@ -24,33 +24,28 @@ */ package jdk.jpackage.internal.util; -import static jdk.jpackage.internal.util.function.ExceptionBox.rethrowUnchecked; - import java.util.Collection; import java.util.List; +import java.util.Objects; import java.util.Optional; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Supplier; -import java.util.function.UnaryOperator; import java.util.stream.StreamSupport; +import jdk.jpackage.internal.util.function.ExceptionBox; +import jdk.jpackage.internal.util.function.ThrowingSupplier; public record Result(Optional value, Collection errors) { public Result { if (value.isEmpty() == errors.isEmpty()) { - throw new IllegalArgumentException(); + throw new IllegalArgumentException("'value' and 'errors' cannot both be non-empty or both be empty"); } - - if (value.isEmpty() && errors.isEmpty()) { - throw new IllegalArgumentException("Error collection must be non-empty"); - } - } public T orElseThrow() { firstError().ifPresent(ex -> { - rethrowUnchecked(ex); + throw ExceptionBox.toUnchecked(ex); }); return value.orElseThrow(); } @@ -64,7 +59,16 @@ public record Result(Optional value, Collection error } public Result map(Function conv) { - return new Result<>(value.map(conv), errors); + if (hasValue()) { + var mapped = value.map(conv); + if (mapped.isEmpty()) { + throw new NullPointerException(); + } else { + return new Result<>(mapped, errors); + } + } else { + return mapErrors(); + } } public Result flatMap(Function> conv) { @@ -73,12 +77,12 @@ public record Result(Optional value, Collection error }); } - public Result mapErrors(UnaryOperator> errorsMapper) { - return new Result<>(value, errorsMapper.apply(errors)); - } - + @SuppressWarnings("unchecked") public Result mapErrors() { - return new Result<>(Optional.empty(), errors); + if (hasValue()) { + throw new IllegalStateException("Can not map errors from a result without errors"); + } + return (Result)this; } public Result peekErrors(Consumer> consumer) { @@ -97,12 +101,31 @@ public record Result(Optional value, Collection error return errors.stream().findFirst(); } - public static Result create(Supplier supplier) { + public static Result of(Supplier supplier) { + return of(supplier::get, RuntimeException.class); + } + + public static Result of( + ThrowingSupplier supplier, Class supplierExceptionType) { + + Objects.requireNonNull(supplier); + Objects.requireNonNull(supplierExceptionType); + + T value; try { - return ofValue(supplier.get()); + value = supplier.get(); } catch (Exception ex) { - return ofError(ex); + if (supplierExceptionType.isInstance(ex)) { + return ofError(ex); + } else if (ex instanceof RuntimeException rex) { + throw rex; + } else { + // Unreachable because the `supplier` can throw exceptions of type or supertype `E` or runtime exceptions. + throw ExceptionBox.reachedUnreachable(); + } } + + return ofValue(value); } public static Result ofValue(T value) { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/XmlUtils.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/XmlUtils.java index c8761259254..f62ffee9260 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/XmlUtils.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/XmlUtils.java @@ -24,7 +24,7 @@ */ package jdk.jpackage.internal.util; -import static jdk.jpackage.internal.util.function.ExceptionBox.rethrowUnchecked; +import static jdk.jpackage.internal.util.function.ExceptionBox.toUnchecked; import java.io.IOException; import java.io.Writer; @@ -80,7 +80,7 @@ public final class XmlUtils { xml.flush(); xml.close(); } catch (XMLStreamException ex) { - throw rethrowUnchecked(ex); + throw toUnchecked(ex); } } @@ -101,7 +101,7 @@ public final class XmlUtils { xml.flush(); xml.close(); } catch (XMLStreamException ex) { - throw rethrowUnchecked(ex); + throw toUnchecked(ex); } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ExceptionBox.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ExceptionBox.java index 8428d5d1e7f..40503469873 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ExceptionBox.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ExceptionBox.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, 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,23 +30,55 @@ public class ExceptionBox extends RuntimeException { private static final long serialVersionUID = 1L; - public static RuntimeException rethrowUnchecked(Throwable throwable) { - if (throwable instanceof RuntimeException err) { - throw err; + public static RuntimeException toUnchecked(Exception ex) { + switch (ex) { + case RuntimeException rex -> { + return rex; + } + case InvocationTargetException itex -> { + var t = itex.getCause(); + if (t instanceof Exception cause) { + return toUnchecked(cause); + } else { + throw (Error)t; + } + } + case InterruptedException _ -> { + Thread.currentThread().interrupt(); + return new ExceptionBox(ex); + } + default -> { + return new ExceptionBox(ex); + } } - - if (throwable instanceof Error err) { - throw err; - } - - if (throwable instanceof InvocationTargetException err) { - throw rethrowUnchecked(err.getCause()); - } - - throw new ExceptionBox(throwable); } - private ExceptionBox(Throwable throwable) { - super(throwable); + public static Exception unbox(Throwable t) { + switch (t) { + case ExceptionBox ex -> { + return unbox(ex.getCause()); + } + case InvocationTargetException ex -> { + return unbox(ex.getCause()); + } + case Exception ex -> { + return ex; + } + case Error err -> { + throw err; + } + default -> { + // Unreachable + throw reachedUnreachable(); + } + } + } + + public static Error reachedUnreachable() { + return new AssertionError("Reached unreachable!"); + } + + private ExceptionBox(Exception ex) { + super(ex); } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingBiConsumer.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingBiConsumer.java index 3ed0fd67d84..374eaf803d9 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingBiConsumer.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingBiConsumer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, 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,17 +27,17 @@ package jdk.jpackage.internal.util.function; import java.util.function.BiConsumer; @FunctionalInterface -public interface ThrowingBiConsumer { +public interface ThrowingBiConsumer { - void accept(T t, U u) throws Throwable; + void accept(T t, U u) throws E; public static BiConsumer toBiConsumer( - ThrowingBiConsumer v) { + ThrowingBiConsumer v) { return (t, u) -> { try { v.accept(t, u); - } catch (Throwable ex) { - throw ExceptionBox.rethrowUnchecked(ex); + } catch (Exception ex) { + throw ExceptionBox.toUnchecked(ex); } }; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingBiFunction.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingBiFunction.java index 8c2df773eb5..13b0b53c887 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingBiFunction.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingBiFunction.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, 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,17 +27,17 @@ package jdk.jpackage.internal.util.function; import java.util.function.BiFunction; @FunctionalInterface -public interface ThrowingBiFunction { +public interface ThrowingBiFunction { - R apply(T t, U u) throws Throwable; + R apply(T t, U u) throws E; public static BiFunction toBiFunction( - ThrowingBiFunction v) { + ThrowingBiFunction v) { return (t, u) -> { try { return v.apply(t, u); - } catch (Throwable ex) { - throw ExceptionBox.rethrowUnchecked(ex); + } catch (Exception ex) { + throw ExceptionBox.toUnchecked(ex); } }; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingConsumer.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingConsumer.java index ef1b0a61df7..38342a361c0 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingConsumer.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingConsumer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, 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,16 +27,16 @@ package jdk.jpackage.internal.util.function; import java.util.function.Consumer; @FunctionalInterface -public interface ThrowingConsumer { +public interface ThrowingConsumer { - void accept(T t) throws Throwable; + void accept(T t) throws E; - public static Consumer toConsumer(ThrowingConsumer v) { + public static Consumer toConsumer(ThrowingConsumer v) { return o -> { try { v.accept(o); - } catch (Throwable ex) { - throw ExceptionBox.rethrowUnchecked(ex); + } catch (Exception ex) { + throw ExceptionBox.toUnchecked(ex); } }; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingFunction.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingFunction.java index 2b5eae43842..5bbfb254858 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingFunction.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingFunction.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, 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,16 +27,16 @@ package jdk.jpackage.internal.util.function; import java.util.function.Function; @FunctionalInterface -public interface ThrowingFunction { +public interface ThrowingFunction { - R apply(T t) throws Throwable; + R apply(T t) throws E; - public static Function toFunction(ThrowingFunction v) { + public static Function toFunction(ThrowingFunction v) { return t -> { try { return v.apply(t); - } catch (Throwable ex) { - throw ExceptionBox.rethrowUnchecked(ex); + } catch (Exception ex) { + throw ExceptionBox.toUnchecked(ex); } }; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingRunnable.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingRunnable.java index 7c75c4d9753..f3ce5affbbf 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingRunnable.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingRunnable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, 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,16 +25,16 @@ package jdk.jpackage.internal.util.function; @FunctionalInterface -public interface ThrowingRunnable { +public interface ThrowingRunnable { - void run() throws Throwable; + void run() throws E; - public static Runnable toRunnable(ThrowingRunnable v) { + public static Runnable toRunnable(ThrowingRunnable v) { return () -> { try { v.run(); - } catch (Throwable ex) { - throw ExceptionBox.rethrowUnchecked(ex); + } catch (Exception ex) { + throw ExceptionBox.toUnchecked(ex); } }; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingSupplier.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingSupplier.java index c69c4729190..4f194a0f4d2 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingSupplier.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingSupplier.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, 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,16 +27,16 @@ package jdk.jpackage.internal.util.function; import java.util.function.Supplier; @FunctionalInterface -public interface ThrowingSupplier { +public interface ThrowingSupplier { - T get() throws Throwable; + T get() throws E; - public static Supplier toSupplier(ThrowingSupplier v) { + public static Supplier toSupplier(ThrowingSupplier v) { return () -> { try { return v.get(); - } catch (Throwable ex) { - throw ExceptionBox.rethrowUnchecked(ex); + } catch (Exception ex) { + throw ExceptionBox.toUnchecked(ex); } }; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingUnaryOperator.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingUnaryOperator.java index 7a2a0fd67cf..3d757bbec48 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingUnaryOperator.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/function/ThrowingUnaryOperator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, 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,17 +27,17 @@ package jdk.jpackage.internal.util.function; import java.util.function.UnaryOperator; @FunctionalInterface -public interface ThrowingUnaryOperator { +public interface ThrowingUnaryOperator { - T apply(T t) throws Throwable; + T apply(T t) throws E; public static UnaryOperator toUnaryOperator( - ThrowingUnaryOperator v) { + ThrowingUnaryOperator v) { return t -> { try { return v.apply(t); - } catch (Throwable ex) { - throw ExceptionBox.rethrowUnchecked(ex); + } catch (Exception ex) { + throw ExceptionBox.toUnchecked(ex); } }; } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinSystemEnvironment.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinSystemEnvironment.java index ab0cc37b9fe..c0bea444e00 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinSystemEnvironment.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinSystemEnvironment.java @@ -34,6 +34,6 @@ record WinSystemEnvironment(WixToolset wixToolset) implements SystemEnvironment } static Result create() { - return Result.create(WixTool::createToolset).map(WinSystemEnvironment::new); + return Result.of(WixTool::createToolset).map(WinSystemEnvironment::new); } } diff --git a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/AnnotationsTest.java b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/AnnotationsTest.java index f88d1f81a34..42dd8eda19b 100644 --- a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/AnnotationsTest.java +++ b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/AnnotationsTest.java @@ -353,12 +353,12 @@ public class AnnotationsTest extends JUnitAdapter { try { log = captureJPackageTestLog(() -> Main.main(TestBuilder.build().workDirRoot(workDir), args)); assertRecordedTestDescs(expectedTestDescs); - } catch (Throwable t) { - t.printStackTrace(System.err); + } catch (Exception ex) { + ex.printStackTrace(System.err); System.exit(1); // Redundant, but needed to suppress "The local variable log may not have been initialized" error. - throw new RuntimeException(t); + throw new RuntimeException(ex); } final var actualTestCount = Integer.parseInt(log.stream().dropWhile(line -> { diff --git a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/PackageTestTest.java b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/PackageTestTest.java index 4723f4dadbd..16909d0eb40 100644 --- a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/PackageTestTest.java +++ b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/PackageTestTest.java @@ -168,7 +168,7 @@ public class PackageTestTest extends JUnitAdapter { protected final int expectedTicks; } - private static class CountingConsumer extends TickCounter implements ThrowingConsumer { + private static class CountingConsumer extends TickCounter implements ThrowingConsumer { @Override public void accept(JPackageCommand cmd) { @@ -188,7 +188,7 @@ public class PackageTestTest extends JUnitAdapter { private final String label; } - private static class CountingRunnable extends TickCounter implements ThrowingRunnable { + private static class CountingRunnable extends TickCounter implements ThrowingRunnable { @Override public void run() { @@ -208,7 +208,7 @@ public class PackageTestTest extends JUnitAdapter { private final String label; } - private static class CountingBundleVerifier extends TickCounter implements ThrowingBiConsumer { + private static class CountingBundleVerifier extends TickCounter implements ThrowingBiConsumer { @Override public void accept(JPackageCommand cmd, Executor.Result result) { diff --git a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/TKitTest.java b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/TKitTest.java index 590f23b002d..00172791ad8 100644 --- a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/TKitTest.java +++ b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/TKitTest.java @@ -25,6 +25,7 @@ package jdk.jpackage.test; import static jdk.jpackage.internal.util.function.ThrowingRunnable.toRunnable; import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier; +import java.io.IOException; import java.lang.reflect.Method; import java.nio.file.Files; import java.nio.file.Path; @@ -212,13 +213,13 @@ public class TKitTest extends JUnitAdapter { @Test @ParameterSupplier("testCreateTempPath") - public void testCreateTempFile(CreateTempTestSpec testSpec) throws Throwable { + public void testCreateTempFile(CreateTempTestSpec testSpec) throws IOException { testSpec.test(TKit::createTempFile, TKit::assertFileExists); } @Test @ParameterSupplier("testCreateTempPath") - public void testCreateTempDirectory(CreateTempTestSpec testSpec) throws Throwable { + public void testCreateTempDirectory(CreateTempTestSpec testSpec) throws IOException { testSpec.test(TKit::createTempDirectory, TKit::assertDirectoryEmpty); } @@ -232,7 +233,7 @@ public class TKitTest extends JUnitAdapter { } } - void test(ThrowingFunction createTempPath, Consumer assertTempPathExists) throws Throwable { + void test(ThrowingFunction createTempPath, Consumer assertTempPathExists) throws IOException { for (var existingFile : existingFiles) { existingFile = TKit.workDir().resolve(existingFile); @@ -333,14 +334,14 @@ public class TKitTest extends JUnitAdapter { }).toList(); } - private static void runAssertWithExpectedLogOutput(ThrowingRunnable action, + private static void runAssertWithExpectedLogOutput(ThrowingRunnable action, boolean expectFail, String... expectLogStrings) { runWithExpectedLogOutput(() -> { TKit.assertAssert(!expectFail, toRunnable(action)); }, expectLogStrings); } - private static void runWithExpectedLogOutput(ThrowingRunnable action, + private static void runWithExpectedLogOutput(ThrowingRunnable action, String... expectLogStrings) { final var output = JUnitAdapter.captureJPackageTestLog(action); if (output.size() == 1 && expectLogStrings.length == 1) { diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/AdditionalLauncher.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/AdditionalLauncher.java index 95373fa0d61..8ce3f4d2948 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/AdditionalLauncher.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/AdditionalLauncher.java @@ -152,7 +152,7 @@ public final class AdditionalLauncher { } public AdditionalLauncher setPersistenceHandler( - ThrowingBiConsumer>> handler) { + ThrowingBiConsumer>, ? extends Exception> handler) { if (handler != null) { createFileHandler = ThrowingBiConsumer.toBiConsumer(handler); } else { @@ -182,7 +182,7 @@ public final class AdditionalLauncher { Optional.ofNullable(defaultArguments), Optional.ofNullable(icon), rawProperties); } - private ThrowingConsumer createVerifierAsConsumer() { + private ThrowingConsumer createVerifierAsConsumer() { return cmd -> { createVerifier().verify(cmd, verifyActions.stream().sorted(Comparator.comparing(Action::ordinal)).toArray(Action[]::new)); }; diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java index 197e835ed8d..f80f1e61cd3 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java @@ -291,7 +291,7 @@ public class JPackageCommand extends CommandArguments { public JPackageCommand setFakeRuntime() { verifyMutable(); - ThrowingConsumer createBulkFile = path -> { + ThrowingConsumer createBulkFile = path -> { Files.createDirectories(path.getParent()); try (FileOutputStream out = new FileOutputStream(path.toFile())) { byte[] bytes = new byte[4 * 1024]; @@ -328,12 +328,12 @@ public class JPackageCommand extends CommandArguments { .removeArgumentWithValue("--input"); } - JPackageCommand addPrerequisiteAction(ThrowingConsumer action) { + JPackageCommand addPrerequisiteAction(ThrowingConsumer action) { prerequisiteActions.add(action); return this; } - JPackageCommand addVerifyAction(ThrowingConsumer action) { + JPackageCommand addVerifyAction(ThrowingConsumer action) { return addVerifyAction(action, ActionRole.DEFAULT); } @@ -343,12 +343,12 @@ public class JPackageCommand extends CommandArguments { ; } - JPackageCommand addVerifyAction(ThrowingConsumer action, ActionRole actionRole) { + JPackageCommand addVerifyAction(ThrowingConsumer action, ActionRole actionRole) { verifyActions.add(action, actionRole); return this; } - Stream> getVerifyActionsWithRole(ActionRole actionRole) { + Stream> getVerifyActionsWithRole(ActionRole actionRole) { return verifyActions.actionsWithRole(actionRole); } @@ -1648,16 +1648,16 @@ public class JPackageCommand extends CommandArguments { actions.addAll(other.actions); } - void add(ThrowingConsumer action) { + void add(ThrowingConsumer action) { add(action, ActionRole.DEFAULT); } - void add(ThrowingConsumer action, ActionRole role) { + void add(ThrowingConsumer action, ActionRole role) { verifyMutable(); actions.add(new Action(action, role)); } - Stream> actionsWithRole(ActionRole role) { + Stream> actionsWithRole(ActionRole role) { Objects.requireNonNull(role); return actions.stream().filter(action -> { return Objects.equals(action.role(), role); @@ -1666,7 +1666,7 @@ public class JPackageCommand extends CommandArguments { private static final class Action implements Consumer { - Action(ThrowingConsumer impl, ActionRole role) { + Action(ThrowingConsumer impl, ActionRole role) { this.impl = Objects.requireNonNull(impl); this.role = Objects.requireNonNull(role); } @@ -1675,7 +1675,7 @@ public class JPackageCommand extends CommandArguments { return role; } - ThrowingConsumer impl() { + ThrowingConsumer impl() { return impl; } @@ -1688,7 +1688,7 @@ public class JPackageCommand extends CommandArguments { } private final ActionRole role; - private final ThrowingConsumer impl; + private final ThrowingConsumer impl; private boolean executed; } diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageStringBundle.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageStringBundle.java index cdf2855faef..9425b84472c 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageStringBundle.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageStringBundle.java @@ -26,7 +26,7 @@ package jdk.jpackage.test; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.text.MessageFormat; -import static jdk.jpackage.internal.util.function.ExceptionBox.rethrowUnchecked; +import static jdk.jpackage.internal.util.function.ExceptionBox.toUnchecked; public enum JPackageStringBundle { @@ -40,7 +40,7 @@ public enum JPackageStringBundle { i18nClass_getString = i18nClass.getDeclaredMethod("getString", String.class); i18nClass_getString.setAccessible(true); } catch (ClassNotFoundException|NoSuchMethodException ex) { - throw rethrowUnchecked(ex); + throw toUnchecked(ex); } } @@ -51,7 +51,7 @@ public enum JPackageStringBundle { try { return (String)i18nClass_getString.invoke(i18nClass, key); } catch (IllegalAccessException|InvocationTargetException ex) { - throw rethrowUnchecked(ex); + throw toUnchecked(ex); } } diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherVerifier.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherVerifier.java index 89468ef7f86..15d96311d98 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherVerifier.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherVerifier.java @@ -102,7 +102,7 @@ public final class LauncherVerifier { EXECUTE_LAUNCHER(LauncherVerifier::executeLauncher), ; - Action(ThrowingBiConsumer action) { + Action(ThrowingBiConsumer action) { this.action = ThrowingBiConsumer.toBiConsumer(action); } diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java index e795f7c9760..3b02a3f6a69 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java @@ -645,7 +645,7 @@ public final class LinuxHelper { } private static void withTestFileAssociationsFile(FileAssociations fa, - ThrowingConsumer consumer) { + ThrowingConsumer consumer) { boolean iterated[] = new boolean[] { false }; PackageTest.withFileAssociationsTestRuns(fa, (testRun, testFiles) -> { if (!iterated[0]) { diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java index caeb0a206fc..678d25e4007 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java @@ -78,7 +78,7 @@ import org.xml.sax.SAXException; public final class MacHelper { public static void withExplodedDmg(JPackageCommand cmd, - ThrowingConsumer consumer) { + ThrowingConsumer consumer) { cmd.verifyIsOfType(PackageType.MAC_DMG); // Explode DMG assuming this can require interaction, thus use `yes`. diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacSign.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacSign.java index 7d2bb908edb..15249c51887 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacSign.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacSign.java @@ -42,6 +42,7 @@ import java.nio.file.Path; import java.nio.file.StandardCopyOption; import java.nio.file.StandardOpenOption; import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; import java.security.cert.CertificateExpiredException; import java.security.cert.CertificateFactory; import java.security.cert.CertificateNotYetValidException; @@ -526,7 +527,7 @@ public final class MacSign { private record CertificateStats(List allResolvedCertificateRequests, List knownCertificateRequests, - Map unmappedCertificates) { + Map unmappedCertificates) { static CertificateStats get(KeychainWithCertsSpec spec) { return CACHE.computeIfAbsent(spec, CertificateStats::create); @@ -560,7 +561,7 @@ public final class MacSign { private static CertificateStats create(KeychainWithCertsSpec spec) { final var allCertificates = spec.keychain().findCertificates(); final List allResolvedCertificateRequests = new ArrayList<>(); - final Map unmappedCertificates = new HashMap<>(); + final Map unmappedCertificates = new HashMap<>(); withTempDirectory(workDir -> { for (final var cert : allCertificates) { @@ -568,13 +569,7 @@ public final class MacSign { try { resolvedCertificateRequest = new ResolvedCertificateRequest(cert); } catch (RuntimeException ex) { - final Throwable t; - if (ex instanceof ExceptionBox) { - t = ex.getCause(); - } else { - t = ex; - } - unmappedCertificates.put(cert, t); + unmappedCertificates.put(cert, ExceptionBox.unbox(ex)); continue; } @@ -635,13 +630,13 @@ public final class MacSign { SHA1(20, () -> MessageDigest.getInstance("SHA-1")), SHA256(32, () -> MessageDigest.getInstance("SHA-256")); - DigestAlgorithm(int hashLength, ThrowingSupplier createDigest) { + DigestAlgorithm(int hashLength, ThrowingSupplier createDigest) { this.hashLength = hashLength; this.createDigest = createDigest; } final int hashLength; - final ThrowingSupplier createDigest; + final ThrowingSupplier createDigest; } public record CertificateHash(byte[] value, DigestAlgorithm alg) { @@ -1223,7 +1218,7 @@ public final class MacSign { }).map(KeychainWithCertsSpec::keychain); } - private static void withTempDirectory(ThrowingConsumer callback) { + private static void withTempDirectory(ThrowingConsumer callback) { try { final var dir = Files.createTempDirectory("jdk.jpackage.test"); try { diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacSignVerify.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacSignVerify.java index 123fba56b71..1f37829791e 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacSignVerify.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacSignVerify.java @@ -262,8 +262,8 @@ public final class MacSignVerify { signIdentities.add(new SignIdentity(name, fingerprint)); } while (lineIt.hasNext()); return signIdentities; - } catch (Throwable t) { - t.printStackTrace(); + } catch (Exception ex) { + ex.printStackTrace(); reportUnexpectedCommandOutcome(exec.getPrintableCommandLine(), result); return null; // Unreachable } diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Main.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Main.java index fa8fe166f5a..fee5b65c897 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Main.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Main.java @@ -37,15 +37,16 @@ import java.util.List; import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Stream; +import jdk.jpackage.internal.util.function.ExceptionBox; public final class Main { - public static void main(String... args) throws Throwable { + public static void main(String... args) throws Exception { main(TestBuilder.build(), args); } - public static void main(TestBuilder.Builder builder, String... args) throws Throwable { + public static void main(TestBuilder.Builder builder, String... args) throws Exception { boolean listTests = false; List tests = new ArrayList<>(); try (TestBuilder testBuilder = builder.testConsumer(tests::add).create()) { @@ -86,8 +87,8 @@ public final class Main { try { testBuilder.processCmdLineArg(arg); success = true; - } catch (Throwable throwable) { - TKit.unbox(throwable); + } catch (Exception ex) { + throw ExceptionBox.unbox(ex); } finally { if (!success) { TKit.log(String.format("Error processing parameter=[%s]", arg)); diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MethodCall.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MethodCall.java index 73d0a7fe495..b27531d0572 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MethodCall.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MethodCall.java @@ -40,7 +40,7 @@ import java.util.stream.Stream; import jdk.jpackage.internal.util.function.ThrowingConsumer; import jdk.jpackage.test.TestInstance.TestDesc; -class MethodCall implements ThrowingConsumer { +class MethodCall implements ThrowingConsumer { MethodCall(Object[] instanceCtorArgs, Method method, Object ... args) { Objects.requireNonNull(instanceCtorArgs); @@ -107,7 +107,7 @@ class MethodCall implements ThrowingConsumer { } @Override - public void accept(Object thiz) throws Throwable { + public void accept(Object thiz) throws Exception { method.invoke(thiz, methodArgs); } diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/ObjectMapper.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/ObjectMapper.java index f35e255951e..126d0e07f00 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/ObjectMapper.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/ObjectMapper.java @@ -24,7 +24,7 @@ package jdk.jpackage.test; import static java.util.stream.Collectors.groupingBy; import static java.util.stream.Collectors.toSet; -import static jdk.jpackage.internal.util.function.ExceptionBox.rethrowUnchecked; +import static jdk.jpackage.internal.util.function.ExceptionBox.toUnchecked; import static jdk.jpackage.internal.util.function.ThrowingConsumer.toConsumer; import static jdk.jpackage.internal.util.function.ThrowingRunnable.toRunnable; import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier; @@ -283,7 +283,7 @@ public final class ObjectMapper { try { return m.invoke(obj); } catch (IllegalAccessException ex) { - throw rethrowUnchecked(ex); + throw toUnchecked(ex); } catch (InvocationTargetException ex) { return map(ex.getTargetException()); } @@ -724,7 +724,7 @@ public final class ObjectMapper { } xml.writeEndElement(); } catch (Exception ex) { - rethrowUnchecked(ex); + throw toUnchecked(ex); } } @@ -740,7 +740,7 @@ public final class ObjectMapper { } xml.writeEndElement(); } catch (Exception ex) { - rethrowUnchecked(ex); + throw toUnchecked(ex); } } } diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageTest.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageTest.java index 5b3815510ce..2e4f11d056f 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageTest.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageTest.java @@ -22,7 +22,7 @@ */ package jdk.jpackage.test; -import static jdk.jpackage.internal.util.function.ExceptionBox.rethrowUnchecked; +import static jdk.jpackage.internal.util.function.ExceptionBox.toUnchecked; import static jdk.jpackage.internal.util.function.ThrowingBiConsumer.toBiConsumer; import static jdk.jpackage.internal.util.function.ThrowingConsumer.toConsumer; import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier; @@ -143,7 +143,7 @@ public final class PackageTest extends RunnablePackageTest { return this; } - private PackageTest addInitializer(ThrowingConsumer v, String id) { + private PackageTest addInitializer(ThrowingConsumer v, String id) { Objects.requireNonNull(v); if (id != null) { if (namedInitializers.contains(id)) { @@ -156,11 +156,11 @@ public final class PackageTest extends RunnablePackageTest { return this; } - private PackageTest addRunOnceInitializer(ThrowingRunnable v, String id) { + private PackageTest addRunOnceInitializer(ThrowingRunnable v, String id) { Objects.requireNonNull(v); - return addInitializer(new ThrowingConsumer() { + return addInitializer(new ThrowingConsumer() { @Override - public void accept(JPackageCommand unused) throws Throwable { + public void accept(JPackageCommand unused) throws Exception { if (!executed) { executed = true; v.run(); @@ -171,21 +171,21 @@ public final class PackageTest extends RunnablePackageTest { }, id); } - public PackageTest addInitializer(ThrowingConsumer v) { + public PackageTest addInitializer(ThrowingConsumer v) { return addInitializer(v, null); } - public PackageTest addRunOnceInitializer(ThrowingRunnable v) { + public PackageTest addRunOnceInitializer(ThrowingRunnable v) { return addRunOnceInitializer(v, null); } - public PackageTest addBundleVerifier(ThrowingBiConsumer v) { + public PackageTest addBundleVerifier(ThrowingBiConsumer v) { Objects.requireNonNull(v); currentTypes.forEach(type -> handlers.get(type).addBundleVerifier(toBiConsumer(v))); return this; } - public PackageTest addBundleVerifier(ThrowingConsumer v) { + public PackageTest addBundleVerifier(ThrowingConsumer v) { Objects.requireNonNull(v); return addBundleVerifier((cmd, unused) -> toConsumer(v).accept(cmd)); } @@ -222,13 +222,13 @@ public final class PackageTest extends RunnablePackageTest { return this; } - public PackageTest addInstallVerifier(ThrowingConsumer v) { + public PackageTest addInstallVerifier(ThrowingConsumer v) { currentTypes.forEach(type -> handlers.get(type).addInstallVerifier( toConsumer(v))); return this; } - public PackageTest addUninstallVerifier(ThrowingConsumer v) { + public PackageTest addUninstallVerifier(ThrowingConsumer v) { currentTypes.forEach(type -> handlers.get(type).addUninstallVerifier( toConsumer(v))); return this; @@ -259,7 +259,7 @@ public final class PackageTest extends RunnablePackageTest { } static void withFileAssociationsTestRuns(FileAssociations fa, - ThrowingBiConsumer> consumer) { + ThrowingBiConsumer, ? extends Exception> consumer) { Objects.requireNonNull(consumer); for (var testRun : fa.getTestRuns()) { TKit.withTempDirectory("fa-test-files", tempDir -> { @@ -860,7 +860,7 @@ public final class PackageTest extends RunnablePackageTest { "Check the package has %d top installation directories", expectedRootCount)); } catch (IOException ex) { - rethrowUnchecked(ex); + throw toUnchecked(ex); } } diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java index 0afdf31ec68..90c73f97106 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java @@ -33,7 +33,6 @@ import java.io.Closeable; import java.io.IOException; import java.io.PrintStream; import java.io.UncheckedIOException; -import java.lang.reflect.InvocationTargetException; import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.LinkOption; @@ -110,7 +109,7 @@ public final class TKit { throw throwUnknownPlatformError(); }).get(); - static void withExtraLogStream(ThrowingRunnable action) { + static void withExtraLogStream(ThrowingRunnable action) { if (state().extraLogStream != null) { ThrowingRunnable.toRunnable(action).run(); } else { @@ -120,19 +119,19 @@ public final class TKit { } } - static void withExtraLogStream(ThrowingRunnable action, PrintStream logStream) { + static void withExtraLogStream(ThrowingRunnable action, PrintStream logStream) { withNewState(action, stateBuilder -> { stateBuilder.extraLogStream(logStream); }); } - public static void withMainLogStream(ThrowingRunnable action, PrintStream logStream) { + public static void withMainLogStream(ThrowingRunnable action, PrintStream logStream) { withNewState(action, stateBuilder -> { stateBuilder.mainLogStream(logStream); }); } - public static void withStackTraceStream(ThrowingRunnable action, PrintStream logStream) { + public static void withStackTraceStream(ThrowingRunnable action, PrintStream logStream) { withNewState(action, stateBuilder -> { stateBuilder.stackTraceStream(logStream); }); @@ -146,7 +145,7 @@ public final class TKit { STATE.set(Objects.requireNonNull(v)); } - private static void withNewState(ThrowingRunnable action, Consumer stateBuilderMutator) { + private static void withNewState(ThrowingRunnable action, Consumer stateBuilderMutator) { Objects.requireNonNull(action); Objects.requireNonNull(stateBuilderMutator); @@ -198,7 +197,7 @@ public final class TKit { }); } - static T runAdhocTest(ThrowingSupplier action) { + static T runAdhocTest(ThrowingSupplier action) { final List box = new ArrayList<>(); runAdhocTest(() -> { box.add(action.get()); @@ -206,7 +205,7 @@ public final class TKit { return box.getFirst(); } - static void runAdhocTest(ThrowingRunnable action) { + static void runAdhocTest(ThrowingRunnable action) { Objects.requireNonNull(action); final Path workDir = toSupplier(() -> Files.createTempDirectory("jdk.jpackage-test")).get(); @@ -227,28 +226,20 @@ public final class TKit { runTests(List.of(test), Set.of(RunTestMode.FAIL_FAST)); } - static Runnable ignoreExceptions(ThrowingRunnable action) { + static Runnable ignoreExceptions(ThrowingRunnable action) { return () -> { try { try { action.run(); - } catch (Throwable ex) { - unbox(ex); + } catch (Exception ex) { + throw ExceptionBox.unbox(ex); } - } catch (Throwable throwable) { - printStackTrace(throwable); + } catch (Exception | AssertionError t) { + printStackTrace(t); } }; } - static void unbox(Throwable throwable) throws Throwable { - try { - throw throwable; - } catch (ExceptionBox | InvocationTargetException ex) { - unbox(ex.getCause()); - } - } - public static Path workDir() { return currentTest().workDir(); } @@ -440,7 +431,7 @@ public final class TKit { return createTempPath(role, Files::createFile); } - private static Path createTempPath(Path templatePath, ThrowingUnaryOperator createPath) { + private static Path createTempPath(Path templatePath, ThrowingUnaryOperator createPath) { if (templatePath.isAbsolute()) { throw new IllegalArgumentException(); } @@ -458,13 +449,11 @@ public final class TKit { return createPath.apply(path); } catch (IOException ex) { throw new UncheckedIOException(ex); - } catch (Throwable t) { - throw ExceptionBox.rethrowUnchecked(t); } } public static Path withTempDirectory(String role, - ThrowingConsumer action) { + ThrowingConsumer action) { final Path tempDir = ThrowingSupplier.toSupplier( () -> createTempDirectory(role)).get(); boolean keepIt = true; diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestBuilder.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestBuilder.java index 4009fe2f687..5f4547c701e 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestBuilder.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestBuilder.java @@ -128,7 +128,7 @@ final class TestBuilder implements AutoCloseable { clear(); } - void processCmdLineArg(String arg) throws Throwable { + void processCmdLineArg(String arg) throws Exception { int separatorIdx = arg.indexOf('='); final String argName; final String argValue; @@ -140,7 +140,7 @@ final class TestBuilder implements AutoCloseable { argValue = null; } try { - ThrowingConsumer argProcessor = argProcessors.get(argName); + var argProcessor = argProcessors.get(argName); if (argProcessor == null) { throw new ParseException("Unrecognized"); } @@ -205,8 +205,8 @@ final class TestBuilder implements AutoCloseable { } private void createTestInstance(MethodCall testBody) { - final List> curBeforeActions; - final List> curAfterActions; + final List> curBeforeActions; + final List> curAfterActions; Method testMethod = testBody.getMethod(); if (Stream.of(BeforeEach.class, AfterEach.class).anyMatch( @@ -326,7 +326,7 @@ final class TestBuilder implements AutoCloseable { } // Wraps Method.invoke() into ThrowingRunnable.run() - private ThrowingConsumer wrap(Method method) { + private ThrowingConsumer wrap(Method method) { return (test) -> { Class methodClass = method.getDeclaringClass(); String methodName = String.join(".", methodClass.getName(), @@ -375,13 +375,13 @@ final class TestBuilder implements AutoCloseable { } private final TestMethodSupplier testMethodSupplier; - private final Map> argProcessors; + private final Map> argProcessors; private final Consumer testConsumer; private final Path workDirRoot; private final ClassLoader testClassLoader; private List testGroup; - private List> beforeActions; - private List> afterActions; + private List> beforeActions; + private List> afterActions; private Set excludedTests; private Set includedTests; private String spaceSubstitute; diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestInstance.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestInstance.java index 4445a194ee7..3c622200249 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestInstance.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestInstance.java @@ -46,7 +46,7 @@ import jdk.jpackage.internal.util.function.ThrowingFunction; import jdk.jpackage.internal.util.function.ThrowingRunnable; import jdk.jpackage.internal.util.function.ThrowingSupplier; -final class TestInstance implements ThrowingRunnable { +final class TestInstance implements ThrowingRunnable { static final class TestDesc { private TestDesc(Class clazz, String functionName, String functionArgs, String instanceArgs) { @@ -149,7 +149,7 @@ final class TestInstance implements ThrowingRunnable { private final String instanceArgs; } - TestInstance(ThrowingRunnable testBody, Path workDirRoot) { + TestInstance(ThrowingRunnable testBody, Path workDirRoot) { assertCount = 0; this.testConstructor = (unused) -> null; this.testBody = (unused) -> testBody.run(); @@ -160,8 +160,8 @@ final class TestInstance implements ThrowingRunnable { this.workDir = workDirRoot.resolve(createWorkDirPath(testDesc)); } - TestInstance(MethodCall testBody, List> beforeActions, - List> afterActions, boolean dryRun, Path workDirRoot) { + TestInstance(MethodCall testBody, List> beforeActions, + List> afterActions, boolean dryRun, Path workDirRoot) { assertCount = 0; this.testConstructor = v -> ((MethodCall)v).newInstance(); this.testBody = testBody; @@ -226,7 +226,7 @@ final class TestInstance implements ThrowingRunnable { } @Override - public void run() throws Throwable { + public void run() throws Exception { final String fullName = fullName(); TKit.log(String.format("[ RUN ] %s", fullName)); try { @@ -333,10 +333,10 @@ final class TestInstance implements ThrowingRunnable { private Status status; private RuntimeException skippedTestException; private final TestDesc testDesc; - private final ThrowingFunction, Object> testConstructor; - private final ThrowingConsumer testBody; - private final List> beforeActions; - private final List> afterActions; + private final ThrowingFunction, Object, ? extends Exception> testConstructor; + private final ThrowingConsumer testBody; + private final List> beforeActions; + private final List> afterActions; private final boolean dryRun; private final Path workDir; diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/WinExecutableIconVerifier.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/WinExecutableIconVerifier.java index 5110259e6f3..f4468fa9ab0 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/WinExecutableIconVerifier.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/WinExecutableIconVerifier.java @@ -22,7 +22,7 @@ */ package jdk.jpackage.test; -import static jdk.jpackage.internal.util.function.ExceptionBox.rethrowUnchecked; +import static jdk.jpackage.internal.util.function.ExceptionBox.toUnchecked; import java.awt.image.BufferedImage; import java.io.IOException; @@ -195,7 +195,7 @@ public final class WinExecutableIconVerifier { iconSwap.setAccessible(true); } catch (ClassNotFoundException | NoSuchMethodException | SecurityException ex) { - throw rethrowUnchecked(ex); + throw toUnchecked(ex); } } @@ -268,7 +268,7 @@ public final class WinExecutableIconVerifier { } } } catch (IllegalAccessException | InvocationTargetException ex) { - throw rethrowUnchecked(ex); + throw toUnchecked(ex); } } finally { executable.toFile().setWritable(false, true); diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/WindowsHelper.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/WindowsHelper.java index 5e97b0d2dde..72b5dbc578b 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/WindowsHelper.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/WindowsHelper.java @@ -22,7 +22,7 @@ */ package jdk.jpackage.test; -import static jdk.jpackage.internal.util.function.ExceptionBox.rethrowUnchecked; +import static jdk.jpackage.internal.util.function.ExceptionBox.toUnchecked; import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier; import java.io.IOException; @@ -634,7 +634,7 @@ public class WindowsHelper { getShortPathWrapper.setAccessible(true); } catch (ClassNotFoundException | NoSuchMethodException | SecurityException ex) { - throw rethrowUnchecked(ex); + throw toUnchecked(ex); } } diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/PackagingPipelineTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/PackagingPipelineTest.java index 8168b876d2f..721e0802d16 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/PackagingPipelineTest.java +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/PackagingPipelineTest.java @@ -23,7 +23,7 @@ package jdk.jpackage.internal; -import static jdk.jpackage.internal.util.function.ExceptionBox.rethrowUnchecked; +import static jdk.jpackage.internal.util.function.ExceptionBox.toUnchecked; import static jdk.jpackage.internal.util.function.ThrowingConsumer.toConsumer; import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -412,7 +412,7 @@ public class PackagingPipelineTest { final var expectedException = new Exception("foo"); final var ex = testExceptionRethrow(expectedException, ExceptionBox.class, () -> { - rethrowUnchecked(expectedException); + throw toUnchecked(expectedException); }); assertSame(expectedException, ex.getCause()); } diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/OptionsValidationFailTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/OptionsValidationFailTest.java index a46cb20815f..ee261dfe8a8 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/OptionsValidationFailTest.java +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/OptionsValidationFailTest.java @@ -160,7 +160,7 @@ public class OptionsValidationFailTest { } @TestFactory - Stream getTestCasesFromErrorTest() throws Throwable { + Stream getTestCasesFromErrorTest() throws Exception { final var jpackageTestsUnnamedModule = JUnitAdapter.class.getModule(); final var testClassloader = new InMemoryClassLoader(Stream.of( diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/ResultTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/ResultTest.java new file mode 100644 index 00000000000..ca8f7aad102 --- /dev/null +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/ResultTest.java @@ -0,0 +1,602 @@ +/* + * Copyright (c) 2025, 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.jpackage.internal.util; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrowsExactly; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.function.Consumer; +import java.util.function.Function; +import jdk.jpackage.internal.util.function.ExceptionBox; +import jdk.jpackage.internal.util.function.ThrowingSupplier; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.params.provider.ValueSource; + +public class ResultTest { + + @Test + public void test_ctor_with_value() { + var result = new Result(Optional.of("foo"), List.of()); + + assertTrue(result.hasValue()); + assertFalse(result.hasErrors()); + assertEquals(Optional.of("foo"), result.value()); + assertEquals(List.of(), result.errors()); + assertEquals(Optional.empty(), result.firstError()); + } + + @Test + public void test_ctor_with_errors() { + var ex = new Exception("Kaput!"); + var result = new Result(Optional.empty(), List.of(ex)); + + assertFalse(result.hasValue()); + assertTrue(result.hasErrors()); + assertEquals(Optional.empty(), result.value()); + assertEquals(List.of(ex), result.errors()); + assertEquals(Optional.of(ex), result.firstError()); + } + + @Test + public void test_ctor_invalid_npe() { + assertThrowsExactly(NullPointerException.class, () -> { + new Result(Optional.of("foo"), null); + }); + + assertThrowsExactly(NullPointerException.class, () -> { + new Result(null, List.of(new Exception())); + }); + + assertThrowsExactly(NullPointerException.class, () -> { + new Result(null, null); + }); + } + + @Test + public void test_ctor_invalid_both_empty() { + var ex = assertThrowsExactly(IllegalArgumentException.class, () -> { + new Result(Optional.empty(), List.of()); + }); + assertEquals("'value' and 'errors' cannot both be non-empty or both be empty", ex.getMessage()); + } + + @Test + public void test_ctor_invalid_both_non_empty() { + var ex = assertThrowsExactly(IllegalArgumentException.class, () -> { + new Result(Optional.of("foo"), List.of(new Exception())); + }); + assertEquals("'value' and 'errors' cannot both be non-empty or both be empty", ex.getMessage()); + } + + @ParameterizedTest + @ValueSource(booleans = {true, false}) + public void test_ofValue(boolean valid) { + if (valid) { + assertTrue(Result.ofValue("foo").hasValue()); + } else { + assertThrowsExactly(NullPointerException.class, () -> { + Result.ofValue(null); + }); + } + } + + @ParameterizedTest + @ValueSource(booleans = {true, false}) + public void test_ofError(boolean valid) { + if (valid) { + var err = new Exception("foo"); + var result = Result.ofError(err); + assertEquals(List.of(err), result.errors()); + } else { + assertThrowsExactly(NullPointerException.class, () -> { + Result.ofError(null); + }); + } + } + + @ParameterizedTest + @ValueSource(booleans = {true, false}) + public void test_ofErrors(boolean valid) { + if (valid) { + var errors = List.of(new Exception("foo"), new IllegalArgumentException("bar")); + var result = Result.ofErrors(errors); + assertSame(errors, result.errors()); + } else { + assertThrowsExactly(NullPointerException.class, () -> { + Result.ofErrors(null); + }); + + assertThrowsExactly(NullPointerException.class, () -> { + var errors = new ArrayList(); + errors.add(new Exception()); + errors.add(null); + Result.ofErrors(errors); + }); + } + } + + @Test + public void test_of() { + assertEquals("foo", Result.of(() -> { + return "foo"; + }).orElseThrow()); + } + + @Test + public void test_of_null_value() { + assertThrowsExactly(NullPointerException.class, () -> { + Result.of(() -> { + return null; + }); + }); + } + + @ParameterizedTest + @ValueSource(booleans = {true, false}) + public void test_of_throws(boolean declaredExceptionType) { + + Exception cause; + if (declaredExceptionType) { + cause = new IOException("foo"); + } else { + cause = new UnsupportedOperationException("bar"); + } + + ThrowingSupplier supplier = () -> { + if (declaredExceptionType) { + throw (IOException)cause; + } else { + throw (UnsupportedOperationException)cause; + } + }; + + if (declaredExceptionType) { + var result = Result.of(supplier, IOException.class); + assertSame(cause, result.firstError().orElseThrow()); + assertEquals(1, result.errors().size()); + } else { + var ex = assertThrowsExactly(cause.getClass(), () -> { + Result.of(supplier, IOException.class); + }); + assertSame(cause, ex); + } + } + + @Test + public void test_orElseThrow_hasValue() { + assertEquals("foo", Result.ofValue("foo").orElseThrow()); + } + + @ParameterizedTest + @ValueSource(booleans = {true, false}) + public void test_orElseThrow(boolean uncheckedException) { + Exception ex; + Class expectedType; + if (uncheckedException) { + ex = new RuntimeException("Kaput!"); + expectedType = ex.getClass(); + } else { + ex = new Exception("Kaput!"); + expectedType = ExceptionBox.class; + } + + var actual = assertThrowsExactly(expectedType, Result.ofError(ex)::orElseThrow); + + if (uncheckedException) { + assertSame(ex, actual); + } else { + assertSame(ex, actual.getCause()); + } + } + + @ParameterizedTest + @MethodSource + public void test_map_and_flatMap(MapTestSpec spec) { + spec.run(); + } + + @ParameterizedTest + @ValueSource(booleans = {true, false}) + public void test_peekValue(boolean hasValue) { + var pickedValue = Slot.createEmpty(); + + Consumer consumer = v -> { + assertNotNull(v); + assertTrue(pickedValue.find().isEmpty()); + pickedValue.set(v); + }; + + Result result; + if (hasValue) { + result = Result.ofValue("foo"); + } else { + result = Result.ofError(new Exception("foo")); + } + result.peekValue(consumer); + + if (hasValue) { + assertEquals("foo", pickedValue.get()); + } else { + assertTrue(pickedValue.find().isEmpty()); + } + } + + @ParameterizedTest + @ValueSource(booleans = {true, false}) + public void test_peekErrors(boolean hasValue) { + var pickedErrors = Slot.>createEmpty(); + + Consumer> consumer = v -> { + assertNotNull(v); + assertTrue(pickedErrors.find().isEmpty()); + pickedErrors.set(v); + }; + + Result result; + if (hasValue) { + result = Result.ofValue("foo"); + } else { + result = Result.ofErrors(List.of(new Exception("foo"), new IOException("bar"))); + } + result.peekErrors(consumer); + + if (hasValue) { + assertTrue(pickedErrors.find().isEmpty()); + } else { + assertSame(result.errors(), pickedErrors.get()); + } + } + + @ParameterizedTest + @ValueSource(booleans = {true, false}) + public void test_mapErrors(boolean hasValue) { + Result result; + if (hasValue) { + result = Result.ofValue("foo"); + } else { + result = Result.ofErrors(List.of(new Exception("foo"), new IOException("bar"))); + } + + if (hasValue) { + var ex = assertThrowsExactly(IllegalStateException.class, result::mapErrors); + assertEquals("Can not map errors from a result without errors", ex.getMessage()); + } else { + assertSame(result, result.mapErrors()); + } + } + + @Test + public void test_allHaveValues_empty() { + assertTrue(Result.allHaveValues()); + } + + @ParameterizedTest + @ValueSource(booleans = {true, false}) + public void test_allHaveValues(boolean expected) { + if (expected) { + assertTrue(Result.allHaveValues(Result.ofValue("foo"), Result.ofValue(37))); + } else { + assertFalse(Result.allHaveValues(Result.ofValue("foo"), Result.ofError(new Exception()))); + } + } + + enum MapFunctionType { + MAP, + FLAT_MAP, + ; + } + + enum MapFunctionOutcome { + RETURN_NON_NULL, + RETURN_NULL, + THROW, + FLAT_MAP_NEW_ERRORS(MapFunctionType.FLAT_MAP), + ; + + MapFunctionOutcome(MapFunctionType... supportedTypes) { + this.supportedTypes = Set.of(supportedTypes); + } + + MapFunctionOutcome() { + this(MapFunctionType.values()); + } + + private final Set supportedTypes; + } + + record MapTestSpec(boolean hasValue, MapFunctionOutcome outcome, MapFunctionType type) { + MapTestSpec { + Objects.requireNonNull(outcome); + Objects.requireNonNull(type); + } + + @Override + public String toString() { + var tokens = new ArrayList(); + tokens.add(outcome.name()); + if (type == MapFunctionType.FLAT_MAP) { + tokens.add("flatMap"); + } + if (!hasValue) { + tokens.add("no-value"); + } + return String.join(", ", tokens); + } + + void run() { + var builder = MapTest.build(); + if (hasValue) { + builder.initialValue(100); + } + + Function plainMapper; + switch (outcome) { + case RETURN_NON_NULL -> { + if (hasValue) { + builder.expectValue("200"); + } + plainMapper = v -> { + return String.valueOf(v * 2); + }; + } + case RETURN_NULL -> { + builder.expectExceptionOfType(NullPointerException.class); + plainMapper = _ -> { + return null; + }; + } + case THROW -> { + var cause = new UnsupportedOperationException("Unsupported"); + builder.expectException(cause); + plainMapper = _ -> { + throw cause; + }; + } + case FLAT_MAP_NEW_ERRORS -> { + if (hasValue) { + // Just a stub to make `builder.create()` pass. + builder.expectValue(""); + } + var mappedResult = Result.ofError(new UnsupportedOperationException("Whoopsy-daisy")); + var test = builder.create().copyWithMappedValue(mappedResult); + test.flatMap(v -> { + return mappedResult; + }); + return; + } + default -> { + throw ExceptionBox.reachedUnreachable(); + } + } + + var test = builder.create(); + + switch (type) { + case MAP -> { + test.map(plainMapper); + } + case FLAT_MAP -> { + test.flatMap(v -> { + return Optional.ofNullable(plainMapper.apply(v)).map(Result::ofValue).orElse(null); + }); + } + } + } + } + + private static List test_map_and_flatMap() { + var data = new ArrayList(); + for (var type : MapFunctionType.values()) { + for (var outcome : MapFunctionOutcome.values()) { + if (outcome.supportedTypes.contains(type)) { + for (var hasValue : List.of(true, false)) { + data.add(new MapTestSpec(hasValue, outcome, type)); + } + } + } + } + return data; + } + + private static final class Counter implements Function { + + Counter(Function impl) { + this.impl = Objects.requireNonNull(impl); + } + + @Override + public U apply(T v) { + counter++; + return impl.apply(v); + } + + int count() { + return counter; + } + + private int counter; + private final Function impl; + } + + private record MapTest( + Result initialValue, + Optional> mappedValue, + Optional expectedException, + Optional> expectedExceptionType) { + + MapTest { + Objects.requireNonNull(initialValue); + Objects.requireNonNull(mappedValue); + Objects.requireNonNull(expectedException); + Objects.requireNonNull(expectedExceptionType); + + if (expectedExceptionType.isPresent() && mappedValue.isPresent()) { + // Bad configuration: the mapping operation is expected to throw, + // but it also expects it to return a value. + throw new IllegalArgumentException(); + } + + if (expectedExceptionType.isEmpty() && mappedValue.isEmpty()) { + // Bad configuration: the mapping operation is expected to return normally (not to throw), + // but it also doesn't expect a mapped value. + throw new IllegalArgumentException(); + } + + if (initialValue.hasErrors() && mappedValue.map(Result::hasValue).orElse(false)) { + // Bad configuration: the initial value has errors but they expect a mapped value without errors. + throw new IllegalArgumentException(); + } + + expectedException.map(Object::getClass).ifPresent(expectedExpectedExceptionType -> { + var configuredExpectedExceptionType = expectedExceptionType.orElseThrow(); + if (!configuredExpectedExceptionType.equals(expectedExpectedExceptionType)) { + throw new IllegalArgumentException(String.format( + "expectedException=%s; expectedExceptionType=%s", + expectedExpectedExceptionType, configuredExpectedExceptionType)); + } + }); + } + + MapTest copyWithMappedValue(Result v) { + return new MapTest<>(initialValue, Optional.of(v), expectedException, expectedExceptionType); + } + + static Builder build() { + return new Builder<>(); + } + + void map(Function mapper) { + map(new Counter<>(mapper), initialValue::map); + } + + void flatMap(Function> mapper) { + map(new Counter<>(mapper), initialValue::flatMap); + } + + private void map(Counter countingMapper, Function, Result> mapper) { + + if (initialValue.hasErrors()) { + Result mapped = mapper.apply(countingMapper); + assertTrue(mapped.hasErrors()); + assertEquals(initialValue.errors(), mapped.errors()); + } else { + expectedExceptionType.ifPresentOrElse(theExpectedExceptionType -> { + var ex = assertThrowsExactly(theExpectedExceptionType, () -> { + initialValue.map(countingMapper); + }); + + expectedException.ifPresent(theExpectedException -> { + assertSame(theExpectedException, ex); + }); + }, () -> { + Result mapped = mapper.apply(countingMapper); + assertEquals(mappedValue.orElseThrow(), mapped); + }); + } + + if (initialValue.hasValue()) { + assertEquals(1, countingMapper.count()); + } else { + assertEquals(0, countingMapper.count()); + } + } + + static final class Builder { + + MapTest create() { + + var theInitialValue = Optional.ofNullable(initialValue).orElseGet(() -> { + return Result.ofError(new Exception("Kaput!")); + }); + + return new MapTest<>( + theInitialValue, + Optional.ofNullable(expectedValue).map(Result::ofValue).or(() -> { + if (expectedExceptionType == null) { + return Optional.of(theInitialValue.mapErrors()); + } else { + return Optional.empty(); + } + }), + Optional.ofNullable(expectedException), + Optional.ofNullable(expectedExceptionType)); + } + + Builder initialValue(Result v) { + initialValue = v; + return this; + } + + Builder initialValue(T v) { + return initialValue(Result.ofValue(v)); + } + + Builder expectException(Exception v) { + expectedException = v; + if (expectedException != null) { + expectedExceptionType = expectedException.getClass(); + expectValue(null); + } else { + expectedExceptionType = null; + } + return this; + } + + Builder expectExceptionOfType(Class v) { + expectedException = null; + expectedExceptionType = v; + if (v != null) { + expectValue(null); + } + return this; + } + + Builder expectValue(U v) { + expectedValue = v; + if (v != null) { + expectException(null); + } + return this; + } + + private Result initialValue; + private U expectedValue; + private Exception expectedException; + private Class expectedExceptionType; + } + } +} diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/function/ExceptionBoxTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/function/ExceptionBoxTest.java new file mode 100644 index 00000000000..c3ef239b02d --- /dev/null +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/function/ExceptionBoxTest.java @@ -0,0 +1,246 @@ +/* + * Copyright (c) 2025, 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.jpackage.internal.util.function; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertThrowsExactly; + +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.util.Objects; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.UnaryOperator; +import jdk.jpackage.internal.util.Slot; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; + +public class ExceptionBoxTest { + + @Test + public void test_unbox_RuntimeException() { + var ex = new RuntimeException(); + assertSame(ex, ExceptionBox.unbox(ex)); + } + + @Test + public void test_unbox_Exception() { + var ex = new Exception(); + assertSame(ex, ExceptionBox.unbox(ex)); + } + + @Test + public void test_unbox_InvocationTargetException() { + var ex = new Exception(); + assertSame(ex, ExceptionBox.unbox(new InvocationTargetException(ex))); + } + + @Test + public void test_unbox_ExceptionBox() { + var ex = new Exception("foo"); + // There is no way to directly instantiate ExceptionBox, use a workaround. + var box = assertThrowsExactly(ExceptionBox.class, () -> { + throw ExceptionBox.toUnchecked(ex); + }); + assertSame(ex, ExceptionBox.unbox(box)); + } + + @Test + public void test_unbox_Error() { + var err = new Error("On Fire!"); + var thrown = assertThrowsExactly(Error.class, () -> { + ExceptionBox.unbox(err); + }); + assertSame(err, thrown); + } + + @Test + public void test_reachedUnreachable() { + var err = ExceptionBox.reachedUnreachable(); + assertEquals("Reached unreachable!", err.getMessage()); + } + + @Test + public void test_toUnchecked_RuntimeException() { + assertToUnchecked(new RuntimeException(), true); + } + + @Test + public void test_toUnchecked_Exception() { + assertToUnchecked(new Exception(), false); + } + + @Test + public void test_toUnchecked_ExceptionBox() { + // There is no way to directly instantiate ExceptionBox, use a workaround. + var box = assertThrowsExactly(ExceptionBox.class, () -> { + throw ExceptionBox.toUnchecked(new Exception("foo")); + }); + assertToUnchecked(box, true); + } + + @Test + public void test_toUnchecked_InterruptedException() throws InterruptedException { + + var workerThreadReadyToWait = Slot.createEmpty(); + + var workerThreadInterruptedExceptionCaught = Slot.createEmpty(); + + var workerThreadException = new AtomicReference(); + + var thread = Thread.ofVirtual().uncaughtExceptionHandler((Thread _, Throwable e) -> { + trace("unexpected exception: %s", e); + workerThreadException.set(e); + }).start(() -> { + try { + var lock = new Object(); + synchronized (lock) { + synchronized (workerThreadReadyToWait) { + workerThreadReadyToWait.set(true); + workerThreadReadyToWait.notify(); + } + trace("wait"); + lock.wait(); + } + } catch (InterruptedException iex) { + trace("interrupted state cleared"); + synchronized (workerThreadInterruptedExceptionCaught) { + workerThreadInterruptedExceptionCaught.set(true); + trace("notify about to interrupt itself"); + workerThreadInterruptedExceptionCaught.notify(); + } + trace("before toUnchecked()"); + var box = assertThrowsExactly(ExceptionBox.class, () -> { + throw ExceptionBox.toUnchecked(iex); + }); + assertSame(iex, box.getCause()); + } + }); + + // Wait until the worker thread gets to the point + // when interrupting it will cause InterruptedException. + synchronized (workerThreadReadyToWait) { + while (workerThreadReadyToWait.find().isEmpty()) { + workerThreadReadyToWait.wait(); + } + } + + trace("interrupt %s", thread); + thread.interrupt(); + + // Wait until the worker thread catches an InterruptedException. + synchronized (workerThreadInterruptedExceptionCaught) { + while (workerThreadInterruptedExceptionCaught.find().isEmpty()) { + trace("wait for %s to catch InterruptedException", thread); + workerThreadInterruptedExceptionCaught.wait(); + } + } + + // Block waiting when ExceptionBox.toUnchecked() + // called in the worker thread will interrupt the worker thread. + while (!thread.isInterrupted()) { + trace("wait %s is interrupted", thread); + Thread.sleep(100); + } + + trace("join interrupted %s", thread); + thread.join(); + + assertNull(workerThreadException.get()); + } + + @ParameterizedTest + @EnumSource(InvocationTargetExceptionType.class) + public void test_rethrowUnchecked_InvocationTargetException(InvocationTargetExceptionType type) + throws NoSuchMethodException, SecurityException, IllegalAccessException { + + var m = ExceptionBoxTest.class.getMethod(type.methodName); + + try { + m.invoke(null); + } catch (InvocationTargetException ex) { + var cause = assertThrows(type.expectedThrownType, () -> { + throw ExceptionBox.toUnchecked(ex); + }); + assertSame(ex.getCause(), type.expectedThrowableGetter.apply(cause)); + } + } + + public enum InvocationTargetExceptionType { + CHECKED("throwIOException", t -> { + return t.getCause(); + }, ExceptionBox.class), + UNCHECKED("throwNPE", x -> x, RuntimeException.class), + ERROR("throwError", x -> x, Error.class), + ; + + InvocationTargetExceptionType( + String methodName, + UnaryOperator expectedThrowableGetter, + Class expectedThrownType) { + this.methodName = Objects.requireNonNull(methodName); + this.expectedThrownType = Objects.requireNonNull(expectedThrownType); + this.expectedThrowableGetter = Objects.requireNonNull(expectedThrowableGetter); + } + + final String methodName; + final Class expectedThrownType; + final UnaryOperator expectedThrowableGetter; + } + + public static void throwIOException() throws IOException { + throw new IOException("foo"); + } + + public static void throwNPE() { + throw new NullPointerException("foo"); + } + + public static void throwError() { + throw new Error("Kaput!"); + } + + private static void assertToUnchecked(Exception cause, boolean asis) { + Class expectedType; + if (asis) { + expectedType = cause.getClass(); + } else { + expectedType = ExceptionBox.class; + } + var unchecked = ExceptionBox.toUnchecked(cause); + if (asis) { + assertSame(cause, unchecked); + } else { + assertSame(cause, unchecked.getCause()); + } + } + + private void trace(String format, Object... args) { + Objects.requireNonNull(format); + System.out.println(String.format("[%s]: %s", Thread.currentThread(), String.format(format, args))); + } +} diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/function/FunctionalTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/function/FunctionalTest.java new file mode 100644 index 00000000000..67c082916a6 --- /dev/null +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/function/FunctionalTest.java @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2025, 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.jpackage.internal.util.function; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrowsExactly; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.Map; +import java.util.function.Supplier; +import jdk.jpackage.internal.util.Slot; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +public class FunctionalTest { + + @ParameterizedTest + @ValueSource(booleans = {true, false}) + public void test_toRunnable(boolean error) { + var reply = Slot.createEmpty(); + + var runnable = ThrowingRunnable.toRunnable(() -> { + if (error) { + throw new Exception(); + } else { + reply.set(135); + } + }); + + if (error) { + assertThrowsExactly(ExceptionBox.class, runnable::run); + assertTrue(reply.find().isEmpty()); + } else { + runnable.run(); + assertEquals(135, reply.get()); + } + } + + @ParameterizedTest + @ValueSource(booleans = {true, false}) + public void test_toSupplier(boolean error) { + var supplier = ThrowingSupplier.toSupplier(() -> { + if (error) { + throw new Exception(); + } else { + return 135; + } + }); + + if (error) { + assertThrowsExactly(ExceptionBox.class, supplier::get); + } else { + assertEquals(135, supplier.get()); + } + } + + @ParameterizedTest + @ValueSource(booleans = {true, false}) + public void test_toConsumer(boolean error) { + var reply = Slot.createEmpty(); + + Runnable runnable = () -> { + ThrowingConsumer.toConsumer(v -> { + if (error) { + throw new Exception(); + } else { + reply.set(v); + } + }).accept(135); + }; + + if (error) { + assertThrowsExactly(ExceptionBox.class, runnable::run); + assertTrue(reply.find().isEmpty()); + } else { + runnable.run(); + assertEquals(135, reply.get()); + } + } + + @ParameterizedTest + @ValueSource(booleans = {true, false}) + public void test_toBiConsumer(boolean error) { + var reply = Slot.createEmpty(); + var reply2 = Slot.createEmpty(); + + Runnable runnable = () -> { + ThrowingBiConsumer.toBiConsumer((x, y) -> { + if (error) { + throw new Exception(); + } else { + reply.set(x); + reply2.set(y); + } + }).accept(456, "Hello"); + }; + + if (error) { + assertThrowsExactly(ExceptionBox.class, runnable::run); + assertTrue(reply.find().isEmpty()); + assertTrue(reply2.find().isEmpty()); + } else { + runnable.run(); + assertEquals(456, reply.get()); + assertEquals("Hello", reply2.get()); + } + } + + @ParameterizedTest + @ValueSource(booleans = {true, false}) + public void test_toFunction(boolean error) { + Supplier supplier = () -> { + return ThrowingFunction.toFunction(v -> { + if (error) { + throw new Exception(); + } else { + return String.valueOf(v); + } + }).apply(765); + }; + + if (error) { + assertThrowsExactly(ExceptionBox.class, supplier::get); + } else { + assertEquals("765", supplier.get()); + } + } + + @ParameterizedTest + @ValueSource(booleans = {true, false}) + public void test_toBiFunction(boolean error) { + Supplier< Map.Entry> supplier = () -> { + return ThrowingBiFunction.>toBiFunction((x, y) -> { + if (error) { + throw new Exception(); + } else { + return Map.entry(y, x + 23); + } + }).apply(400, "foo"); + }; + + if (error) { + assertThrowsExactly(ExceptionBox.class, supplier::get); + } else { + assertEquals(Map.entry("foo", 423), supplier.get()); + } + } + + @ParameterizedTest + @ValueSource(booleans = {true, false}) + public void test_toUnaryOperator(boolean error) { + Supplier supplier = () -> { + return ThrowingUnaryOperator.toUnaryOperator(v -> { + if (error) { + throw new Exception(); + } else { + return v - 222; + } + }).apply(777); + }; + + if (error) { + assertThrowsExactly(ExceptionBox.class, supplier::get); + } else { + assertEquals(555, supplier.get()); + } + } +} diff --git a/test/jdk/tools/jpackage/junit/tools/jdk/jpackage/test/JUnitAdapter.java b/test/jdk/tools/jpackage/junit/tools/jdk/jpackage/test/JUnitAdapter.java index 5a605b1642d..952b4b520d5 100644 --- a/test/jdk/tools/jpackage/junit/tools/jdk/jpackage/test/JUnitAdapter.java +++ b/test/jdk/tools/jpackage/junit/tools/jdk/jpackage/test/JUnitAdapter.java @@ -49,7 +49,7 @@ public class JUnitAdapter { } } - public static Stream createJPackageTests(ClassLoader testClassLoader, String... args) throws Throwable { + public static Stream createJPackageTests(ClassLoader testClassLoader, String... args) throws Exception { final List tests = new ArrayList<>(); try (final var testBuilder = TestBuilder.build().workDirRoot(Path.of("")).testClassLoader(testClassLoader).testConsumer(tests::add).create()) { for (final var arg : args) { @@ -64,11 +64,11 @@ public class JUnitAdapter { } @TestFactory - Stream createJPackageTests() throws Throwable { + Stream createJPackageTests() throws Exception { return createJPackageTests(getClass().getClassLoader(), "--jpt-run=" + getClass().getName()); } - static List captureJPackageTestLog(ThrowingRunnable runnable) { + static List captureJPackageTestLog(ThrowingRunnable runnable) { final var buf = new ByteArrayOutputStream(); try (PrintStream ps = new PrintStream(buf, true, StandardCharsets.UTF_8)) { TKit.withExtraLogStream(runnable, ps); diff --git a/test/jdk/tools/jpackage/linux/AppAboutUrlTest.java b/test/jdk/tools/jpackage/linux/AppAboutUrlTest.java index aef46e29725..8196ab733c9 100644 --- a/test/jdk/tools/jpackage/linux/AppAboutUrlTest.java +++ b/test/jdk/tools/jpackage/linux/AppAboutUrlTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, 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 @@ -82,7 +82,7 @@ public class AppAboutUrlTest { runTest(JPackageCommand::setFakeRuntime, "", "(none)"); } - private static void runTest(ThrowingConsumer initializer, + private static void runTest(ThrowingConsumer initializer, String expectedDebHomepage, String expectedRpmUrl) { new PackageTest() .forTypes(PackageType.LINUX) diff --git a/test/jdk/tools/jpackage/macosx/CustomInfoPListTest.java b/test/jdk/tools/jpackage/macosx/CustomInfoPListTest.java index dd94330d039..50445c0e9ab 100644 --- a/test/jdk/tools/jpackage/macosx/CustomInfoPListTest.java +++ b/test/jdk/tools/jpackage/macosx/CustomInfoPListTest.java @@ -23,7 +23,6 @@ import static java.util.Collections.unmodifiableSortedSet; import static java.util.Map.entry; -import jdk.jpackage.internal.util.Slot; import static jdk.jpackage.internal.util.PListWriter.writeDict; import static jdk.jpackage.internal.util.PListWriter.writeKey; import static jdk.jpackage.internal.util.PListWriter.writePList; @@ -52,6 +51,7 @@ import java.util.stream.Stream; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamWriter; import jdk.jpackage.internal.util.PListReader; +import jdk.jpackage.internal.util.Slot; import jdk.jpackage.internal.util.function.ThrowingBiConsumer; import jdk.jpackage.test.Annotations.Parameter; import jdk.jpackage.test.Annotations.ParameterSupplier; @@ -84,7 +84,7 @@ public class CustomInfoPListTest { @Test @ParameterSupplier("customPLists") - public void testAppImage(TestConfig cfg) throws Throwable { + public void testAppImage(TestConfig cfg) { testApp(new ConfigurationTarget(JPackageCommand.helloAppImage()), cfg); } @@ -254,6 +254,10 @@ public class CustomInfoPListTest { .addArguments(cmd.getAllArguments()) .setPackageType(PackageType.IMAGE) .removeArgumentWithValue("--resource-dir") + // Ignore externally configured runtime if any. + // It may or may not have the "bin" directory, it also can be a bundle. + // These factors affect the runtime plist file (see JDK-8363980) which may not be the default one. + .ignoreDefaultRuntime(true) .setArgumentValue("--dest", TKit.createTempDirectory("vanilla")); vanillaCmd.execute(); @@ -320,8 +324,8 @@ public class CustomInfoPListTest { ; private CustomPListType( - ThrowingBiConsumer inputPlistWriter, - ThrowingBiConsumer outputPlistWriter, + ThrowingBiConsumer inputPlistWriter, + ThrowingBiConsumer outputPlistWriter, String outputPlistFilename) { this.inputPlistWriter = ThrowingBiConsumer.toBiConsumer(inputPlistWriter); this.outputPlistWriter = ThrowingBiConsumer.toBiConsumer(outputPlistWriter); diff --git a/test/jdk/tools/jpackage/macosx/EntitlementsTest.java b/test/jdk/tools/jpackage/macosx/EntitlementsTest.java index aa5879e0c61..6e03c858db3 100644 --- a/test/jdk/tools/jpackage/macosx/EntitlementsTest.java +++ b/test/jdk/tools/jpackage/macosx/EntitlementsTest.java @@ -99,7 +99,7 @@ public class EntitlementsTest { }), ; - EntitlementsSource(ThrowingConsumer initializer) { + EntitlementsSource(ThrowingConsumer initializer) { this.initializer = toConsumer(initializer); } diff --git a/test/jdk/tools/jpackage/share/AppContentTest.java b/test/jdk/tools/jpackage/share/AppContentTest.java index 97c83bba57d..b6066bb9cc4 100644 --- a/test/jdk/tools/jpackage/share/AppContentTest.java +++ b/test/jdk/tools/jpackage/share/AppContentTest.java @@ -37,7 +37,6 @@ import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.List; -import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.Set; @@ -631,7 +630,7 @@ public class AppContentTest { private static final class FileContentFactory implements ContentFactory { - FileContentFactory(ThrowingSupplier factory, Path pathInAppContentRoot) { + FileContentFactory(ThrowingSupplier factory, Path pathInAppContentRoot) { this.factory = ThrowingSupplier.toSupplier(factory); this.pathInAppContentRoot = pathInAppContentRoot; if (pathInAppContentRoot.isAbsolute()) { diff --git a/test/jdk/tools/jpackage/share/AsyncTest.java b/test/jdk/tools/jpackage/share/AsyncTest.java index b2755d4594f..e3a3f7e3cb8 100644 --- a/test/jdk/tools/jpackage/share/AsyncTest.java +++ b/test/jdk/tools/jpackage/share/AsyncTest.java @@ -37,6 +37,7 @@ import java.util.function.Predicate; import java.util.spi.ToolProvider; import java.util.stream.IntStream; import jdk.jpackage.internal.util.function.ThrowingRunnable; +import jdk.jpackage.internal.util.Slot; import jdk.jpackage.test.Annotations.ParameterSupplier; import jdk.jpackage.test.Annotations.Test; import jdk.jpackage.test.HelloApp; @@ -61,7 +62,7 @@ import jdk.jpackage.test.TKit; public class AsyncTest { @Test - public void test() throws Throwable { + public void test() throws Exception { // Create test jar only once. // Besides of saving time, this avoids asynchronous invocations of java tool provider that randomly fail. @@ -94,7 +95,7 @@ public class AsyncTest { future.get(3, TimeUnit.MINUTES); } - Throwable[] fatalError = new Throwable[1]; + var fatalError = Slot.createEmpty(); for (var future : futures) { var result = future.get(); @@ -102,13 +103,11 @@ public class AsyncTest { TKit.trace(String.format("[%s] STDOUT END", result.id())); TKit.trace(String.format("[%s] STDERR BEGIN\n%s", result.id(), result.stderrBuffer())); TKit.trace(String.format("[%s] STDERR END", result.id())); - result.throwable().filter(Predicate.not(TKit::isSkippedException)).ifPresent(t -> { - fatalError[0] = t; - }); + result.exception().filter(Predicate.not(TKit::isSkippedException)).ifPresent(fatalError::set); } - if (fatalError[0] != null) { - throw fatalError[0]; + if (fatalError.find().isPresent()) { + throw fatalError.get(); } } } @@ -143,13 +142,13 @@ public class AsyncTest { } - private record Result(String stdoutBuffer, String stderrBuffer, String id, Optional throwable) { + private record Result(String stdoutBuffer, String stderrBuffer, String id, Optional exception) { Result { Objects.requireNonNull(stdoutBuffer); Objects.requireNonNull(stderrBuffer); Objects.requireNonNull(id); - Objects.requireNonNull(throwable); + Objects.requireNonNull(exception); } } @@ -157,7 +156,7 @@ public class AsyncTest { private record Workload( ByteArrayOutputStream stdoutBuffer, ByteArrayOutputStream stderrBuffer, - ThrowingRunnable runnable, + ThrowingRunnable runnable, String id) implements Callable { Workload { @@ -167,7 +166,7 @@ public class AsyncTest { Objects.requireNonNull(id); } - Workload(ThrowingRunnable runnable, String id) { + Workload(ThrowingRunnable runnable, String id) { this(new ByteArrayOutputStream(), new ByteArrayOutputStream(), runnable, id); } @@ -202,14 +201,14 @@ public class AsyncTest { } }); - Optional err = Optional.empty(); + Optional err = Optional.empty(); try (var bufOut = new PrintStream(stdoutBuffer, true, StandardCharsets.UTF_8); var bufErr = new PrintStream(stderrBuffer, true, StandardCharsets.UTF_8)) { TKit.withStackTraceStream(() -> { TKit.withMainLogStream(runnable, bufOut); }, bufErr); - } catch (Throwable t) { - err = Optional.of(t); + } catch (Exception ex) { + err = Optional.of(ex); } return new Result(stdoutBufferAsString(), stderrBufferAsString(), id, err); } diff --git a/test/jdk/tools/jpackage/share/BasicTest.java b/test/jdk/tools/jpackage/share/BasicTest.java index 958fe150711..0f5d87048dd 100644 --- a/test/jdk/tools/jpackage/share/BasicTest.java +++ b/test/jdk/tools/jpackage/share/BasicTest.java @@ -307,12 +307,12 @@ public final class BasicTest { @Test @Parameter("true") @Parameter("false") - public void testNoOutputDir(boolean appImage) throws Throwable { + public void testNoOutputDir(boolean appImage) throws IOException { var cmd = JPackageCommand.helloAppImage(); final var execDir = cmd.outputDir(); - final ThrowingConsumer initializer = cmdNoOutputDir -> { + final ThrowingConsumer initializer = cmdNoOutputDir -> { cmd.executePrerequisiteActions(); final var pkgType = cmdNoOutputDir.packageType(); diff --git a/test/jdk/tools/jpackage/share/IconTest.java b/test/jdk/tools/jpackage/share/IconTest.java index 12458eda34b..17759db7192 100644 --- a/test/jdk/tools/jpackage/share/IconTest.java +++ b/test/jdk/tools/jpackage/share/IconTest.java @@ -203,7 +203,7 @@ public class IconTest { return withDesktopFile; } - private ThrowingBiConsumer createBundleVerifier() { + private ThrowingBiConsumer createBundleVerifier() { return (cmd, result) -> { Stream.of(Launcher.Main, Launcher.Additional).filter(config::containsKey).forEach(launcher -> { createConsoleOutputVerifier(cmd, launcher).ifPresent(verifier -> { @@ -276,7 +276,7 @@ public class IconTest { return Optional.of(TKit.assertTextStream(lookupString.getValue())); } - private ThrowingConsumer createInstallVerifier() { + private ThrowingConsumer createInstallVerifier() { return cmd -> { var verifier = new LauncherIconVerifier(); diff --git a/test/jdk/tools/jpackage/share/InOutPathTest.java b/test/jdk/tools/jpackage/share/InOutPathTest.java index d36731c2960..211fb843263 100644 --- a/test/jdk/tools/jpackage/share/InOutPathTest.java +++ b/test/jdk/tools/jpackage/share/InOutPathTest.java @@ -21,6 +21,8 @@ * questions. */ +import static jdk.jpackage.test.RunnablePackageTest.Action.CREATE_AND_UNPACK; + import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; @@ -31,17 +33,16 @@ import java.util.Set; import java.util.function.Predicate; import java.util.stream.Stream; import jdk.internal.util.OperatingSystem; -import jdk.jpackage.test.AppImageFile; -import jdk.jpackage.test.ApplicationLayout; -import jdk.jpackage.test.PackageFile; +import jdk.jpackage.internal.util.function.ThrowingConsumer; import jdk.jpackage.test.Annotations.Parameters; import jdk.jpackage.test.Annotations.Test; -import jdk.jpackage.internal.util.function.ThrowingConsumer; +import jdk.jpackage.test.AppImageFile; +import jdk.jpackage.test.ApplicationLayout; import jdk.jpackage.test.JPackageCommand; import jdk.jpackage.test.JPackageCommand.StandardAssert; +import jdk.jpackage.test.PackageFile; import jdk.jpackage.test.PackageTest; import jdk.jpackage.test.PackageType; -import static jdk.jpackage.test.RunnablePackageTest.Action.CREATE_AND_UNPACK; import jdk.jpackage.test.TKit; /* @@ -145,11 +146,11 @@ public final class InOutPathTest { } @Test - public void test() throws Throwable { + public void test() throws Exception { runTest(packageTypes, configure); } - private static Envelope wrap(ThrowingConsumer v, String label) { + private static Envelope wrap(ThrowingConsumer v, String label) { return new Envelope(v, label); } @@ -158,8 +159,8 @@ public final class InOutPathTest { } private static void runTest(Set packageTypes, - ThrowingConsumer configure) throws Throwable { - ThrowingConsumer configureWrapper = cmd -> { + ThrowingConsumer configure) throws Exception { + ThrowingConsumer configureWrapper = cmd -> { // Make sure the input directory is empty in every test run. // This is needed because jpackage output directories in this test // are subdirectories of the input directory. @@ -268,7 +269,7 @@ public final class InOutPathTest { } } - private static final record Envelope(ThrowingConsumer value, String label) { + private static final record Envelope(ThrowingConsumer value, String label) { @Override public String toString() { // Will produce the same test description for the same label every @@ -291,7 +292,7 @@ public final class InOutPathTest { } private final Set packageTypes; - private final ThrowingConsumer configure; + private final ThrowingConsumer configure; // Placing jar file in the "Resources" subdir of the input directory would allow // to use the input directory with `--app-content` on OSX. diff --git a/test/jdk/tools/jpackage/share/PerUserCfgTest.java b/test/jdk/tools/jpackage/share/PerUserCfgTest.java index d2f368cd824..b28eb060b8f 100644 --- a/test/jdk/tools/jpackage/share/PerUserCfgTest.java +++ b/test/jdk/tools/jpackage/share/PerUserCfgTest.java @@ -158,8 +158,8 @@ public class PerUserCfgTest { } private static void withConfigFile(JPackageCommand cmd, Path srcCfgFile, - Path outputCfgFileDir, ThrowingConsumer action) throws - Throwable { + Path outputCfgFileDir, ThrowingConsumer action) throws + Exception { Path targetCfgFile = outputCfgFileDir.resolve(cmd.appLauncherCfgPath( null).getFileName()); TKit.assertPathExists(targetCfgFile, false); diff --git a/test/jdk/tools/jpackage/share/RuntimePackageTest.java b/test/jdk/tools/jpackage/share/RuntimePackageTest.java index 387b46acdfb..6cc668f94f9 100644 --- a/test/jdk/tools/jpackage/share/RuntimePackageTest.java +++ b/test/jdk/tools/jpackage/share/RuntimePackageTest.java @@ -30,7 +30,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.Objects; import java.util.function.Predicate; -import jdk.jpackage.internal.util.function.ThrowingSupplier; +import java.util.function.Supplier; import jdk.jpackage.test.Annotations.Parameter; import jdk.jpackage.test.Annotations.Test; import jdk.jpackage.test.JPackageCommand; @@ -114,7 +114,7 @@ public class RuntimePackageTest { return init(JPackageCommand::createInputRuntimeImage); } - private static PackageTest init(ThrowingSupplier createRuntime) { + private static PackageTest init(Supplier createRuntime) { Objects.requireNonNull(createRuntime); final Path[] runtimeImageDir = new Path[1]; diff --git a/test/jdk/tools/jpackage/share/ServiceTest.java b/test/jdk/tools/jpackage/share/ServiceTest.java index 94d3421a2cd..91950f0dba8 100644 --- a/test/jdk/tools/jpackage/share/ServiceTest.java +++ b/test/jdk/tools/jpackage/share/ServiceTest.java @@ -109,7 +109,7 @@ public class ServiceTest { } @Test - public void test() throws Throwable { + public void test() { var pkg = createPackageTest().addHelloAppInitializer("com.foo.ServiceTest"); LauncherAsServiceVerifier.build().setExpectedValue("A1").applyTo(pkg); createTestInitializer().applyTo(pkg); @@ -117,7 +117,7 @@ public class ServiceTest { } @Test - public void testUpdate() throws Throwable { + public void testUpdate() { var testInitializer = createTestInitializer().setUpgradeCode( "4050AD4D-D6CC-452A-9CB0-58E5FA8C410F"); From 30be94086aad42b99a15a05fe5115f552e8efb8b Mon Sep 17 00:00:00 2001 From: Jonas Norlinder Date: Tue, 16 Dec 2025 21:33:27 +0000 Subject: [PATCH 325/706] 8373625: CPUTimeCounters creates a total counter for unsupported GCs Reviewed-by: sjohanss, tschatzl --- src/hotspot/share/runtime/cpuTimeCounters.hpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/runtime/cpuTimeCounters.hpp b/src/hotspot/share/runtime/cpuTimeCounters.hpp index 9ad00492731..c2e636bdb1d 100644 --- a/src/hotspot/share/runtime/cpuTimeCounters.hpp +++ b/src/hotspot/share/runtime/cpuTimeCounters.hpp @@ -28,6 +28,7 @@ #define SHARE_RUNTIME_CPUTIMECOUNTERS_HPP +#include "gc/shared/gc_globals.hpp" #include "memory/iterator.hpp" #include "runtime/os.hpp" #include "runtime/perfData.hpp" @@ -83,7 +84,9 @@ public: assert(_instance == nullptr, "we can only allocate one CPUTimeCounters object"); if (UsePerfData && os::is_thread_cpu_time_supported()) { _instance = new CPUTimeCounters(); - create_counter(SUN_THREADS, CPUTimeGroups::CPUTimeType::gc_total); + if (UseG1GC || UseParallelGC) { + create_counter(SUN_THREADS, CPUTimeGroups::CPUTimeType::gc_total); + } } } From 87d881fee01c42f5847031a63d50873b3d438f7a Mon Sep 17 00:00:00 2001 From: Bradford Wetmore Date: Tue, 16 Dec 2025 21:43:43 +0000 Subject: [PATCH 326/706] 8368493: Disable most test JSSE debug output by default, and increase the test default maximum output log size Reviewed-by: jnimeh, hchao --- test/jdk/javax/net/ssl/DTLS/TEST.properties | 1 - .../net/ssl/HttpsURLConnection/Equals.java | 19 ++- .../net/ssl/SSLEngine/NoAuthClientAuth.java | 4 +- .../ssl/SSLSession/ResumeTLS13withSNI.java | 4 +- ...erverNameRejectedTLSSessionResumption.java | 19 ++- .../SSLEngineExplorerMatchedSNI.java | 4 +- .../ssl/Stapling/SSLEngineWithStapling.java | 6 +- test/jdk/javax/net/ssl/TEST.properties | 1 + test/jdk/javax/net/ssl/TLS/TestJSSE.java | 17 ++- test/jdk/javax/net/ssl/TLSCommon/TLSTest.java | 126 ++++++++++-------- .../javax/net/ssl/TLSCommon/TLSWithEdDSA.java | 20 ++- .../javax/net/ssl/TLSv12/ShortRSAKey512.java | 4 +- .../net/ssl/TLSv13/ClientHelloKeyShares.java | 20 ++- .../javax/net/ssl/TLSv13/HRRKeyShares.java | 20 ++- .../compatibility/ClientHelloProcessing.java | 19 ++- .../net/ssl/templates/SSLEngineTemplate.java | 16 +++ .../net/ssl/templates/SSLSocketTemplate.java | 15 +++ .../ssl/SSLEngineImpl/TestBadDNForPeerCA.java | 17 ++- .../SSLEngineImpl/TestBadDNForPeerCA12.java | 18 ++- .../NoInvalidateSocketException.java | 16 ++- .../ResumeClientTLS12withSNI.java | 18 ++- .../AnonCipherWithWantClientAuth.java | 21 ++- .../SigAlgosExtTestWithTLS12.java | 16 ++- .../SigSchemePropOrdering.java | 15 ++- .../ssl/Stapling/StatusResponseManager.java | 5 +- .../ssl/StatusResponseManagerTests.java | 17 ++- test/jdk/sun/security/ssl/TEST.properties | 1 + 27 files changed, 357 insertions(+), 102 deletions(-) create mode 100644 test/jdk/javax/net/ssl/TEST.properties create mode 100644 test/jdk/sun/security/ssl/TEST.properties diff --git a/test/jdk/javax/net/ssl/DTLS/TEST.properties b/test/jdk/javax/net/ssl/DTLS/TEST.properties index a50cba09c0f..ceb6c8c9c42 100644 --- a/test/jdk/javax/net/ssl/DTLS/TEST.properties +++ b/test/jdk/javax/net/ssl/DTLS/TEST.properties @@ -6,4 +6,3 @@ modules = \ java.security.jgss/sun.security.krb5.internal:+open \ java.security.jgss/sun.security.krb5.internal.ktab \ java.base/sun.security.util -maxOutputSize = 2500000 diff --git a/test/jdk/javax/net/ssl/HttpsURLConnection/Equals.java b/test/jdk/javax/net/ssl/HttpsURLConnection/Equals.java index d36dfb2630e..35913edd2bf 100644 --- a/test/jdk/javax/net/ssl/HttpsURLConnection/Equals.java +++ b/test/jdk/javax/net/ssl/HttpsURLConnection/Equals.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, 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,7 +27,7 @@ * @library /test/lib * @modules jdk.httpserver * @build jdk.test.lib.net.SimpleSSLContext - * @run main/othervm -Djavax.net.debug=ssl,handshake,record Equals + * @run main/othervm Equals */ import com.sun.net.httpserver.*; import java.net.*; @@ -38,9 +38,24 @@ import jdk.test.lib.net.SimpleSSLContext; public class Equals { + /* + * Enables the JSSE system debugging system property: + * + * -Djavax.net.debug=ssl,handshake,record + * + * This gives a lot of low-level information about operations underway, + * including specific handshake messages, and might be best examined + * after gaining some familiarity with this application. + */ + private static final boolean debug = false; + static SSLContext ctx; public static void main(String[] args) throws Exception { + if (debug) { + System.setProperty("javax.net.debug", "ssl,handshake,record"); + } + HttpsServer s2 = null; ExecutorService executor = null; try { diff --git a/test/jdk/javax/net/ssl/SSLEngine/NoAuthClientAuth.java b/test/jdk/javax/net/ssl/SSLEngine/NoAuthClientAuth.java index 208fb3935ae..95754a4763e 100644 --- a/test/jdk/javax/net/ssl/SSLEngine/NoAuthClientAuth.java +++ b/test/jdk/javax/net/ssl/SSLEngine/NoAuthClientAuth.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, 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 @@ -99,7 +99,7 @@ public class NoAuthClientAuth { * including specific handshake messages, and might be best examined * after gaining some familiarity with this application. */ - private static boolean debug = true; + private static boolean debug = false; private SSLContext sslc; diff --git a/test/jdk/javax/net/ssl/SSLSession/ResumeTLS13withSNI.java b/test/jdk/javax/net/ssl/SSLSession/ResumeTLS13withSNI.java index 3d05607bd39..d288fe70200 100644 --- a/test/jdk/javax/net/ssl/SSLSession/ResumeTLS13withSNI.java +++ b/test/jdk/javax/net/ssl/SSLSession/ResumeTLS13withSNI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, 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 @@ -54,7 +54,7 @@ public class ResumeTLS13withSNI { * including specific handshake messages, and might be best examined * after gaining some familiarity with this application. */ - private static final boolean debug = true; + private static final boolean debug = false; private static final ByteBuffer clientOut = ByteBuffer.wrap("Hi Server, I'm Client".getBytes()); diff --git a/test/jdk/javax/net/ssl/SSLSession/ServerNameRejectedTLSSessionResumption.java b/test/jdk/javax/net/ssl/SSLSession/ServerNameRejectedTLSSessionResumption.java index f80f3402c7e..de51b9c565e 100644 --- a/test/jdk/javax/net/ssl/SSLSession/ServerNameRejectedTLSSessionResumption.java +++ b/test/jdk/javax/net/ssl/SSLSession/ServerNameRejectedTLSSessionResumption.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, 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,11 +43,20 @@ import javax.net.ssl.StandardConstants; * between the server and the client happens correctly without any * errors * @library /javax/net/ssl/templates - * @run main/othervm -Djavax.net.debug=all - * ServerNameRejectedTLSSessionResumption + * @run main/othervm ServerNameRejectedTLSSessionResumption */ public class ServerNameRejectedTLSSessionResumption extends SSLContextTemplate { + /* + * Enables the JSSE system debugging system property: + * + * -Djavax.net.debug=all + * + * This gives a lot of low-level information about operations underway, + * including specific handshake messages, and might be best examined + * after gaining some familiarity with this application. + */ + private static final boolean debug = false; private static final String CLIENT_REQUESTED_SNI = "client.local"; // dummy host, no connection is attempted in this test @@ -56,6 +65,10 @@ public class ServerNameRejectedTLSSessionResumption private static final int PEER_PORT = 12345; public static void main(final String[] args) throws Exception { + if (debug) { + System.setProperty("javax.net.debug", "all"); + } + new ServerNameRejectedTLSSessionResumption().runTest(); } diff --git a/test/jdk/javax/net/ssl/ServerName/SSLEngineExplorerMatchedSNI.java b/test/jdk/javax/net/ssl/ServerName/SSLEngineExplorerMatchedSNI.java index a42134abdb1..bb288684384 100644 --- a/test/jdk/javax/net/ssl/ServerName/SSLEngineExplorerMatchedSNI.java +++ b/test/jdk/javax/net/ssl/ServerName/SSLEngineExplorerMatchedSNI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, 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 @@ -71,7 +71,7 @@ public class SSLEngineExplorerMatchedSNI extends SSLEngineService { /* * Turn on SSL debugging? */ - static boolean debug = true; + static boolean debug = false; /* * Define the server side of the test. diff --git a/test/jdk/javax/net/ssl/Stapling/SSLEngineWithStapling.java b/test/jdk/javax/net/ssl/Stapling/SSLEngineWithStapling.java index 506e7b00e6d..34398a4b6f8 100644 --- a/test/jdk/javax/net/ssl/Stapling/SSLEngineWithStapling.java +++ b/test/jdk/javax/net/ssl/Stapling/SSLEngineWithStapling.java @@ -99,13 +99,13 @@ public class SSLEngineWithStapling { /* * Enables the JSSE system debugging system property: * - * -Djavax.net.debug=all + * -Djavax.net.debug=ssl,handshake * * This gives a lot of low-level information about operations underway, * including specific handshake messages, and might be best examined * after gaining some familiarity with this application. */ - private static final boolean debug = true; + private static final boolean debug = false; private SSLEngine clientEngine; // client Engine private ByteBuffer clientOut; // write side of clientEngine @@ -151,7 +151,7 @@ public class SSLEngineWithStapling { */ public static void main(String args[]) throws Exception { if (debug) { - System.setProperty("javax.net.debug", "ssl:handshake"); + System.setProperty("javax.net.debug", "ssl,handshake"); } // Create the PKI we will use for the test and start the OCSP servers diff --git a/test/jdk/javax/net/ssl/TEST.properties b/test/jdk/javax/net/ssl/TEST.properties new file mode 100644 index 00000000000..741c2565067 --- /dev/null +++ b/test/jdk/javax/net/ssl/TEST.properties @@ -0,0 +1 @@ +maxOutputSize=500000 diff --git a/test/jdk/javax/net/ssl/TLS/TestJSSE.java b/test/jdk/javax/net/ssl/TLS/TestJSSE.java index 29631064011..baabd7f6054 100644 --- a/test/jdk/javax/net/ssl/TLS/TestJSSE.java +++ b/test/jdk/javax/net/ssl/TLS/TestJSSE.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2025, 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,17 @@ import java.security.Security; public class TestJSSE { + /* + * Enables the JSSE system debugging system property: + * + * -Djavax.net.debug=ssl,record + * + * This gives a lot of low-level information about operations underway, + * including specific handshake messages, and might be best examined + * after gaining some familiarity with this application. + */ + private static final boolean debug = false; + private static final String LOCAL_IP = InetAddress.getLoopbackAddress().getHostAddress(); public static void main(String... args) throws Exception { @@ -35,7 +46,9 @@ public class TestJSSE { Security.setProperty("jdk.tls.disabledAlgorithms", ""); // enable debug output - System.setProperty("javax.net.debug", "ssl,record"); + if (debug) { + System.setProperty("javax.net.debug", "ssl,record"); + } String srvProtocol = System.getProperty("SERVER_PROTOCOL"); String clnProtocol = System.getProperty("CLIENT_PROTOCOL"); diff --git a/test/jdk/javax/net/ssl/TLSCommon/TLSTest.java b/test/jdk/javax/net/ssl/TLSCommon/TLSTest.java index 6aec08deedd..fc6369a2bbc 100644 --- a/test/jdk/javax/net/ssl/TLSCommon/TLSTest.java +++ b/test/jdk/javax/net/ssl/TLSCommon/TLSTest.java @@ -49,98 +49,112 @@ import javax.net.ssl.TrustManagerFactory; * @bug 8205111 * @enablePreview * @summary Test TLS with different types of supported keys. - * @run main/othervm -Djavax.net.debug=ssl,handshake TLSTest TLSv1.3 rsa_pkcs1_sha1 TLS_AES_128_GCM_SHA256 - * @run main/othervm -Djavax.net.debug=ssl,handshake TLSTest TLSv1.3 rsa_pkcs1_sha256 TLS_AES_128_GCM_SHA256 - * @run main/othervm -Djavax.net.debug=ssl,handshake TLSTest TLSv1.3 rsa_pkcs1_sha384 TLS_AES_128_GCM_SHA256 - * @run main/othervm -Djavax.net.debug=ssl,handshake TLSTest TLSv1.3 rsa_pkcs1_sha512 TLS_AES_128_GCM_SHA256 - * @run main/othervm -Djavax.net.debug=ssl,handshake TLSTest TLSv1.3 ec_rsa_pkcs1_sha256 TLS_AES_128_GCM_SHA256 - * @run main/othervm -Djavax.net.debug=ssl,handshake TLSTest TLSv1.3 ecdsa_sha1 TLS_AES_128_GCM_SHA256 - * @run main/othervm -Djavax.net.debug=ssl,handshake TLSTest TLSv1.3 ecdsa_secp384r1_sha384 + * @run main/othervm TLSTest TLSv1.3 rsa_pkcs1_sha1 TLS_AES_128_GCM_SHA256 + * @run main/othervm TLSTest TLSv1.3 rsa_pkcs1_sha256 TLS_AES_128_GCM_SHA256 + * @run main/othervm TLSTest TLSv1.3 rsa_pkcs1_sha384 TLS_AES_128_GCM_SHA256 + * @run main/othervm TLSTest TLSv1.3 rsa_pkcs1_sha512 TLS_AES_128_GCM_SHA256 + * @run main/othervm TLSTest TLSv1.3 ec_rsa_pkcs1_sha256 TLS_AES_128_GCM_SHA256 + * @run main/othervm TLSTest TLSv1.3 ecdsa_sha1 TLS_AES_128_GCM_SHA256 + * @run main/othervm TLSTest TLSv1.3 ecdsa_secp384r1_sha384 * TLS_AES_128_GCM_SHA256 - * @run main/othervm -Djavax.net.debug=ssl,handshake TLSTest TLSv1.3 ecdsa_secp521r1_sha512 + * @run main/othervm TLSTest TLSv1.3 ecdsa_secp521r1_sha512 * TLS_AES_128_GCM_SHA256 - * @run main/othervm -Djavax.net.debug=ssl,handshake TLSTest TLSv1.3 rsa_pss_rsae_sha256 TLS_AES_128_GCM_SHA256 - * @run main/othervm -Djavax.net.debug=ssl,handshake TLSTest TLSv1.3 rsa_pss_rsae_sha384 TLS_AES_128_GCM_SHA256 - * @run main/othervm -Djavax.net.debug=ssl,handshake TLSTest TLSv1.3 rsa_pss_rsae_sha512 TLS_AES_128_GCM_SHA256 - * @run main/othervm -Djavax.net.debug=ssl,handshake TLSTest TLSv1.3 rsa_pss_pss_sha256 TLS_AES_128_GCM_SHA256 - * @run main/othervm -Djavax.net.debug=ssl,handshake TLSTest TLSv1.3 rsa_pss_pss_sha384 TLS_AES_128_GCM_SHA256 - * @run main/othervm -Djavax.net.debug=ssl,handshake TLSTest TLSv1.3 rsa_pss_pss_sha512 TLS_AES_128_GCM_SHA256 + * @run main/othervm TLSTest TLSv1.3 rsa_pss_rsae_sha256 TLS_AES_128_GCM_SHA256 + * @run main/othervm TLSTest TLSv1.3 rsa_pss_rsae_sha384 TLS_AES_128_GCM_SHA256 + * @run main/othervm TLSTest TLSv1.3 rsa_pss_rsae_sha512 TLS_AES_128_GCM_SHA256 + * @run main/othervm TLSTest TLSv1.3 rsa_pss_pss_sha256 TLS_AES_128_GCM_SHA256 + * @run main/othervm TLSTest TLSv1.3 rsa_pss_pss_sha384 TLS_AES_128_GCM_SHA256 + * @run main/othervm TLSTest TLSv1.3 rsa_pss_pss_sha512 TLS_AES_128_GCM_SHA256 * - * @run main/othervm -Djavax.net.debug=ssl,handshake TLSTest TLSv1.3 rsa_pkcs1_sha1 TLS_AES_256_GCM_SHA384 - * @run main/othervm -Djavax.net.debug=ssl,handshake TLSTest TLSv1.3 rsa_pkcs1_sha256 TLS_AES_256_GCM_SHA384 - * @run main/othervm -Djavax.net.debug=ssl,handshake TLSTest TLSv1.3 rsa_pkcs1_sha384 TLS_AES_256_GCM_SHA384 - * @run main/othervm -Djavax.net.debug=ssl,handshake TLSTest TLSv1.3 rsa_pkcs1_sha512 TLS_AES_256_GCM_SHA384 - * @run main/othervm -Djavax.net.debug=ssl,handshake TLSTest TLSv1.3 ec_rsa_pkcs1_sha256 TLS_AES_256_GCM_SHA384 - * @run main/othervm -Djavax.net.debug=ssl,handshake TLSTest TLSv1.3 ecdsa_sha1 TLS_AES_256_GCM_SHA384 - * @run main/othervm -Djavax.net.debug=ssl,handshake TLSTest TLSv1.3 ecdsa_secp384r1_sha384 + * @run main/othervm TLSTest TLSv1.3 rsa_pkcs1_sha1 TLS_AES_256_GCM_SHA384 + * @run main/othervm TLSTest TLSv1.3 rsa_pkcs1_sha256 TLS_AES_256_GCM_SHA384 + * @run main/othervm TLSTest TLSv1.3 rsa_pkcs1_sha384 TLS_AES_256_GCM_SHA384 + * @run main/othervm TLSTest TLSv1.3 rsa_pkcs1_sha512 TLS_AES_256_GCM_SHA384 + * @run main/othervm TLSTest TLSv1.3 ec_rsa_pkcs1_sha256 TLS_AES_256_GCM_SHA384 + * @run main/othervm TLSTest TLSv1.3 ecdsa_sha1 TLS_AES_256_GCM_SHA384 + * @run main/othervm TLSTest TLSv1.3 ecdsa_secp384r1_sha384 * TLS_AES_256_GCM_SHA384 - * @run main/othervm -Djavax.net.debug=ssl,handshake TLSTest TLSv1.3 ecdsa_secp521r1_sha512 + * @run main/othervm TLSTest TLSv1.3 ecdsa_secp521r1_sha512 * TLS_AES_256_GCM_SHA384 - * @run main/othervm -Djavax.net.debug=ssl,handshake TLSTest TLSv1.3 rsa_pss_rsae_sha256 TLS_AES_256_GCM_SHA384 - * @run main/othervm -Djavax.net.debug=ssl,handshake TLSTest TLSv1.3 rsa_pss_rsae_sha384 TLS_AES_256_GCM_SHA384 - * @run main/othervm -Djavax.net.debug=ssl,handshake TLSTest TLSv1.3 rsa_pss_rsae_sha512 TLS_AES_256_GCM_SHA384 - * @run main/othervm -Djavax.net.debug=ssl,handshake TLSTest TLSv1.3 rsa_pss_pss_sha256 TLS_AES_256_GCM_SHA384 - * @run main/othervm -Djavax.net.debug=ssl,handshake TLSTest TLSv1.3 rsa_pss_pss_sha384 TLS_AES_256_GCM_SHA384 - * @run main/othervm -Djavax.net.debug=ssl,handshake TLSTest TLSv1.3 rsa_pss_pss_sha512 TLS_AES_256_GCM_SHA384 + * @run main/othervm TLSTest TLSv1.3 rsa_pss_rsae_sha256 TLS_AES_256_GCM_SHA384 + * @run main/othervm TLSTest TLSv1.3 rsa_pss_rsae_sha384 TLS_AES_256_GCM_SHA384 + * @run main/othervm TLSTest TLSv1.3 rsa_pss_rsae_sha512 TLS_AES_256_GCM_SHA384 + * @run main/othervm TLSTest TLSv1.3 rsa_pss_pss_sha256 TLS_AES_256_GCM_SHA384 + * @run main/othervm TLSTest TLSv1.3 rsa_pss_pss_sha384 TLS_AES_256_GCM_SHA384 + * @run main/othervm TLSTest TLSv1.3 rsa_pss_pss_sha512 TLS_AES_256_GCM_SHA384 * - * @run main/othervm -Djavax.net.debug=ssl,handshake TLSTest TLSv1.2 rsa_pkcs1_sha1 TLS_RSA_WITH_AES_128_CBC_SHA - * @run main/othervm -Djavax.net.debug=ssl,handshake TLSTest TLSv1.2 rsa_pkcs1_sha256 + * @run main/othervm TLSTest TLSv1.2 rsa_pkcs1_sha1 TLS_RSA_WITH_AES_128_CBC_SHA + * @run main/othervm TLSTest TLSv1.2 rsa_pkcs1_sha256 * TLS_RSA_WITH_AES_128_CBC_SHA - * @run main/othervm -Djavax.net.debug=ssl,handshake TLSTest TLSv1.2 rsa_pkcs1_sha384 + * @run main/othervm TLSTest TLSv1.2 rsa_pkcs1_sha384 * TLS_RSA_WITH_AES_256_GCM_SHA384 - * @run main/othervm -Djavax.net.debug=ssl,handshake TLSTest TLSv1.2 rsa_pkcs1_sha512 + * @run main/othervm TLSTest TLSv1.2 rsa_pkcs1_sha512 * TLS_RSA_WITH_AES_128_GCM_SHA256 - * @run main/othervm -Djavax.net.debug=ssl,handshake TLSTest TLSv1.2 ec_rsa_pkcs1_sha256 + * @run main/othervm TLSTest TLSv1.2 ec_rsa_pkcs1_sha256 * TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 - * @run main/othervm -Djavax.net.debug=ssl,handshake TLSTest TLSv1.2 ecdsa_sha1 + * @run main/othervm TLSTest TLSv1.2 ecdsa_sha1 * TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 - * @run main/othervm -Djavax.net.debug=ssl,handshake TLSTest TLSv1.2 ecdsa_secp384r1_sha384 + * @run main/othervm TLSTest TLSv1.2 ecdsa_secp384r1_sha384 * TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 - * @run main/othervm -Djavax.net.debug=ssl,handshake TLSTest TLSv1.2 ecdsa_secp521r1_sha512 + * @run main/othervm TLSTest TLSv1.2 ecdsa_secp521r1_sha512 * TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA - * @run main/othervm -Djavax.net.debug=ssl,handshake TLSTest TLSv1.2 rsa_pss_rsae_sha256 + * @run main/othervm TLSTest TLSv1.2 rsa_pss_rsae_sha256 * TLS_RSA_WITH_AES_256_CBC_SHA256 - * @run main/othervm -Djavax.net.debug=ssl,handshake TLSTest TLSv1.2 rsa_pss_rsae_sha384 + * @run main/othervm TLSTest TLSv1.2 rsa_pss_rsae_sha384 * TLS_RSA_WITH_AES_256_CBC_SHA - * @run main/othervm -Djavax.net.debug=ssl,handshake TLSTest TLSv1.2 rsa_pss_rsae_sha512 + * @run main/othervm TLSTest TLSv1.2 rsa_pss_rsae_sha512 * TLS_RSA_WITH_AES_128_CBC_SHA256 - * @run main/othervm -Djavax.net.debug=ssl,handshake TLSTest TLSv1.2 rsa_pss_pss_sha256 + * @run main/othervm TLSTest TLSv1.2 rsa_pss_pss_sha256 * TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 - * @run main/othervm -Djavax.net.debug=ssl,handshake TLSTest TLSv1.2 rsa_pss_pss_sha384 + * @run main/othervm TLSTest TLSv1.2 rsa_pss_pss_sha384 * TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 - * @run main/othervm -Djavax.net.debug=ssl,handshake TLSTest TLSv1.2 rsa_pss_pss_sha512 + * @run main/othervm TLSTest TLSv1.2 rsa_pss_pss_sha512 * TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 * - * @run main/othervm -Djavax.net.debug=ssl,handshake TLSTest TLSv1.1 rsa_pkcs1_sha1 TLS_RSA_WITH_AES_128_CBC_SHA - * @run main/othervm -Djavax.net.debug=ssl,handshake TLSTest TLSv1.1 rsa_pkcs1_sha256 + * @run main/othervm TLSTest TLSv1.1 rsa_pkcs1_sha1 TLS_RSA_WITH_AES_128_CBC_SHA + * @run main/othervm TLSTest TLSv1.1 rsa_pkcs1_sha256 * TLS_RSA_WITH_AES_256_CBC_SHA - * @run main/othervm -Djavax.net.debug=ssl,handshake TLSTest TLSv1.1 rsa_pkcs1_sha384 + * @run main/othervm TLSTest TLSv1.1 rsa_pkcs1_sha384 * TLS_RSA_WITH_AES_128_CBC_SHA - * @run main/othervm -Djavax.net.debug=ssl,handshake TLSTest TLSv1.1 rsa_pkcs1_sha512 + * @run main/othervm TLSTest TLSv1.1 rsa_pkcs1_sha512 * TLS_RSA_WITH_AES_256_CBC_SHA - * @run main/othervm -Djavax.net.debug=ssl,handshake TLSTest TLSv1.1 rsa_pss_rsae_sha256 + * @run main/othervm TLSTest TLSv1.1 rsa_pss_rsae_sha256 * TLS_RSA_WITH_AES_128_CBC_SHA - * @run main/othervm -Djavax.net.debug=ssl,handshake TLSTest TLSv1.1 rsa_pss_rsae_sha384 + * @run main/othervm TLSTest TLSv1.1 rsa_pss_rsae_sha384 * TLS_RSA_WITH_AES_256_CBC_SHA - * @run main/othervm -Djavax.net.debug=ssl,handshake TLSTest TLSv1.1 rsa_pss_rsae_sha512 + * @run main/othervm TLSTest TLSv1.1 rsa_pss_rsae_sha512 * TLS_RSA_WITH_AES_128_CBC_SHA * - * @run main/othervm -Djavax.net.debug=ssl,handshake TLSTest TLSv1 rsa_pkcs1_sha1 TLS_RSA_WITH_AES_128_CBC_SHA - * @run main/othervm -Djavax.net.debug=ssl,handshake TLSTest TLSv1 rsa_pkcs1_sha256 TLS_RSA_WITH_AES_256_CBC_SHA - * @run main/othervm -Djavax.net.debug=ssl,handshake TLSTest TLSv1 rsa_pkcs1_sha384 TLS_RSA_WITH_AES_128_CBC_SHA - * @run main/othervm -Djavax.net.debug=ssl,handshake TLSTest TLSv1 rsa_pkcs1_sha512 TLS_RSA_WITH_AES_256_CBC_SHA - * @run main/othervm -Djavax.net.debug=ssl,handshake TLSTest TLSv1 rsa_pss_rsae_sha256 + * @run main/othervm TLSTest TLSv1 rsa_pkcs1_sha1 TLS_RSA_WITH_AES_128_CBC_SHA + * @run main/othervm TLSTest TLSv1 rsa_pkcs1_sha256 TLS_RSA_WITH_AES_256_CBC_SHA + * @run main/othervm TLSTest TLSv1 rsa_pkcs1_sha384 TLS_RSA_WITH_AES_128_CBC_SHA + * @run main/othervm TLSTest TLSv1 rsa_pkcs1_sha512 TLS_RSA_WITH_AES_256_CBC_SHA + * @run main/othervm TLSTest TLSv1 rsa_pss_rsae_sha256 * TLS_RSA_WITH_AES_128_CBC_SHA - * @run main/othervm -Djavax.net.debug=ssl,handshake TLSTest TLSv1 rsa_pss_rsae_sha384 + * @run main/othervm TLSTest TLSv1 rsa_pss_rsae_sha384 * TLS_RSA_WITH_AES_256_CBC_SHA - * @run main/othervm -Djavax.net.debug=ssl,handshake TLSTest TLSv1 rsa_pss_rsae_sha512 + * @run main/othervm TLSTest TLSv1 rsa_pss_rsae_sha512 * TLS_RSA_WITH_AES_128_CBC_SHA */ public class TLSTest { + /* + * Enables the JSSE system debugging system property: + * + * -Djavax.net.debug=ssl,handshake + * + * This gives a lot of low-level information about operations underway, + * including specific handshake messages, and might be best examined + * after gaining some familiarity with this application. + */ + private static final boolean debug = false; + private volatile static boolean clientRenegoReady = false; public static void main(String[] args) throws Exception { + if (debug) { + System.setProperty("javax.net.debug", "ssl,handshake"); + } final String tlsProtocol = args[0]; final KeyType keyType = KeyType.valueOf(args[1]); diff --git a/test/jdk/javax/net/ssl/TLSCommon/TLSWithEdDSA.java b/test/jdk/javax/net/ssl/TLSCommon/TLSWithEdDSA.java index 3fabc5bd73c..f21b7b32b6a 100644 --- a/test/jdk/javax/net/ssl/TLSCommon/TLSWithEdDSA.java +++ b/test/jdk/javax/net/ssl/TLSCommon/TLSWithEdDSA.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, 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,8 +24,6 @@ /* * SunJSSE does not support dynamic system properties, no way to re-use * system properties in samevm/agentvm mode. - * For extra debugging output, add -Djavax.net.debug=ssl:handshake into the - * run directive below. */ /* @@ -74,6 +72,18 @@ import javax.net.ssl.X509KeyManager; import jdk.test.lib.security.SecurityUtils; public class TLSWithEdDSA extends SSLSocketTemplate { + + /* + * Enables the JSSE system debugging system property: + * + * -Djavax.net.debug=ssl,handshake + * + * This gives a lot of low-level information about operations underway, + * including specific handshake messages, and might be best examined + * after gaining some familiarity with this application. + */ + private static final boolean debug = false; + private static final String PASSWD = "passphrase"; private static final String DEF_TRUST_ANCHORS = "CA_DSA_1024:CA_DSA_2048:" + "CA_ECDSA_SECP256R1:CA_ECDSA_SECP384R1:CA_ECDSA_SECP521R1:" + @@ -556,6 +566,10 @@ public class TLSWithEdDSA extends SSLSocketTemplate { } public static void main(String[] args) throws Exception { + if (debug) { + System.setProperty("javax.net.debug", "ssl,handshake"); + } + SecurityUtils.removeFromDisabledTlsAlgs("TLSv1.1", "TLSv1"); certFac = CertificateFactory.getInstance("X.509"); String testFormat; diff --git a/test/jdk/javax/net/ssl/TLSv12/ShortRSAKey512.java b/test/jdk/javax/net/ssl/TLSv12/ShortRSAKey512.java index 4d4331dc973..3f8e5e4e6a5 100644 --- a/test/jdk/javax/net/ssl/TLSv12/ShortRSAKey512.java +++ b/test/jdk/javax/net/ssl/TLSv12/ShortRSAKey512.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, 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 @@ -65,7 +65,7 @@ public class ShortRSAKey512 extends SSLContextTemplate { /* * Turn on SSL debugging? */ - static boolean debug = true; + static boolean debug = false; /* * Define the server side of the test. diff --git a/test/jdk/javax/net/ssl/TLSv13/ClientHelloKeyShares.java b/test/jdk/javax/net/ssl/TLSv13/ClientHelloKeyShares.java index 56f37a9e4f1..efb9895b33c 100644 --- a/test/jdk/javax/net/ssl/TLSv13/ClientHelloKeyShares.java +++ b/test/jdk/javax/net/ssl/TLSv13/ClientHelloKeyShares.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, 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,8 +22,7 @@ */ // SunJSSE does not support dynamic system properties, no way to re-use -// system properties in samevm/agentvm mode. For further debugging output -// set the -Djavax.net.debug=ssl:handshake property on the @run lines. +// system properties in samevm/agentvm mode. /* * @test @@ -46,6 +45,17 @@ import java.util.*; public class ClientHelloKeyShares { + /* + * Enables the JSSE system debugging system property: + * + * -Djavax.net.debug=ssl,handshake + * + * This gives a lot of low-level information about operations underway, + * including specific handshake messages, and might be best examined + * after gaining some familiarity with this application. + */ + private static final boolean debug = false; + // Some TLS constants we'll use for testing private static final int TLS_REC_HANDSHAKE = 22; private static final int HELLO_EXT_SUPP_GROUPS = 10; @@ -58,6 +68,10 @@ public class ClientHelloKeyShares { private static final int NG_X448 = 0x001E; public static void main(String args[]) throws Exception { + if (debug) { + System.setProperty("javax.net.debug", "ssl,handshake"); + } + // Arguments to this test are an abitrary number of integer // values which will be the expected NamedGroup IDs in the key_share // extension. Expected named group assertions may also be affected diff --git a/test/jdk/javax/net/ssl/TLSv13/HRRKeyShares.java b/test/jdk/javax/net/ssl/TLSv13/HRRKeyShares.java index 313b2c5084b..560faf87049 100644 --- a/test/jdk/javax/net/ssl/TLSv13/HRRKeyShares.java +++ b/test/jdk/javax/net/ssl/TLSv13/HRRKeyShares.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, 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,8 +22,7 @@ */ // SunJSSE does not support dynamic system properties, no way to re-use -// system properties in samevm/agentvm mode. For further debugging output -// set the -Djavax.net.debug=ssl:handshake property on the @run lines. +// system properties in samevm/agentvm mode. /* * @test @@ -48,6 +47,16 @@ import jdk.test.lib.Utils; public class HRRKeyShares { + /* + * Enables the JSSE system debugging system property: + * + * -Djavax.net.debug=ssl,handshake + * + * This gives a lot of low-level information about operations underway, + * including specific handshake messages, and might be best examined + * after gaining some familiarity with this application. + */ + private static final boolean debug = false; // Some TLS constants we'll use for testing private static final int TLS_REC_HANDSHAKE = 22; @@ -209,6 +218,11 @@ public class HRRKeyShares { } public static void main(String args[]) throws Exception { + + if (debug) { + System.setProperty("javax.net.debug", "ssl,handshake"); + } + System.out.println("Test 1: Good HRR exchange using secp384r1"); hrrKeyShareTest(NG_SECP384R1, true); System.out.println(); diff --git a/test/jdk/javax/net/ssl/compatibility/ClientHelloProcessing.java b/test/jdk/javax/net/ssl/compatibility/ClientHelloProcessing.java index c147f732ec5..4c1b621b180 100644 --- a/test/jdk/javax/net/ssl/compatibility/ClientHelloProcessing.java +++ b/test/jdk/javax/net/ssl/compatibility/ClientHelloProcessing.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, 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,6 +60,17 @@ import java.util.Objects; public class ClientHelloProcessing { + /* + * Enables the JSSE system debugging system property: + * + * -Djavax.net.debug=ssl:handshake + * + * This gives a lot of low-level information about operations underway, + * including specific handshake messages, and might be best examined + * after gaining some familiarity with this application. + */ + private static final boolean debug = false; + private static final ByteBuffer SERVOUTBUF = ByteBuffer.wrap("Server Side".getBytes()); @@ -476,7 +487,11 @@ public class ClientHelloProcessing { public static void main(String[] args) throws Exception { boolean allGood = true; - System.setProperty("javax.net.debug", "ssl:handshake"); + + if (debug) { + System.setProperty("javax.net.debug", "ssl:handshake"); + } + trustMgrFac = makeTrustManagerFactory(trustFilename, passwd); keyMgrFac = makeKeyManagerFactory(keyFilename, passwd); diff --git a/test/jdk/javax/net/ssl/templates/SSLEngineTemplate.java b/test/jdk/javax/net/ssl/templates/SSLEngineTemplate.java index 2c1cfaa44ef..fed82d1164f 100644 --- a/test/jdk/javax/net/ssl/templates/SSLEngineTemplate.java +++ b/test/jdk/javax/net/ssl/templates/SSLEngineTemplate.java @@ -54,6 +54,18 @@ import java.nio.ByteBuffer; * produced. */ public class SSLEngineTemplate extends SSLContextTemplate { + + /* + * Enables the JSSE system debugging system property: + * + * -Djavax.net.debug=all + * + * This gives a lot of low-level information about operations underway, + * including specific handshake messages, and might be best examined + * after gaining some familiarity with this application. + */ + private static final boolean debug = false; + protected final SSLEngine clientEngine; // client Engine protected final ByteBuffer clientOut; // write side of clientEngine protected final ByteBuffer clientIn; // read side of clientEngine @@ -139,6 +151,10 @@ public class SSLEngineTemplate extends SSLContextTemplate { } public static void main(String[] args) throws Exception { + if (debug) { + System.setProperty("javax.net.debug", "all"); + } + new SSLEngineTemplate().runTest(); } diff --git a/test/jdk/javax/net/ssl/templates/SSLSocketTemplate.java b/test/jdk/javax/net/ssl/templates/SSLSocketTemplate.java index 51706cec927..9d1b1fe94c4 100644 --- a/test/jdk/javax/net/ssl/templates/SSLSocketTemplate.java +++ b/test/jdk/javax/net/ssl/templates/SSLSocketTemplate.java @@ -58,11 +58,26 @@ import java.util.concurrent.TimeUnit; */ public class SSLSocketTemplate extends SSLContextTemplate { + /* + * Enables the JSSE system debugging system property: + * + * -Djavax.net.debug=all + * + * This gives a lot of low-level information about operations underway, + * including specific handshake messages, and might be best examined + * after gaining some familiarity with this application. + */ + private static final boolean debug = false; + /* * ================== * Run the test case. */ public static void main(String[] args) throws Exception { + if (debug) { + System.setProperty("javax.net.debug", "all"); + } + (new SSLSocketTemplate()).run(); } diff --git a/test/jdk/sun/security/ssl/SSLEngineImpl/TestBadDNForPeerCA.java b/test/jdk/sun/security/ssl/SSLEngineImpl/TestBadDNForPeerCA.java index 20b4c39afb1..cbdabea4a19 100644 --- a/test/jdk/sun/security/ssl/SSLEngineImpl/TestBadDNForPeerCA.java +++ b/test/jdk/sun/security/ssl/SSLEngineImpl/TestBadDNForPeerCA.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, 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,7 +27,6 @@ * @library /test/lib * @summary SSLEngine throws IAE during parsing of X500Principal * @run main/othervm TestBadDNForPeerCA - * @run main/othervm -Djavax.net.debug=all TestBadDNForPeerCA */ import javax.net.ssl.KeyManagerFactory; @@ -45,6 +44,16 @@ import java.util.Base64; public class TestBadDNForPeerCA { + /* + * Enables the JSSE system debugging system property: + * + * -Djavax.net.debug=all + * + * This gives a lot of low-level information about operations underway, + * including specific handshake messages, and might be best examined + * after gaining some familiarity with this application. + */ + private static final boolean debug = false; private static final String proto = "TLSv1.3"; @@ -85,6 +94,10 @@ public class TestBadDNForPeerCA { */ public static void main(String[] args) throws Exception { + if (debug) { + System.setProperty("javax.net.debug", "all"); + } + TestBadDNForPeerCA test = new TestBadDNForPeerCA(); try { diff --git a/test/jdk/sun/security/ssl/SSLEngineImpl/TestBadDNForPeerCA12.java b/test/jdk/sun/security/ssl/SSLEngineImpl/TestBadDNForPeerCA12.java index 527ceb406c6..70405b61ab3 100644 --- a/test/jdk/sun/security/ssl/SSLEngineImpl/TestBadDNForPeerCA12.java +++ b/test/jdk/sun/security/ssl/SSLEngineImpl/TestBadDNForPeerCA12.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, 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,7 +27,6 @@ * @library /test/lib * @summary SSLEngine throws IAE during parsing of X500Principal * @run main/othervm TestBadDNForPeerCA12 - * @run main/othervm -Djavax.net.debug=all TestBadDNForPeerCA12 */ import javax.net.ssl.KeyManagerFactory; @@ -45,6 +44,17 @@ import java.util.Base64; public class TestBadDNForPeerCA12 { + /* + * Enables the JSSE system debugging system property: + * + * -Djavax.net.debug=all + * + * This gives a lot of low-level information about operations underway, + * including specific handshake messages, and might be best examined + * after gaining some familiarity with this application. + */ + private static final boolean debug = false; + // Test was originally written for TLSv1.2 private static final String proto = "TLSv1.2"; @@ -108,6 +118,10 @@ public class TestBadDNForPeerCA12 { */ public static void main(String[] args) throws Exception { + if (debug) { + System.setProperty("javax.net.debug", "all"); + } + TestBadDNForPeerCA12 test = new TestBadDNForPeerCA12(); try { diff --git a/test/jdk/sun/security/ssl/SSLSessionImpl/NoInvalidateSocketException.java b/test/jdk/sun/security/ssl/SSLSessionImpl/NoInvalidateSocketException.java index 696eb58d463..977e005daf3 100644 --- a/test/jdk/sun/security/ssl/SSLSessionImpl/NoInvalidateSocketException.java +++ b/test/jdk/sun/security/ssl/SSLSessionImpl/NoInvalidateSocketException.java @@ -52,6 +52,18 @@ import java.util.Objects; import java.util.concurrent.TimeUnit; public class NoInvalidateSocketException extends SSLSocketTemplate { + + /* + * Enables the JSSE system debugging system property: + * + * -Djavax.net.debug=ssl,session + * + * This gives a lot of low-level information about operations underway, + * including specific handshake messages, and might be best examined + * after gaining some familiarity with this application. + */ + private static final boolean debug = false; + private static final int ITERATIONS = 10; // This controls how long the main thread waits before closing the socket. @@ -73,8 +85,8 @@ public class NoInvalidateSocketException extends SSLSocketTemplate { private static volatile boolean finished = false; public static void main(String[] args) throws Exception { - if (System.getProperty("javax.net.debug") == null) { - System.setProperty("javax.net.debug", "session"); + if (debug) { + System.setProperty("javax.net.debug", "ssl,session"); } if (args != null && args.length >= 1) { diff --git a/test/jdk/sun/security/ssl/SSLSessionImpl/ResumeClientTLS12withSNI.java b/test/jdk/sun/security/ssl/SSLSessionImpl/ResumeClientTLS12withSNI.java index c9768c1756c..b21d7aa4e31 100644 --- a/test/jdk/sun/security/ssl/SSLSessionImpl/ResumeClientTLS12withSNI.java +++ b/test/jdk/sun/security/ssl/SSLSessionImpl/ResumeClientTLS12withSNI.java @@ -26,7 +26,7 @@ * @bug 8350830 * @summary TLS 1.2 Client session resumption having ServerNameIndication * @modules java.base/sun.security.tools.keytool - * @run main/othervm -Djavax.net.debug=all ResumeClientTLS12withSNI + * @run main/othervm ResumeClientTLS12withSNI */ import javax.net.ssl.*; @@ -41,6 +41,17 @@ import java.util.*; public class ResumeClientTLS12withSNI { + /* + * Enables the JSSE system debugging system property: + * + * -Djavax.net.debug=all + * + * This gives a lot of low-level information about operations underway, + * including specific handshake messages, and might be best examined + * after gaining some familiarity with this application. + */ + private static final boolean debug = false; + /* * Enables logging of the SSLEngine operations. */ @@ -77,6 +88,11 @@ public class ResumeClientTLS12withSNI { * Main entry point for this test. */ public static void main(String args[]) throws Exception { + + if (debug) { + System.setProperty("javax.net.debug", "all"); + } + Files.deleteIfExists(Path.of(keyFilename)); sun.security.tools.keytool.Main.main( diff --git a/test/jdk/sun/security/ssl/ServerHandshaker/AnonCipherWithWantClientAuth.java b/test/jdk/sun/security/ssl/ServerHandshaker/AnonCipherWithWantClientAuth.java index 145a68a6b0e..d085c1fe890 100644 --- a/test/jdk/sun/security/ssl/ServerHandshaker/AnonCipherWithWantClientAuth.java +++ b/test/jdk/sun/security/ssl/ServerHandshaker/AnonCipherWithWantClientAuth.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, 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,7 @@ * @modules jdk.crypto.ec * @library /javax/net/ssl/templates * @summary Calling setWantClientAuth(true) disables anonymous suites - * @run main/othervm -Djavax.net.debug=all AnonCipherWithWantClientAuth + * @run main/othervm AnonCipherWithWantClientAuth */ import java.io.InputStream; @@ -41,10 +41,27 @@ import java.security.Security; import javax.net.ssl.SSLSocket; public class AnonCipherWithWantClientAuth extends SSLSocketTemplate { + + /* + * Enables the JSSE system debugging system property: + * + * -Djavax.net.debug=all + * + * This gives a lot of low-level information about operations underway, + * including specific handshake messages, and might be best examined + * after gaining some familiarity with this application. + */ + private static final boolean debug = false; + /* * Run the test case. */ public static void main(String[] args) throws Exception { + + if (debug) { + System.setProperty("javax.net.debug", "all"); + } + // reset the security property to make sure that the algorithms // and keys used in this test are not disabled. Security.setProperty("jdk.tls.disabledAlgorithms", ""); diff --git a/test/jdk/sun/security/ssl/SignatureScheme/SigAlgosExtTestWithTLS12.java b/test/jdk/sun/security/ssl/SignatureScheme/SigAlgosExtTestWithTLS12.java index 43bc40fabf2..351d3ad76a1 100644 --- a/test/jdk/sun/security/ssl/SignatureScheme/SigAlgosExtTestWithTLS12.java +++ b/test/jdk/sun/security/ssl/SignatureScheme/SigAlgosExtTestWithTLS12.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (C) 2021, 2024, Tencent. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -56,6 +56,16 @@ import java.nio.ByteBuffer; import java.util.*; public class SigAlgosExtTestWithTLS12 extends SSLEngineTemplate { + /* + * Enables the JSSE system debugging system property: + * + * -Djavax.net.debug=ssl,handshake + * + * This gives a lot of low-level information about operations underway, + * including specific handshake messages, and might be best examined + * after gaining some familiarity with this application. + */ + private static final boolean debug = false; private static final boolean CLIENT_AUTH = Boolean.getBoolean("test.clientAuth"); @@ -114,7 +124,9 @@ public class SigAlgosExtTestWithTLS12 extends SSLEngineTemplate { } public static void main(String[] args) throws Exception { - System.setProperty("javax.net.debug", "ssl:handshake"); + if (debug) { + System.setProperty("javax.net.debug", "ssl,handshake"); + } try { new SigAlgosExtTestWithTLS12().run(); diff --git a/test/jdk/sun/security/ssl/SignatureScheme/SigSchemePropOrdering.java b/test/jdk/sun/security/ssl/SignatureScheme/SigSchemePropOrdering.java index b7719e6af19..4299c1cc049 100644 --- a/test/jdk/sun/security/ssl/SignatureScheme/SigSchemePropOrdering.java +++ b/test/jdk/sun/security/ssl/SignatureScheme/SigSchemePropOrdering.java @@ -38,6 +38,16 @@ import java.util.Arrays; import java.util.List; public class SigSchemePropOrdering extends AbstractCheckSignatureSchemes { + /* + * Enables the JSSE system debugging system property: + * + * -Djavax.net.debug=ssl:handshake + * + * This gives a lot of low-level information about operations underway, + * including specific handshake messages, and might be best examined + * after gaining some familiarity with this application. + */ + private static final boolean debug = false; private static final String SIG_SCHEME_STR = "rsa_pkcs1_sha256,rsa_pss_rsae_sha256,rsa_pss_pss_sha256," + @@ -48,7 +58,10 @@ public class SigSchemePropOrdering extends AbstractCheckSignatureSchemes { } public static void main(String[] args) throws Exception { - System.setProperty("javax.net.debug", "ssl:handshake"); + if (debug) { + System.setProperty("javax.net.debug", "ssl:handshake"); + } + System.setProperty("jdk.tls.client.SignatureSchemes", SIG_SCHEME_STR); System.setProperty("jdk.tls.server.SignatureSchemes", SIG_SCHEME_STR); new SigSchemePropOrdering().run(); diff --git a/test/jdk/sun/security/ssl/Stapling/StatusResponseManager.java b/test/jdk/sun/security/ssl/Stapling/StatusResponseManager.java index 57b16ed7862..6e78c6b4c73 100644 --- a/test/jdk/sun/security/ssl/Stapling/StatusResponseManager.java +++ b/test/jdk/sun/security/ssl/Stapling/StatusResponseManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, 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,7 +28,6 @@ * jdk.test.lib.security.CertificateBuilder * @bug 8046321 8339403 * @summary OCSP Stapling for TLS - * @run main/othervm -Djavax.net.debug=ssl:respmgr - * java.base/sun.security.ssl.StatusResponseManagerTests + * @run main/othervm java.base/sun.security.ssl.StatusResponseManagerTests */ diff --git a/test/jdk/sun/security/ssl/Stapling/java.base/sun/security/ssl/StatusResponseManagerTests.java b/test/jdk/sun/security/ssl/Stapling/java.base/sun/security/ssl/StatusResponseManagerTests.java index bcfc1290cf0..c7ecbe9f13c 100644 --- a/test/jdk/sun/security/ssl/Stapling/java.base/sun/security/ssl/StatusResponseManagerTests.java +++ b/test/jdk/sun/security/ssl/Stapling/java.base/sun/security/ssl/StatusResponseManagerTests.java @@ -47,7 +47,17 @@ import static sun.security.ssl.CertStatusExtension.*; */ public class StatusResponseManagerTests { - private static final boolean debug = true; + /* + * Enables the JSSE system debugging system property: + * + * -Djavax.net.debug=ssl:respmgr + * + * This gives a lot of low-level information about operations underway, + * including specific handshake messages, and might be best examined + * after gaining some familiarity with this application. + */ + private static final boolean debug = false; + private static final boolean ocspDebug = false; private static Field responseCacheField; @@ -72,6 +82,11 @@ public class StatusResponseManagerTests { static X509Certificate[] chain; public static void main(String[] args) throws Exception { + + if (debug) { + System.setProperty("javax.net.debug", "ssl:respmgr"); + } + responseCacheField = StatusResponseManager.class.getDeclaredField("responseCache"); responseCacheField.setAccessible(true); diff --git a/test/jdk/sun/security/ssl/TEST.properties b/test/jdk/sun/security/ssl/TEST.properties new file mode 100644 index 00000000000..741c2565067 --- /dev/null +++ b/test/jdk/sun/security/ssl/TEST.properties @@ -0,0 +1 @@ +maxOutputSize=500000 From 3f07710270dbe7268f21828dff20e2eb810b1e70 Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Tue, 16 Dec 2025 23:17:29 +0000 Subject: [PATCH 327/706] 8373441: Remove DCmdFactory::_enabled Reviewed-by: kevinw, fparain, jsjolen --- src/hotspot/share/jfr/dcmd/jfrDcmds.cpp | 14 +-- .../share/logging/logDiagnosticCommand.cpp | 2 +- .../share/services/diagnosticCommand.cpp | 111 +++++++++--------- .../share/services/diagnosticFramework.cpp | 7 +- .../share/services/diagnosticFramework.hpp | 31 ++--- src/hotspot/share/services/management.cpp | 6 +- .../management/DiagnosticCommandMBean.java | 4 +- 7 files changed, 77 insertions(+), 98 deletions(-) diff --git a/src/hotspot/share/jfr/dcmd/jfrDcmds.cpp b/src/hotspot/share/jfr/dcmd/jfrDcmds.cpp index d18136e1570..549d879de99 100644 --- a/src/hotspot/share/jfr/dcmd/jfrDcmds.cpp +++ b/src/hotspot/share/jfr/dcmd/jfrDcmds.cpp @@ -47,14 +47,14 @@ bool register_jfr_dcmds() { uint32_t full_export = DCmd_Source_Internal | DCmd_Source_AttachAPI | DCmd_Source_MBean; - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export)); // JFR.query Uncomment when developing new queries for the JFR.view command - // DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, true)); - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); + // DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, /*hidden=*/true)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export)); return true; } diff --git a/src/hotspot/share/logging/logDiagnosticCommand.cpp b/src/hotspot/share/logging/logDiagnosticCommand.cpp index adf596afc94..c9b1015ab45 100644 --- a/src/hotspot/share/logging/logDiagnosticCommand.cpp +++ b/src/hotspot/share/logging/logDiagnosticCommand.cpp @@ -46,7 +46,7 @@ LogDiagnosticCommand::LogDiagnosticCommand(outputStream* output, bool heap_alloc void LogDiagnosticCommand::registerCommand() { uint32_t full_visibility = DCmd_Source_Internal | DCmd_Source_AttachAPI | DCmd_Source_MBean; - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_visibility, true, false)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_visibility)); } void LogDiagnosticCommand::execute(DCmdSource source, TRAPS) { diff --git a/src/hotspot/share/services/diagnosticCommand.cpp b/src/hotspot/share/services/diagnosticCommand.cpp index 91b23904676..0ff7f445d24 100644 --- a/src/hotspot/share/services/diagnosticCommand.cpp +++ b/src/hotspot/share/services/diagnosticCommand.cpp @@ -98,78 +98,78 @@ void DCmd::register_dcmds(){ // Third argument specifies if the command is hidden uint32_t full_export = DCmd_Source_Internal | DCmd_Source_AttachAPI | DCmd_Source_MBean; - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export)); #if INCLUDE_SERVICES - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(DCmd_Source_Internal | DCmd_Source_AttachAPI, true, false)); - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(DCmd_Source_Internal | DCmd_Source_AttachAPI)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export)); #if INCLUDE_JVMTI // Both JVMTI and SERVICES have to be enabled to have this dcmd - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export)); #endif // INCLUDE_JVMTI #endif // INCLUDE_SERVICES #if INCLUDE_JVMTI - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export)); #endif // INCLUDE_JVMTI - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export)); #if INCLUDE_JVMTI - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export)); #endif // INCLUDE_JVMTI - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export)); #ifdef LINUX - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export)); #endif // LINUX #if defined(LINUX) || defined(_WIN64) || defined(__APPLE__) - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true,false)); - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true,false)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export)); #endif // LINUX or WINDOWS or MacOS - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export)); - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export)); // Enhanced JMX Agent Support // These commands not currently exported via the DiagnosticCommandMBean uint32_t jmx_agent_export_flags = DCmd_Source_Internal | DCmd_Source_AttachAPI; - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(jmx_agent_export_flags, true,false)); - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(jmx_agent_export_flags, true,false)); - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(jmx_agent_export_flags, true,false)); - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(jmx_agent_export_flags, true,false)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(jmx_agent_export_flags)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(jmx_agent_export_flags)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(jmx_agent_export_flags)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(jmx_agent_export_flags)); #if INCLUDE_CDS - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export)); #endif // INCLUDE_CDS - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export)); } HelpDCmd::HelpDCmd(outputStream* output, bool heap) : DCmdWithParser(output, heap), @@ -192,8 +192,7 @@ void HelpDCmd::execute(DCmdSource source, TRAPS) { for (int i = 0; i < cmd_list->length(); i++) { DCmdFactory* factory = DCmdFactory::factory(source, cmd_list->at(i), strlen(cmd_list->at(i))); - output()->print_cr("%s%s", factory->name(), - factory->is_enabled() ? "" : " [disabled]"); + output()->print_cr("%s", factory->name()); output()->print_cr("\t%s", factory->description()); output()->cr(); factory = factory->next(); @@ -203,8 +202,7 @@ void HelpDCmd::execute(DCmdSource source, TRAPS) { DCmdFactory* factory = DCmdFactory::factory(source, _cmd.value(), strlen(_cmd.value())); if (factory != nullptr) { - output()->print_cr("%s%s", factory->name(), - factory->is_enabled() ? "" : " [disabled]"); + output()->print_cr("%s", factory->name()); output()->print_cr("%s", factory->description()); output()->print_cr("\nImpact: %s", factory->impact()); output()->cr(); @@ -223,8 +221,7 @@ void HelpDCmd::execute(DCmdSource source, TRAPS) { for (int i = 0; i < cmd_list->length(); i++) { DCmdFactory* factory = DCmdFactory::factory(source, cmd_list->at(i), strlen(cmd_list->at(i))); - output()->print_cr("%s%s", factory->name(), - factory->is_enabled() ? "" : " [disabled]"); + output()->print_cr("%s", factory->name()); factory = factory->_next; } output()->print_cr("\nFor more information about a specific command use 'help '."); diff --git a/src/hotspot/share/services/diagnosticFramework.cpp b/src/hotspot/share/services/diagnosticFramework.cpp index c37fe7b4e1e..71cc461f161 100644 --- a/src/hotspot/share/services/diagnosticFramework.cpp +++ b/src/hotspot/share/services/diagnosticFramework.cpp @@ -563,10 +563,6 @@ DCmd* DCmdFactory::create_local_DCmd(DCmdSource source, CmdLine &line, outputStream* out, TRAPS) { DCmdFactory* f = factory(source, line.cmd_addr(), line.cmd_len()); if (f != nullptr) { - if (!f->is_enabled()) { - THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), - f->disabled_message()); - } return f->create_resource_instance(out); } THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), @@ -594,8 +590,7 @@ GrowableArray* DCmdFactory::DCmdInfo_list(DCmdSource source ) { if (!factory->is_hidden() && (factory->export_flags() & source)) { array->append(new DCmdInfo(factory->name(), factory->description(), factory->impact(), - factory->num_arguments(), - factory->is_enabled())); + factory->num_arguments())); } factory = factory->next(); } diff --git a/src/hotspot/share/services/diagnosticFramework.hpp b/src/hotspot/share/services/diagnosticFramework.hpp index 206b5ed27b4..5f9253b492e 100644 --- a/src/hotspot/share/services/diagnosticFramework.hpp +++ b/src/hotspot/share/services/diagnosticFramework.hpp @@ -117,21 +117,18 @@ protected: const char* const _description; /* Short description */ const char* const _impact; /* Impact on the JVM */ const int _num_arguments; /* Number of supported options or arguments */ - const bool _is_enabled; /* True if the diagnostic command can be invoked, false otherwise */ public: DCmdInfo(const char* name, const char* description, const char* impact, - int num_arguments, - bool enabled) + int num_arguments) : _name(name), _description(description), _impact(impact), - _num_arguments(num_arguments), _is_enabled(enabled) {} + _num_arguments(num_arguments) {} const char* name() const { return _name; } bool name_equals(const char* cmd_name) const; const char* description() const { return _description; } const char* impact() const { return _impact; } int num_arguments() const { return _num_arguments; } - bool is_enabled() const { return _is_enabled; } }; // A DCmdArgumentInfo instance provides a description of a diagnostic command @@ -233,8 +230,6 @@ public: // static const char* name() { return "";} // static const char* description() { return "";} - static const char* disabled_message() { return "Diagnostic command currently disabled"; } - // The impact() method returns a description of the intrusiveness of the diagnostic // command on the Java Virtual Machine behavior. The rational for this method is that some // diagnostic commands can seriously disrupt the behavior of the Java Virtual Machine @@ -337,8 +332,7 @@ public: }; // Diagnostic commands are not directly instantiated but created with a factory. -// Each diagnostic command class has its own factory. The DCmdFactory class also -// manages the status of the diagnostic command (hidden, enabled). A DCmdFactory +// Each diagnostic command class has its own factory. A DCmdFactory // has to be registered to make the diagnostic command available (see // management.cpp) class DCmdFactory: public CHeapObj { @@ -350,10 +344,6 @@ private: // Pointer to the next factory in the singly-linked list of registered // diagnostic commands DCmdFactory* _next; - // When disabled, a diagnostic command cannot be executed. Any attempt to - // execute it will result in the printing of the disabled message without - // instantiating the command. - const bool _enabled; // When hidden, a diagnostic command doesn't appear in the list of commands // provided by the 'help' command. const bool _hidden; @@ -361,10 +351,9 @@ private: const int _num_arguments; public: - DCmdFactory(int num_arguments, uint32_t flags, bool enabled, bool hidden) - : _next(nullptr), _enabled(enabled), _hidden(hidden), + DCmdFactory(int num_arguments, uint32_t flags, bool hidden) + : _next(nullptr), _hidden(hidden), _export_flags(flags), _num_arguments(num_arguments) {} - bool is_enabled() const { return _enabled; } bool is_hidden() const { return _hidden; } uint32_t export_flags() const { return _export_flags; } int num_arguments() const { return _num_arguments; } @@ -373,11 +362,8 @@ public: virtual const char* name() const = 0; virtual const char* description() const = 0; virtual const char* impact() const = 0; - virtual const char* disabled_message() const = 0; // Register a DCmdFactory to make a diagnostic command available. // Once registered, a diagnostic command must not be unregistered. - // To prevent a diagnostic command from being executed, just set the - // enabled flag to false. static int register_DCmdFactory(DCmdFactory* factory); static DCmdFactory* factory(DCmdSource source, const char* cmd, size_t len); // Returns a resourceArea allocated diagnostic command for the given command line @@ -401,8 +387,8 @@ private: // where this template is used to create and register factories. template class DCmdFactoryImpl : public DCmdFactory { public: - DCmdFactoryImpl(uint32_t flags, bool enabled, bool hidden) : - DCmdFactory(get_num_arguments(), flags, enabled, hidden) { } + DCmdFactoryImpl(uint32_t flags, bool hidden = false) : + DCmdFactory(get_num_arguments(), flags, hidden) { } // Returns a resourceArea allocated instance DCmd* create_resource_instance(outputStream* output) const { return new DCmdClass(output, false); @@ -416,9 +402,6 @@ public: const char* impact() const { return DCmdClass::impact(); } - const char* disabled_message() const { - return DCmdClass::disabled_message(); - } private: #ifdef ASSERT diff --git a/src/hotspot/share/services/management.cpp b/src/hotspot/share/services/management.cpp index cc26e2e1352..290e4839c96 100644 --- a/src/hotspot/share/services/management.cpp +++ b/src/hotspot/share/services/management.cpp @@ -2032,7 +2032,11 @@ JVM_ENTRY(void, jmm_GetDiagnosticCommandInfo(JNIEnv *env, jobjectArray cmds, infoArray[i].description = info->description(); infoArray[i].impact = info->impact(); infoArray[i].num_arguments = info->num_arguments(); - infoArray[i].enabled = info->is_enabled(); + + // All registered DCmds are always enabled. We set the dcmdInfo::enabled + // field to true to be compatible with the Java API + // com.sun.management.internal.DiagnosticCommandInfo. + infoArray[i].enabled = true; } JVM_END diff --git a/src/jdk.management/share/classes/com/sun/management/DiagnosticCommandMBean.java b/src/jdk.management/share/classes/com/sun/management/DiagnosticCommandMBean.java index d5fedf93855..994757f17c3 100644 --- a/src/jdk.management/share/classes/com/sun/management/DiagnosticCommandMBean.java +++ b/src/jdk.management/share/classes/com/sun/management/DiagnosticCommandMBean.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2025, 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 @@ -135,7 +135,7 @@ import javax.management.DynamicMBean; * * * dcmd.enabledboolean - * True if the diagnostic command is enabled, false otherwise + * This field is always true -- diagnostic commands cannot be disabled. * * * dcmd.argumentsDescriptor From e635330ae17fd2ce653ec75fd57fdd72d2512bba Mon Sep 17 00:00:00 2001 From: Anjian Wen Date: Wed, 17 Dec 2025 02:41:19 +0000 Subject: [PATCH 328/706] 8373069: RISC-V: implement GHASH intrinsic Reviewed-by: fjiang, fyang --- src/hotspot/cpu/riscv/assembler_riscv.hpp | 3 + src/hotspot/cpu/riscv/globals_riscv.hpp | 3 +- src/hotspot/cpu/riscv/stubGenerator_riscv.cpp | 71 +++++++++++++++++-- src/hotspot/cpu/riscv/vm_version_riscv.cpp | 16 +++++ src/hotspot/cpu/riscv/vm_version_riscv.hpp | 2 + .../os_cpu/linux_riscv/riscv_hwprobe.cpp | 3 + 6 files changed, 90 insertions(+), 8 deletions(-) diff --git a/src/hotspot/cpu/riscv/assembler_riscv.hpp b/src/hotspot/cpu/riscv/assembler_riscv.hpp index 711ae03bf27..b657c1f108d 100644 --- a/src/hotspot/cpu/riscv/assembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/assembler_riscv.hpp @@ -2662,6 +2662,9 @@ enum Nf { INSN(vsha2ch_vv, 0b1110111, 0b010, 0b1, 0b101110); INSN(vsha2cl_vv, 0b1110111, 0b010, 0b1, 0b101111); + // Vector GHASH (Zvkg) Extension + INSN(vghsh_vv, 0b1110111, 0b010, 0b1, 0b101100); + #undef INSN #define INSN(NAME, op, funct3, Vs1, funct6) \ diff --git a/src/hotspot/cpu/riscv/globals_riscv.hpp b/src/hotspot/cpu/riscv/globals_riscv.hpp index c78bfaa8ffd..390ed2daeb9 100644 --- a/src/hotspot/cpu/riscv/globals_riscv.hpp +++ b/src/hotspot/cpu/riscv/globals_riscv.hpp @@ -123,6 +123,7 @@ define_pd_global(intx, InlineSmallCode, 1000); product(bool, UseZvkn, false, EXPERIMENTAL, \ "Use Zvkn group extension, Zvkned, Zvknhb, Zvkb, Zvkt") \ product(bool, UseCtxFencei, false, EXPERIMENTAL, \ - "Use PR_RISCV_CTX_SW_FENCEI_ON to avoid explicit icache flush") + "Use PR_RISCV_CTX_SW_FENCEI_ON to avoid explicit icache flush") \ + product(bool, UseZvkg, false, EXPERIMENTAL, "Use Zvkg instructions") #endif // CPU_RISCV_GLOBALS_RISCV_HPP diff --git a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp index 49c80dce88a..75669d0e89c 100644 --- a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp +++ b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp @@ -2655,8 +2655,7 @@ class StubGenerator: public StubCodeGenerator { // x10 - input length // address generate_cipherBlockChaining_encryptAESCrypt() { - assert(UseAESIntrinsics, "Must be"); - assert(UseZvkn, "need AES instructions (Zvkned extension) support"); + assert(UseAESIntrinsics, "need AES instructions (Zvkned extension) support"); __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_cipherBlockChaining_encryptAESCrypt_id; StubCodeMark mark(this, stub_id); @@ -2745,8 +2744,7 @@ class StubGenerator: public StubCodeGenerator { // x10 - input length // address generate_cipherBlockChaining_decryptAESCrypt() { - assert(UseAESIntrinsics, "Must be"); - assert(UseZvkn, "need AES instructions (Zvkned extension) support"); + assert(UseAESIntrinsics, "need AES instructions (Zvkned extension) support"); __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_cipherBlockChaining_decryptAESCrypt_id; StubCodeMark mark(this, stub_id); @@ -2950,9 +2948,7 @@ class StubGenerator: public StubCodeGenerator { // x10 - input length // address generate_counterMode_AESCrypt() { - assert(UseAESCTRIntrinsics, "Must be"); - assert(UseZvkn, "need AES instructions (Zvkned extension) support"); - assert(UseZbb, "need basic bit manipulation (Zbb extension) support"); + assert(UseAESCTRIntrinsics, "need AES instructions (Zvkned extension) and Zbb extension support"); __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_counterMode_AESCrypt_id; @@ -3001,6 +2997,63 @@ class StubGenerator: public StubCodeGenerator { return start; } + /** + * Arguments: + * + * Input: + * c_rarg0 - current state address + * c_rarg1 - H key address + * c_rarg2 - data address + * c_rarg3 - number of blocks + * + * Output: + * Updated state at c_rarg0 + */ + address generate_ghash_processBlocks() { + assert(UseGHASHIntrinsics, "need GHASH instructions (Zvkg extension) and Zvbb support"); + + __ align(CodeEntryAlignment); + StubId stub_id = StubId::stubgen_ghash_processBlocks_id; + StubCodeMark mark(this, stub_id); + + address start = __ pc(); + __ enter(); + + Register state = c_rarg0; + Register subkeyH = c_rarg1; + Register data = c_rarg2; + Register blocks = c_rarg3; + + VectorRegister partial_hash = v1; + VectorRegister hash_subkey = v2; + VectorRegister cipher_text = v3; + + const unsigned int BLOCK_SIZE = 16; + + __ vsetivli(x0, 2, Assembler::e64, Assembler::m1); + __ vle64_v(hash_subkey, subkeyH); + __ vrev8_v(hash_subkey, hash_subkey); + __ vle64_v(partial_hash, state); + __ vrev8_v(partial_hash, partial_hash); + + __ vsetivli(x0, 4, Assembler::e32, Assembler::m1); + Label L_ghash_loop; + __ bind(L_ghash_loop); + __ vle32_v(cipher_text, data); + __ addi(data, data, BLOCK_SIZE); + __ vghsh_vv(partial_hash, hash_subkey, cipher_text); + __ subi(blocks, blocks, 1); + __ bnez(blocks, L_ghash_loop); + + __ vsetivli(x0, 2, Assembler::e64, Assembler::m1); + __ vrev8_v(partial_hash, partial_hash); + __ vse64_v(partial_hash, state); + __ leave(); + __ ret(); + + return start; + } + // code for comparing 8 characters of strings with Latin1 and Utf16 encoding void compare_string_8_x_LU(Register tmpL, Register tmpU, Register strL, Register strU, Label& DIFF) { @@ -7227,6 +7280,10 @@ static const int64_t right_3_bits = right_n_bits(3); StubRoutines::_counterMode_AESCrypt = generate_counterMode_AESCrypt(); } + if (UseGHASHIntrinsics) { + StubRoutines::_ghash_processBlocks = generate_ghash_processBlocks(); + } + if (UsePoly1305Intrinsics) { StubRoutines::_poly1305_processBlocks = generate_poly1305_processBlocks(); } diff --git a/src/hotspot/cpu/riscv/vm_version_riscv.cpp b/src/hotspot/cpu/riscv/vm_version_riscv.cpp index 75605f25759..22f19c4f5ea 100644 --- a/src/hotspot/cpu/riscv/vm_version_riscv.cpp +++ b/src/hotspot/cpu/riscv/vm_version_riscv.cpp @@ -457,6 +457,22 @@ void VM_Version::c2_initialize() { FLAG_SET_DEFAULT(UseAESCTRIntrinsics, false); } } + + if (UseZvkg) { + if (FLAG_IS_DEFAULT(UseGHASHIntrinsics) && UseZvbb) { + FLAG_SET_DEFAULT(UseGHASHIntrinsics, true); + } + + if (UseGHASHIntrinsics && !UseZvbb) { + warning("Cannot enable UseGHASHIntrinsics on cpu without UseZvbb support"); + FLAG_SET_DEFAULT(UseGHASHIntrinsics, false); + } + } else { + if (UseGHASHIntrinsics) { + warning("Cannot enable UseGHASHIntrinsics on cpu without UseZvkg support"); + FLAG_SET_DEFAULT(UseGHASHIntrinsics, false); + } + } } #endif // COMPILER2 diff --git a/src/hotspot/cpu/riscv/vm_version_riscv.hpp b/src/hotspot/cpu/riscv/vm_version_riscv.hpp index 168a3a576d0..03c843efc69 100644 --- a/src/hotspot/cpu/riscv/vm_version_riscv.hpp +++ b/src/hotspot/cpu/riscv/vm_version_riscv.hpp @@ -289,6 +289,8 @@ class VM_Version : public Abstract_VM_Version { decl(Zvfh , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT_DEP(UseZvfh, &ext_v, &ext_Zfh, nullptr)) \ /* Shorthand for Zvkned + Zvknhb + Zvkb + Zvkt */ \ decl(Zvkn , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT_DEP(UseZvkn, &ext_v, nullptr)) \ + /* Zvkg crypto extension for ghash and gcm */ \ + decl(Zvkg , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT_DEP(UseZvkg, &ext_v, nullptr)) \ #define DECLARE_RV_EXT_FEATURE(PRETTY, LINUX_BIT, FSTRING, FLAGF) \ struct ext_##PRETTY##RVExtFeatureValue : public RVExtFeatureValue { \ diff --git a/src/hotspot/os_cpu/linux_riscv/riscv_hwprobe.cpp b/src/hotspot/os_cpu/linux_riscv/riscv_hwprobe.cpp index ec756c44fe6..253f460dca3 100644 --- a/src/hotspot/os_cpu/linux_riscv/riscv_hwprobe.cpp +++ b/src/hotspot/os_cpu/linux_riscv/riscv_hwprobe.cpp @@ -256,6 +256,9 @@ void RiscvHwprobe::add_features_from_query_result() { is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_EXT_ZVKT)) { VM_Version::ext_Zvkn.enable_feature(); } + if (is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_EXT_ZVKG)) { + VM_Version::ext_Zvkg.enable_feature(); + } #endif // ====== non-extensions ====== From e9b4696acc966d96d42880e840c8fe27434e4e1b Mon Sep 17 00:00:00 2001 From: Christian Stein Date: Wed, 17 Dec 2025 07:18:26 +0000 Subject: [PATCH 329/706] 8373097: Save command should create missing parent directories Reviewed-by: jlahoda --- .../jdk/internal/jshell/tool/JShellTool.java | 14 +++++++++++++- test/langtools/jdk/jshell/ToolBasicTest.java | 5 ++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java b/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java index 795321253fd..9a030f7e46b 100644 --- a/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java +++ b/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java @@ -3362,7 +3362,19 @@ public class JShellTool implements MessageHandler { // error occurred, already reported return false; } - try (BufferedWriter writer = Files.newBufferedWriter(toPathResolvingUserHome(filename), + // Create missing parent directories before writing to target file + Path target; + try { + target = toPathResolvingUserHome(filename); + Path parent = target.getParent(); + if (parent != null) { + Files.createDirectories(parent); + } + } catch (Exception e) { + errormsg("jshell.err.file.exception", "/save", filename, e); + return false; + } + try (BufferedWriter writer = Files.newBufferedWriter(target, Charset.defaultCharset(), CREATE, TRUNCATE_EXISTING, WRITE)) { if (at.hasOption("-history")) { diff --git a/test/langtools/jdk/jshell/ToolBasicTest.java b/test/langtools/jdk/jshell/ToolBasicTest.java index 5015d1f64b1..7fba0a9cd44 100644 --- a/test/langtools/jdk/jshell/ToolBasicTest.java +++ b/test/langtools/jdk/jshell/ToolBasicTest.java @@ -585,6 +585,7 @@ public class ToolBasicTest extends ReplToolTesting { Compiler compiler = new Compiler(); Path path = compiler.getPath("testSave.repl"); { + Path pathWithDirectories = compiler.getPath("what/ever/testSave.repl"); List list = Arrays.asList( "int a;", "class A { public String toString() { return \"A\"; } }" @@ -593,9 +594,11 @@ public class ToolBasicTest extends ReplToolTesting { (a) -> assertVariable(a, "int", "a"), (a) -> assertCommand(a, "()", null, null, null, "", ""), (a) -> assertClass(a, "class A { public String toString() { return \"A\"; } }", "class", "A"), - (a) -> assertCommand(a, "/save " + path.toString(), "") + (a) -> assertCommand(a, "/save " + path.toString(), ""), + (a) -> assertCommand(a, "/save " + pathWithDirectories.toString(), "") ); assertEquals(list, Files.readAllLines(path)); + assertEquals(list, Files.readAllLines(pathWithDirectories)); } { List output = new ArrayList<>(); From 94c51ce314eea7a4f188fa0db1bae0e3f3dbd230 Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Wed, 17 Dec 2025 07:22:37 +0000 Subject: [PATCH 330/706] 8372635: Lambdas do not copy over SYNTHETIC flag for local variables Reviewed-by: vromero, liach --- .../sun/tools/javac/comp/LambdaToMethod.java | 5 +- .../javac/patterns/SyntheticVariables.java | 138 ++++++++++++++++++ 2 files changed, 141 insertions(+), 2 deletions(-) create mode 100644 test/langtools/tools/javac/patterns/SyntheticVariables.java diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java index b13c9e0fe2b..22cb796870b 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java @@ -1152,7 +1152,7 @@ public class LambdaToMethod extends TreeTranslator { propagateAnnos = false; break; case LOCAL_VAR: - ret = new VarSymbol(sym.flags() & FINAL, sym.name, sym.type, translatedSym); + ret = new VarSymbol(sym.flags(), sym.name, sym.type, translatedSym); ret.pos = sym.pos; // If sym.data == ElementKind.EXCEPTION_PARAMETER, // set ret.data = ElementKind.EXCEPTION_PARAMETER too. @@ -1164,7 +1164,8 @@ public class LambdaToMethod extends TreeTranslator { } break; case PARAM: - ret = new VarSymbol((sym.flags() & FINAL) | PARAMETER, sym.name, types.erasure(sym.type), translatedSym); + Assert.check((sym.flags() & PARAMETER) != 0); + ret = new VarSymbol(sym.flags(), sym.name, types.erasure(sym.type), translatedSym); ret.pos = sym.pos; break; default: diff --git a/test/langtools/tools/javac/patterns/SyntheticVariables.java b/test/langtools/tools/javac/patterns/SyntheticVariables.java new file mode 100644 index 00000000000..26ece40d656 --- /dev/null +++ b/test/langtools/tools/javac/patterns/SyntheticVariables.java @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2025, 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 8372635 + * @enablePreview + * @summary Verify temporary variables created for pattern matching are + * marked as synthetic. + * @compile -g SyntheticVariables.java + * @run main SyntheticVariables + */ + +import java.io.IOException; +import java.io.InputStream; +import java.lang.classfile.Attributes; +import java.lang.classfile.ClassFile; +import java.lang.classfile.ClassModel; +import java.lang.classfile.MethodModel; +import java.lang.classfile.attribute.CodeAttribute; +import java.lang.classfile.attribute.LocalVariableTableAttribute; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; + +public class SyntheticVariables { + + public static void main(String[] args) throws IOException { + try (InputStream in = Test.class.getClassLoader().getResource(Test.class.getName().replace('.', '/') + ".class").openStream()) { + ClassModel model = ClassFile.of().parse(in.readAllBytes()); + Map name2Method = model.methods().stream().collect(Collectors.toMap(m -> m.methodName().stringValue(), m -> m)); + assertEquals(Set.of("str", "b", "b2", "this", "l", "o"), localVars(name2Method.get("testInMethod"))); + assertEquals(Set.of("str", "b", "b2", "l", "o"), localVars(name2Method.get("lambda$testInLambda$0"))); + } + } + + private static Set localVars(MethodModel method) { + CodeAttribute code = method.findAttribute(Attributes.code()).orElseThrow(); + LocalVariableTableAttribute lvt = code.findAttribute(Attributes.localVariableTable()).orElseThrow(); + return lvt.localVariables() + .stream() + .map(info -> info.name().stringValue()) + .collect(Collectors.toSet()); + } + + private static void assertEquals(Set expected, Set actual) { + if (!Objects.equals(expected, actual)) { + throw new AssertionError("Unexpected value, expected: " + expected + + ", got: " + actual); + } + } + + public record Test(Object o) { + private void testInMethod() { + Object o = create(); + + //synthetic variable for the instanceof's expression + boolean b = o.toString() instanceof String str && str.isEmpty(); + + System.err.println(b); + + //synthetic variable for the switch's selector and index: + switch (create()) { + //synthetic variable for the nested component values, + //and for the synthetic catch over the getters + case Test(Test(String str)) when str.isEmpty() -> System.err.println(1); + case Test(Test(String str)) -> System.err.println(2); + default -> System.err.println(2); + } + + List l = List.of(0); + + //synthetic variable for case where the static and dynamic types + //don't match for primitive patterns: + boolean b2 = l.get(0) instanceof int; + + System.err.println(b2); + } + + private void testInLambda() { + Object o = create(); + Runnable r = () -> { + + //synthetic variable for the instanceof's expression + boolean b = o.toString() instanceof String str && str.isEmpty(); + + System.err.println(b); + + //synthetic variable for the switch's selector and index: + switch (create()) { + //synthetic variable for the nested component values, + //and for the synthetic catch over the getters + case Test(Test(String str)) when str.isEmpty() -> System.err.println(1); + case Test(Test(String str)) -> System.err.println(2); + default -> System.err.println(2); + } + + List l = List.of(0); + + //synthetic variable for case where the static and dynamic types + //don't match for primitive patterns: + boolean b2 = l.get(0) instanceof int; + + System.err.println(b2); + }; + } + private static String val = "v"; + public static Test create() { + try { + return new Test(new Test(val)); + } finally { + val += val; + } + } + } +} From 386ad61458a3901622b92ca56982d728c11b846a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Jeli=C5=84ski?= Date: Wed, 17 Dec 2025 07:49:58 +0000 Subject: [PATCH 331/706] 8373409: java/net/httpclient/http3/H3ErrorHandlingTest.java failed due to deadlock Reviewed-by: dfuchs --- .../internal/net/http/quic/QuicEndpoint.java | 66 +++++++++---------- .../httpclient/http3/H3ErrorHandlingTest.java | 1 + 2 files changed, 31 insertions(+), 36 deletions(-) diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicEndpoint.java b/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicEndpoint.java index b1de5ef4bfd..8bdba21594c 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicEndpoint.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicEndpoint.java @@ -1581,34 +1581,30 @@ public abstract sealed class QuicEndpoint implements AutoCloseable peerIssuedResetTokens.replaceAll((tok, c) -> c == from ? to : c); } - public void draining(final QuicPacketReceiver connection) { + public void draining(final QuicConnectionImpl connection) { // remap the connection to a DrainingConnection if (closed) return; + + final long idleTimeout = connection.peerPtoMs() * 3; // 3 PTO + connection.localConnectionIdManager().close(); + DrainingConnection draining = new DrainingConnection(connection.connectionIds(), idleTimeout); + // we can ignore stateless reset in the draining state. + remapPeerIssuedResetToken(connection, draining); + connection.connectionIds().forEach((id) -> - connections.compute(id, this::remapDraining)); + connections.compute(id, (i, r) -> remapDraining(i, r, draining))); + draining.startTimer(); assert !connections.containsValue(connection) : connection; } - private DrainingConnection remapDraining(QuicConnectionId id, QuicPacketReceiver conn) { + private DrainingConnection remapDraining(QuicConnectionId id, QuicPacketReceiver conn, DrainingConnection draining) { if (closed) return null; var debugOn = debug.on() && !Thread.currentThread().isVirtual(); - if (conn instanceof ClosingConnection closing) { + if (conn instanceof QuicConnectionImpl || conn instanceof ClosingConnection) { if (debugOn) debug.log("remapping %s to DrainingConnection", id); - final var draining = closing.toDraining(); - remapPeerIssuedResetToken(closing, draining); - draining.startTimer(); - return draining; - } else if (conn instanceof DrainingConnection draining) { - return draining; - } else if (conn instanceof QuicConnectionImpl impl) { - final long idleTimeout = impl.peerPtoMs() * 3; // 3 PTO - impl.localConnectionIdManager().close(); - if (debugOn) debug.log("remapping %s to DrainingConnection", id); - var draining = new DrainingConnection(conn.connectionIds(), idleTimeout); - // we can ignore stateless reset in the draining state. - remapPeerIssuedResetToken(impl, draining); - draining.startTimer(); return draining; + } else if (conn instanceof DrainingConnection d) { + return d; } else if (conn == null) { // connection absent (was probably removed), don't remap to draining if (debugOn) { @@ -1623,30 +1619,32 @@ public abstract sealed class QuicEndpoint implements AutoCloseable protected void closing(QuicConnectionImpl connection, ByteBuffer datagram) { if (closed) return; - ByteBuffer closing = ByteBuffer.allocate(datagram.limit()); - closing.put(datagram.slice()); - closing.flip(); + ByteBuffer closingDatagram = ByteBuffer.allocate(datagram.limit()); + closingDatagram.put(datagram.slice()); + closingDatagram.flip(); + + final long idleTimeout = connection.peerPtoMs() * 3; // 3 PTO + connection.localConnectionIdManager().close(); + var closingConnection = new ClosingConnection(connection.connectionIds(), idleTimeout, datagram); + remapPeerIssuedResetToken(connection, closingConnection); + connection.connectionIds().forEach((id) -> - connections.compute(id, (i, r) -> remapClosing(i, r, closing))); + connections.compute(id, (i, r) -> remapClosing(i, r, closingConnection))); + closingConnection.startTimer(); assert !connections.containsValue(connection) : connection; } - private ClosedConnection remapClosing(QuicConnectionId id, QuicPacketReceiver conn, ByteBuffer datagram) { + private ClosedConnection remapClosing(QuicConnectionId id, QuicPacketReceiver conn, ClosingConnection closingConnection) { if (closed) return null; var debugOn = debug.on() && !Thread.currentThread().isVirtual(); - if (conn instanceof ClosingConnection closing) { + if (conn instanceof QuicConnectionImpl) { + if (debugOn) debug.log("remapping %s to ClosingConnection", id); + return closingConnection; + } else if (conn instanceof ClosingConnection closing) { // we already have a closing datagram, drop the new one return closing; } else if (conn instanceof DrainingConnection draining) { return draining; - } else if (conn instanceof QuicConnectionImpl impl) { - final long idleTimeout = impl.peerPtoMs() * 3; // 3 PTO - impl.localConnectionIdManager().close(); - if (debugOn) debug.log("remapping %s to ClosingConnection", id); - var closing = new ClosingConnection(conn.connectionIds(), idleTimeout, datagram); - remapPeerIssuedResetToken(impl, closing); - closing.startTimer(); - return closing; } else if (conn == null) { // connection absent (was probably removed), don't remap to closing if (debugOn) { @@ -1896,10 +1894,6 @@ public abstract sealed class QuicEndpoint implements AutoCloseable debug.log("ClosingConnection(%s): dropping %s packet", localConnectionIds, headersType); } } - - private DrainingConnection toDraining() { - return new DrainingConnection(localConnectionIds, maxIdleTimeMs); - } } /** diff --git a/test/jdk/java/net/httpclient/http3/H3ErrorHandlingTest.java b/test/jdk/java/net/httpclient/http3/H3ErrorHandlingTest.java index 4315fd36de5..bb5aeacbb0c 100644 --- a/test/jdk/java/net/httpclient/http3/H3ErrorHandlingTest.java +++ b/test/jdk/java/net/httpclient/http3/H3ErrorHandlingTest.java @@ -71,6 +71,7 @@ import static org.testng.Assert.*; /* * @test + * @bug 8373409 * @key intermittent * @comment testResetControlStream may fail if the client doesn't read the stream type * before the stream is reset, From 9e2008bf5e9a63b640eefc6cc7ec5c4f344c4266 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Wed, 17 Dec 2025 08:44:46 +0000 Subject: [PATCH 332/706] 8373676: Test javax/net/ssl/HttpsURLConnection/SubjectAltNameIP.java fails on a machine without IPV6 Reviewed-by: jpai, dfuchs --- .../net/ssl/HttpsURLConnection/SubjectAltNameIP.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/test/jdk/javax/net/ssl/HttpsURLConnection/SubjectAltNameIP.java b/test/jdk/javax/net/ssl/HttpsURLConnection/SubjectAltNameIP.java index 2def2f69d6e..cbd2089e7bd 100644 --- a/test/jdk/javax/net/ssl/HttpsURLConnection/SubjectAltNameIP.java +++ b/test/jdk/javax/net/ssl/HttpsURLConnection/SubjectAltNameIP.java @@ -30,7 +30,7 @@ * @modules java.base/sun.net.util * @comment Insert -Djavax.net.debug=all into the following lines to enable SSL debugging * @run main/othervm SubjectAltNameIP 127.0.0.1 - * @run main/othervm SubjectAltNameIP [::1] + * @run main/othervm SubjectAltNameIP ::1 */ import javax.net.ssl.HandshakeCompletedListener; @@ -166,14 +166,19 @@ public class SubjectAltNameIP { } public static void main(String[] args) throws Exception { + boolean isIpv6Addr = IPAddressUtil.isIPv6LiteralAddress(args[0]); - if (IPAddressUtil.isIPv6LiteralAddress(args[0]) && !IPSupport.hasIPv6()) { + if (isIpv6Addr && !IPSupport.hasIPv6()) { throw new SkippedException("Skipping test - IPv6 is not supported"); } /* * Start the tests. */ - new SubjectAltNameIP(args[0]); + if (isIpv6Addr) { // use the URL notion wrapper + new SubjectAltNameIP("[" + args[0] + "]"); + } else { + new SubjectAltNameIP(args[0]); + } } Thread serverThread = null; From 4924b29fa519996b806ac0f4a7c898085f44bc4c Mon Sep 17 00:00:00 2001 From: Michael McMahon Date: Wed, 17 Dec 2025 08:54:56 +0000 Subject: [PATCH 333/706] 8370655: Check EINTR handling InetAddress implementation and NET_ThrowNew Reviewed-by: alanb --- src/java.base/share/native/libnet/net_util.c | 1 - .../unix/native/libnet/Inet4AddressImpl.c | 34 ++++++++++++------- .../unix/native/libnet/Inet6AddressImpl.c | 32 +++++++++++------ .../unix/native/libnet/net_util_md.c | 15 ++++---- .../unix/native/libnet/net_util_md.h | 13 +++++++ 5 files changed, 62 insertions(+), 33 deletions(-) diff --git a/src/java.base/share/native/libnet/net_util.c b/src/java.base/share/native/libnet/net_util.c index 5b356d04b3c..7b148f03cfd 100644 --- a/src/java.base/share/native/libnet/net_util.c +++ b/src/java.base/share/native/libnet/net_util.c @@ -86,7 +86,6 @@ DEF_JNI_OnLoad(JavaVM *vm, void *reserved) /* check if SO_REUSEPORT is supported on this platform */ REUSEPORT_available = reuseport_supported(IPv6_available); - return JNI_VERSION_1_2; } diff --git a/src/java.base/unix/native/libnet/Inet4AddressImpl.c b/src/java.base/unix/native/libnet/Inet4AddressImpl.c index fff524e03ae..f537226c330 100644 --- a/src/java.base/unix/native/libnet/Inet4AddressImpl.c +++ b/src/java.base/unix/native/libnet/Inet4AddressImpl.c @@ -108,7 +108,8 @@ Java_java_net_Inet4AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this, hints.ai_flags = AI_CANONNAME; hints.ai_family = AF_INET; - error = getaddrinfo(hostname, NULL, &hints, &res); + NET_RESTARTABLE(error, getaddrinfo(hostname, NULL, &hints, &res), + error == EAI_SYSTEM && errno == EINTR); if (error) { #if defined(MACOSX) @@ -229,17 +230,21 @@ Java_java_net_Inet4AddressImpl_getHostByAddr(JNIEnv *env, jobject this, sa.sin_addr.s_addr = htonl(addr); sa.sin_family = AF_INET; - if (getnameinfo((struct sockaddr *)&sa, sizeof(struct sockaddr_in), - host, sizeof(host), NULL, 0, NI_NAMEREQD)) { - JNU_ThrowByName(env, "java/net/UnknownHostException", NULL); - } else { + int r; + + NET_RESTARTABLE(r, getnameinfo((struct sockaddr *)&sa, sizeof(struct sockaddr_in), + host, sizeof(host), NULL, 0, NI_NAMEREQD), + r == EAI_SYSTEM && errno == EINTR); + + if (r == 0) { ret = (*env)->NewStringUTF(env, host); - if (ret == NULL) { - JNU_ThrowByName(env, "java/net/UnknownHostException", NULL); + if (ret != NULL) { + return ret; } } - return ret; + JNU_ThrowByName(env, "java/net/UnknownHostException", NULL); + return NULL; } /** @@ -283,7 +288,8 @@ tcp_ping4(JNIEnv *env, SOCKETADDRESS *sa, SOCKETADDRESS *netif, jint timeout, SET_NONBLOCKING(fd); sa->sa4.sin_port = htons(7); // echo port - connect_rv = connect(fd, &sa->sa, sizeof(struct sockaddr_in)); + NET_RESTARTABLE(connect_rv, connect(fd, &sa->sa, sizeof(struct sockaddr_in)), + connect_rv == -1 && errno == EINTR); // connection established or refused immediately, either way it means // we were able to reach the host! @@ -397,8 +403,11 @@ ping4(JNIEnv *env, jint fd, SOCKETADDRESS *sa, SOCKETADDRESS *netif, icmp->icmp_cksum = 0; // manually calculate checksum icmp->icmp_cksum = in_cksum((u_short *)icmp, plen); + // send it - n = sendto(fd, sendbuf, plen, 0, &sa->sa, sizeof(struct sockaddr_in)); + NET_RESTARTABLE(n, sendto(fd, sendbuf, plen, 0, &sa->sa, sizeof(struct sockaddr_in)), + n == -1 && errno == EINTR) + if (n < 0 && errno != EINPROGRESS) { #if defined(__linux__) /* @@ -422,8 +431,9 @@ ping4(JNIEnv *env, jint fd, SOCKETADDRESS *sa, SOCKETADDRESS *netif, tmout2 = NET_Wait(env, fd, NET_WAIT_READ, tmout2); if (tmout2 >= 0) { len = sizeof(sa_recv); - n = recvfrom(fd, recvbuf, sizeof(recvbuf), 0, - (struct sockaddr *)&sa_recv, &len); + NET_RESTARTABLE(n, recvfrom(fd, recvbuf, sizeof(recvbuf), 0, + (struct sockaddr *)&sa_recv, &len), + n == -1 && errno == EINTR); // check if we received enough data if (n < (jint)sizeof(struct ip)) { continue; diff --git a/src/java.base/unix/native/libnet/Inet6AddressImpl.c b/src/java.base/unix/native/libnet/Inet6AddressImpl.c index 83354356936..8dce4f9cc6b 100644 --- a/src/java.base/unix/native/libnet/Inet6AddressImpl.c +++ b/src/java.base/unix/native/libnet/Inet6AddressImpl.c @@ -227,7 +227,8 @@ Java_java_net_Inet6AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this, hints.ai_flags = AI_CANONNAME; hints.ai_family = lookupCharacteristicsToAddressFamily(characteristics); - error = getaddrinfo(hostname, NULL, &hints, &res); + NET_RESTARTABLE(error, getaddrinfo(hostname, NULL, &hints, &res), + error == EAI_SYSTEM && errno == EINTR); if (error) { #if defined(MACOSX) @@ -430,16 +431,20 @@ Java_java_net_Inet6AddressImpl_getHostByAddr(JNIEnv *env, jobject this, len = sizeof(struct sockaddr_in6); } - if (getnameinfo(&sa.sa, len, host, sizeof(host), NULL, 0, NI_NAMEREQD)) { - JNU_ThrowByName(env, "java/net/UnknownHostException", NULL); - } else { + int r; + + NET_RESTARTABLE(r, getnameinfo(&sa.sa, len, host, sizeof(host), NULL, 0, NI_NAMEREQD), + r == EAI_SYSTEM && errno == EINTR); + + if (r == 0) { ret = (*env)->NewStringUTF(env, host); - if (ret == NULL) { - JNU_ThrowByName(env, "java/net/UnknownHostException", NULL); + if (ret != NULL) { + return ret; } } - return ret; + JNU_ThrowByName(env, "java/net/UnknownHostException", NULL); + return NULL; } /** @@ -483,7 +488,8 @@ tcp_ping6(JNIEnv *env, SOCKETADDRESS *sa, SOCKETADDRESS *netif, jint timeout, SET_NONBLOCKING(fd); sa->sa6.sin6_port = htons(7); // echo port - connect_rv = connect(fd, &sa->sa, sizeof(struct sockaddr_in6)); + NET_RESTARTABLE(connect_rv, connect(fd, &sa->sa, sizeof(struct sockaddr_in6)), + connect_rv == -1 && errno == EINTR); // connection established or refused immediately, either way it means // we were able to reach the host! @@ -604,7 +610,10 @@ ping6(JNIEnv *env, jint fd, SOCKETADDRESS *sa, SOCKETADDRESS *netif, memcpy(sendbuf + sizeof(struct icmp6_hdr), &tv, sizeof(tv)); icmp6->icmp6_cksum = 0; // send it - n = sendto(fd, sendbuf, plen, 0, &sa->sa, sizeof(struct sockaddr_in6)); + + NET_RESTARTABLE(n, sendto(fd, sendbuf, plen, 0, &sa->sa, sizeof(struct sockaddr_in6)), + n == -1 && errno == EINTR); + if (n < 0 && errno != EINPROGRESS) { #if defined(__linux__) /* @@ -628,8 +637,9 @@ ping6(JNIEnv *env, jint fd, SOCKETADDRESS *sa, SOCKETADDRESS *netif, tmout2 = NET_Wait(env, fd, NET_WAIT_READ, tmout2); if (tmout2 >= 0) { len = sizeof(sa_recv); - n = recvfrom(fd, recvbuf, sizeof(recvbuf), 0, - (struct sockaddr *)&sa_recv, &len); + NET_RESTARTABLE(n, recvfrom(fd, recvbuf, sizeof(recvbuf), 0, + (struct sockaddr *)&sa_recv, &len), + n == -1 && errno == EINTR); // check if we received enough data if (n < (jint)sizeof(struct icmp6_hdr)) { continue; diff --git a/src/java.base/unix/native/libnet/net_util_md.c b/src/java.base/unix/native/libnet/net_util_md.c index 9bb6a026961..b0915615d96 100644 --- a/src/java.base/unix/native/libnet/net_util_md.c +++ b/src/java.base/unix/native/libnet/net_util_md.c @@ -76,9 +76,6 @@ NET_ThrowNew(JNIEnv *env, int errorNumber, char *msg) { jio_snprintf(fullMsg, sizeof(fullMsg), "socket closed: %s", msg); JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", fullMsg); break; - case EINTR: - JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException", msg); - break; default: errno = errorNumber; JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", msg); @@ -627,11 +624,11 @@ NET_Wait(JNIEnv *env, jint fd, jint flags, jint timeout) pfd.fd = fd; pfd.events = 0; if (flags & NET_WAIT_READ) - pfd.events |= POLLIN; + pfd.events |= POLLIN; if (flags & NET_WAIT_WRITE) - pfd.events |= POLLOUT; + pfd.events |= POLLOUT; if (flags & NET_WAIT_CONNECT) - pfd.events |= POLLOUT; + pfd.events |= POLLOUT; errno = 0; read_rv = poll(&pfd, 1, nanoTimeout / NET_NSEC_PER_MSEC); @@ -639,13 +636,13 @@ NET_Wait(JNIEnv *env, jint fd, jint flags, jint timeout) newNanoTime = JVM_NanoTime(env, 0); nanoTimeout -= (newNanoTime - prevNanoTime); if (nanoTimeout < NET_NSEC_PER_MSEC) { - return read_rv > 0 ? 0 : -1; + return read_rv > 0 ? 0 : -1; } prevNanoTime = newNanoTime; if (read_rv > 0) { - break; + break; } - } /* while */ + } /* while */ return (nanoTimeout / NET_NSEC_PER_MSEC); } diff --git a/src/java.base/unix/native/libnet/net_util_md.h b/src/java.base/unix/native/libnet/net_util_md.h index 902cf96732f..d6cb3250bbe 100644 --- a/src/java.base/unix/native/libnet/net_util_md.h +++ b/src/java.base/unix/native/libnet/net_util_md.h @@ -80,4 +80,17 @@ void NET_ThrowUnknownHostExceptionWithGaiError(JNIEnv *env, void NET_ThrowByNameWithLastError(JNIEnv *env, const char *name, const char *defaultDetail); +/** + * Invokes CALL in a loop, setting RET to return value. + * Invokes PREDICATE for condition to restart CALL (in loop) + * Return RET otherwise + */ +#define NET_RESTARTABLE(RET,CALL,PREDICATE) \ + while (1) { \ + RET = CALL; \ + if (!(PREDICATE)) { \ + break; \ + } \ + } + #endif /* NET_UTILS_MD_H */ From af18fbd42d2a437dd35f33e557a8906ca0c3bd07 Mon Sep 17 00:00:00 2001 From: Arno Zeller Date: Wed, 17 Dec 2025 09:08:29 +0000 Subject: [PATCH 334/706] 8371559: Intermittent timeouts in test javax/net/ssl/Stapling/HttpsUrlConnClient.java Reviewed-by: mbaesken, myankelevich --- .../net/ssl/Stapling/HttpsUrlConnClient.java | 86 +++++++++++-------- 1 file changed, 48 insertions(+), 38 deletions(-) diff --git a/test/jdk/javax/net/ssl/Stapling/HttpsUrlConnClient.java b/test/jdk/javax/net/ssl/Stapling/HttpsUrlConnClient.java index b9829621d68..c34311f1689 100644 --- a/test/jdk/javax/net/ssl/Stapling/HttpsUrlConnClient.java +++ b/test/jdk/javax/net/ssl/Stapling/HttpsUrlConnClient.java @@ -33,7 +33,11 @@ * @run main/othervm HttpsUrlConnClient RSASSA-PSS RSASSA-PSS */ -import java.io.*; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; import java.math.BigInteger; import java.security.KeyPair; import java.security.KeyPairGenerator; @@ -41,7 +45,9 @@ import java.net.Socket; import java.net.URL; import java.net.HttpURLConnection; import java.net.InetAddress; + import javax.net.ssl.*; + import java.security.KeyStore; import java.security.PublicKey; import java.security.Security; @@ -55,7 +61,16 @@ import java.security.cert.X509Certificate; import java.security.cert.PKIXRevocationChecker; import java.security.spec.PKCS8EncodedKeySpec; import java.text.SimpleDateFormat; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Base64; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.TimeZone; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import jdk.test.lib.security.SimpleOCSPServer; @@ -92,10 +107,6 @@ public class HttpsUrlConnClient { static String INT_ALIAS = "intermediate"; static String SSL_ALIAS = "ssl"; - /* - * Is the server ready to serve? - */ - volatile static boolean serverReady = false; volatile int serverPort = 0; volatile Exception serverException = null; @@ -164,7 +175,7 @@ public class HttpsUrlConnClient { ClientParameters cliParams = new ClientParameters(); cliParams.protocols = allowedProts; ServerParameters servParams = new ServerParameters(); - serverReady = false; + CountDownLatch serverReady = new CountDownLatch(1); System.out.println("====================================="); System.out.println("Stapling enabled, PKIXParameters with"); @@ -192,7 +203,7 @@ public class HttpsUrlConnClient { Security.setProperty("ocsp.enable", "false"); HttpsUrlConnClient sslTest = new HttpsUrlConnClient(cliParams, - servParams); + servParams, serverReady); TestResult tr = sslTest.getResult(); if (!checkClientValidationFailure(tr.clientExc, BasicReason.REVOKED)) { if (tr.clientExc != null) { @@ -219,10 +230,11 @@ public class HttpsUrlConnClient { /* * Define the server side of the test. * - * If the server prematurely exits, serverReady will be set to true + * If the server prematurely exits, serverReady will be counted down * to avoid infinite hangs. */ - void doServerSide(ServerParameters servParams) throws Exception { + void doServerSide(ServerParameters servParams, CountDownLatch serverReady) + throws Exception { // Selectively enable or disable the feature System.setProperty("jdk.tls.server.enableStatusRequestExtension", @@ -274,7 +286,7 @@ public class HttpsUrlConnClient { /* * Signal Client, we're ready for his connect. */ - serverReady = true; + serverReady.countDown(); try (SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept(); BufferedReader in = new BufferedReader( @@ -306,18 +318,13 @@ public class HttpsUrlConnClient { /* * Define the client side of the test. * - * If the server prematurely exits, serverReady will be set to true + * If the server prematurely exits, serverReady will be counted down * to avoid infinite hangs. */ - void doClientSide(ClientParameters cliParams) throws Exception { + void doClientSide(ClientParameters cliParams, CountDownLatch serverReady) + throws Exception { - // Wait 5 seconds for server ready - for (int i = 0; (i < 100 && !serverReady); i++) { - Thread.sleep(50); - } - if (!serverReady) { - throw new RuntimeException("Server not ready yet"); - } + serverReady.await(); // Selectively enable or disable the feature System.setProperty("jdk.tls.client.enableStatusRequestExtension", @@ -373,16 +380,16 @@ public class HttpsUrlConnClient { * * Fork off the other side, then do your work. */ - HttpsUrlConnClient(ClientParameters cliParams, - ServerParameters servParams) throws Exception { + HttpsUrlConnClient(ClientParameters cliParams, ServerParameters servParams, + CountDownLatch serverReady) throws Exception { Exception startException = null; try { if (separateServerThread) { - startServer(servParams, true); - startClient(cliParams, false); + startServer(servParams, true, serverReady); + startClient(cliParams, false, serverReady); } else { - startClient(cliParams, true); - startServer(servParams, false); + startClient(cliParams, true, serverReady); + startServer(servParams, false, serverReady); } } catch (Exception e) { startException = e; @@ -453,51 +460,53 @@ public class HttpsUrlConnClient { return tr; } - final void startServer(ServerParameters servParams, boolean newThread) - throws Exception { + final void startServer(ServerParameters servParams, boolean newThread, + CountDownLatch serverReady) throws IOException { if (newThread) { serverThread = new Thread() { @Override public void run() { try { - doServerSide(servParams); + doServerSide(servParams, serverReady); } catch (Exception e) { /* * Our server thread just died. * * Release the client, if not active already... */ - System.err.println("Server died..."); - serverReady = true; + System.err.println("Server died: " + e); serverException = e; + } finally { + serverReady.countDown(); } } }; serverThread.start(); } else { try { - doServerSide(servParams); + doServerSide(servParams, serverReady); } catch (Exception e) { + System.err.println("Server died: " + e); serverException = e; } finally { - serverReady = true; + serverReady.countDown(); } } } - final void startClient(ClientParameters cliParams, boolean newThread) - throws Exception { + final void startClient(ClientParameters cliParams, boolean newThread, + CountDownLatch serverReady) throws Exception { if (newThread) { clientThread = new Thread() { @Override public void run() { try { - doClientSide(cliParams); + doClientSide(cliParams, serverReady); } catch (Exception e) { /* * Our client thread just died. */ - System.err.println("Client died..."); + System.err.println("Client died: " + e); clientException = e; } } @@ -505,9 +514,10 @@ public class HttpsUrlConnClient { clientThread.start(); } else { try { - doClientSide(cliParams); + doClientSide(cliParams, serverReady); } catch (Exception e) { clientException = e; + System.err.println("Client died: " + e); } } } From fc76403b01c4e801f2a58810deeec2a6ebfa8458 Mon Sep 17 00:00:00 2001 From: Raffaello Giulietti Date: Wed, 17 Dec 2025 09:20:48 +0000 Subject: [PATCH 335/706] 8373798: Refactor java/math tests to use JUnit Reviewed-by: darcy --- .../jdk/java/math/BigDecimal/Constructor.java | 56 +++++--- .../math/BigInteger/LargeValueExceptions.java | 134 ++++++++++-------- 2 files changed, 111 insertions(+), 79 deletions(-) diff --git a/test/jdk/java/math/BigDecimal/Constructor.java b/test/jdk/java/math/BigDecimal/Constructor.java index b7371074225..975d96772a6 100644 --- a/test/jdk/java/math/BigDecimal/Constructor.java +++ b/test/jdk/java/math/BigDecimal/Constructor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2025, 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,45 +26,57 @@ * @bug 4259453 8200698 * @summary Test constructors of BigDecimal * @library .. - * @run testng Constructor + * @run junit Constructor */ +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + import java.math.BigDecimal; -import org.testng.annotations.Test; public class Constructor { - @Test(expectedExceptions=NumberFormatException.class) + @Test public void stringConstructor() { - BigDecimal bd = new BigDecimal("1.2e"); + Assertions.assertThrows(NumberFormatException.class, () -> { + BigDecimal bd = new BigDecimal("1.2e"); + }); } - @Test(expectedExceptions=NumberFormatException.class) + @Test public void charArrayConstructorNegativeOffset() { - BigDecimal bd = new BigDecimal(new char[5], -1, 4, null); + Assertions.assertThrows(NumberFormatException.class, () -> { + BigDecimal bd = new BigDecimal(new char[5], -1, 4, null); + }); } - @Test(expectedExceptions=NumberFormatException.class) + @Test public void charArrayConstructorNegativeLength() { - BigDecimal bd = new BigDecimal(new char[5], 0, -1, null); + Assertions.assertThrows(NumberFormatException.class, () -> { + BigDecimal bd = new BigDecimal(new char[5], 0, -1, null); + }); } - @Test(expectedExceptions=NumberFormatException.class) + @Test public void charArrayConstructorIntegerOverflow() { - try { - BigDecimal bd = new BigDecimal(new char[5], Integer.MAX_VALUE - 5, - 6, null); - } catch (NumberFormatException nfe) { - if (nfe.getCause() instanceof IndexOutOfBoundsException) { - throw new RuntimeException - ("NumberFormatException should not have a cause"); - } else { - throw nfe; + Assertions.assertThrows(NumberFormatException.class, () -> { + try { + BigDecimal bd = new BigDecimal(new char[5], Integer.MAX_VALUE - 5, + 6, null); + } catch (NumberFormatException nfe) { + if (nfe.getCause() instanceof IndexOutOfBoundsException) { + throw new RuntimeException + ("NumberFormatException should not have a cause"); + } else { + throw nfe; + } } - } + }); } - @Test(expectedExceptions=NumberFormatException.class) + @Test public void charArrayConstructorIndexOutOfBounds() { - BigDecimal bd = new BigDecimal(new char[5], 1, 5, null); + Assertions.assertThrows(NumberFormatException.class, () -> { + BigDecimal bd = new BigDecimal(new char[5], 1, 5, null); + }); } } diff --git a/test/jdk/java/math/BigInteger/LargeValueExceptions.java b/test/jdk/java/math/BigInteger/LargeValueExceptions.java index 4c85281a5c0..9670691e51c 100644 --- a/test/jdk/java/math/BigInteger/LargeValueExceptions.java +++ b/test/jdk/java/math/BigInteger/LargeValueExceptions.java @@ -26,13 +26,16 @@ * @bug 8200698 * @summary Tests that exceptions are thrown for ops which would overflow * @requires (sun.arch.data.model == "64" & os.maxMemory >= 4g) - * @run testng/othervm/timeout=480 -Xmx4g LargeValueExceptions + * @run junit/othervm/timeout=480 -Xmx4g LargeValueExceptions */ + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + import java.math.BigInteger; + import static java.math.BigInteger.ONE; -import org.testng.ITestResult; -import org.testng.annotations.AfterMethod; -import org.testng.annotations.Test; // // The intent of this test is to probe the boundaries between overflow and @@ -64,47 +67,48 @@ public class LargeValueExceptions { // Half BigInteger.MAX_MAG_LENGTH private static final int MAX_INTS_HALF = MAX_INTS / 2; - // Print the run time of each sub-test in milliseconds - @AfterMethod - public void getRunTime(ITestResult tr) { - long time = tr.getEndMillis() - tr.getStartMillis(); - System.out.printf("Run time: %d ms%n", time); - } - // --- squaring --- // Largest no overflow determined by examining data lengths alone. - @Test(enabled=false) + @Test + @Disabled public void squareNoOverflow() { BigInteger x = ONE.shiftLeft(16*MAX_INTS - 1).subtract(ONE); BigInteger y = x.multiply(x); } // Smallest no overflow determined by extra calculations. - @Test(enabled=false) + @Test + @Disabled public void squareIndefiniteOverflowSuccess() { BigInteger x = ONE.shiftLeft(16*MAX_INTS - 1); BigInteger y = x.multiply(x); } // Largest overflow detected by extra calculations. - @Test(expectedExceptions=ArithmeticException.class,enabled=false) + @Test + @Disabled public void squareIndefiniteOverflowFailure() { - BigInteger x = ONE.shiftLeft(16*MAX_INTS).subtract(ONE); - BigInteger y = x.multiply(x); + Assertions.assertThrows(ArithmeticException.class, () -> { + BigInteger x = ONE.shiftLeft(16*MAX_INTS).subtract(ONE); + BigInteger y = x.multiply(x); + }); } // Smallest overflow detected by examining data lengths alone. - @Test(expectedExceptions=ArithmeticException.class) + @Test public void squareDefiniteOverflow() { - BigInteger x = ONE.shiftLeft(16*MAX_INTS); - BigInteger y = x.multiply(x); + Assertions.assertThrows(ArithmeticException.class, () -> { + BigInteger x = ONE.shiftLeft(16*MAX_INTS); + BigInteger y = x.multiply(x); + }); } // --- multiplication --- // Largest no overflow determined by examining data lengths alone. - @Test(enabled=false) + @Test + @Disabled public void multiplyNoOverflow() { final int halfMaxBits = MAX_INTS_HALF << 5; @@ -114,7 +118,8 @@ public class LargeValueExceptions { } // Smallest no overflow determined by extra calculations. - @Test(enabled=false) + @Test + @Disabled public void multiplyIndefiniteOverflowSuccess() { BigInteger x = ONE.shiftLeft((int)(MAX_BITS/2) - 1); long m = MAX_BITS - x.bitLength(); @@ -130,68 +135,83 @@ public class LargeValueExceptions { } // Largest overflow detected by extra calculations. - @Test(expectedExceptions=ArithmeticException.class,enabled=false) + @Test + @Disabled public void multiplyIndefiniteOverflowFailure() { - BigInteger x = ONE.shiftLeft((int)(MAX_BITS/2)).subtract(ONE); - long m = MAX_BITS - x.bitLength(); + Assertions.assertThrows(ArithmeticException.class, () -> { + BigInteger x = ONE.shiftLeft((int)(MAX_BITS/2)).subtract(ONE); + long m = MAX_BITS - x.bitLength(); - BigInteger y = ONE.shiftLeft((int)(MAX_BITS/2)).subtract(ONE); - long n = MAX_BITS - y.bitLength(); + BigInteger y = ONE.shiftLeft((int)(MAX_BITS/2)).subtract(ONE); + long n = MAX_BITS - y.bitLength(); - if (m + n != MAX_BITS) { - throw new RuntimeException("Unexpected leading zero sum"); - } + if (m + n != MAX_BITS) { + throw new RuntimeException("Unexpected leading zero sum"); + } - BigInteger z = x.multiply(y); + BigInteger z = x.multiply(y); + }); } // Smallest overflow detected by examining data lengths alone. - @Test(expectedExceptions=ArithmeticException.class) + @Test public void multiplyDefiniteOverflow() { - // multiply by 4 as MAX_INTS_HALF refers to ints - byte[] xmag = new byte[4*MAX_INTS_HALF]; - xmag[0] = (byte)0xff; - BigInteger x = new BigInteger(1, xmag); + Assertions.assertThrows(ArithmeticException.class, () -> { + // multiply by 4 as MAX_INTS_HALF refers to ints + byte[] xmag = new byte[4*MAX_INTS_HALF]; + xmag[0] = (byte)0xff; + BigInteger x = new BigInteger(1, xmag); - byte[] ymag = new byte[4*MAX_INTS_HALF + 1]; - ymag[0] = (byte)0xff; - BigInteger y = new BigInteger(1, ymag); + byte[] ymag = new byte[4*MAX_INTS_HALF + 1]; + ymag[0] = (byte)0xff; + BigInteger y = new BigInteger(1, ymag); - BigInteger z = x.multiply(y); + BigInteger z = x.multiply(y); + }); } // --- exponentiation --- - @Test(expectedExceptions=ArithmeticException.class) + @Test public void powOverflow() { - BigInteger.TEN.pow(Integer.MAX_VALUE); + Assertions.assertThrows(ArithmeticException.class, () -> { + BigInteger.TEN.pow(Integer.MAX_VALUE); + }); } - @Test(expectedExceptions=ArithmeticException.class) + @Test public void powOverflow1() { - int shift = 20; - int exponent = 1 << shift; - BigInteger x = ONE.shiftLeft((int)(MAX_BITS / exponent)); - BigInteger y = x.pow(exponent); + Assertions.assertThrows(ArithmeticException.class, () -> { + int shift = 20; + int exponent = 1 << shift; + BigInteger x = ONE.shiftLeft((int)(MAX_BITS / exponent)); + BigInteger y = x.pow(exponent); + }); } - @Test(expectedExceptions=ArithmeticException.class) + @Test public void powOverflow2() { - int shift = 20; - int exponent = 1 << shift; - BigInteger x = ONE.shiftLeft((int)(MAX_BITS / exponent)).add(ONE); - BigInteger y = x.pow(exponent); + Assertions.assertThrows(ArithmeticException.class, () -> { + int shift = 20; + int exponent = 1 << shift; + BigInteger x = ONE.shiftLeft((int)(MAX_BITS / exponent)).add(ONE); + BigInteger y = x.pow(exponent); + }); } - @Test(expectedExceptions=ArithmeticException.class,enabled=false) + @Test + @Disabled public void powOverflow3() { - int shift = 20; - int exponent = 1 << shift; - BigInteger x = ONE.shiftLeft((int)(MAX_BITS / exponent)).subtract(ONE); - BigInteger y = x.pow(exponent); + Assertions.assertThrows(ArithmeticException.class, () -> { + int shift = 20; + int exponent = 1 << shift; + BigInteger x = ONE.shiftLeft((int)(MAX_BITS / exponent)).subtract(ONE); + BigInteger y = x.pow(exponent); + }); } - @Test(enabled=false) + @Test + @Disabled public void powOverflow4() { int shift = 20; int exponent = 1 << shift; From 9a23f8aa337e1292179625ce9bb8abe22c9e22e2 Mon Sep 17 00:00:00 2001 From: Aggelos Biboudis Date: Wed, 17 Dec 2025 10:31:23 +0000 Subject: [PATCH 336/706] 8373552: ExactConversionsSupport: bad JLS links in javadoc Reviewed-by: liach, iris --- .../java/lang/runtime/ExactConversionsSupport.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/java.base/share/classes/java/lang/runtime/ExactConversionsSupport.java b/src/java.base/share/classes/java/lang/runtime/ExactConversionsSupport.java index 6e17a4b85a0..b86891749da 100644 --- a/src/java.base/share/classes/java/lang/runtime/ExactConversionsSupport.java +++ b/src/java.base/share/classes/java/lang/runtime/ExactConversionsSupport.java @@ -64,9 +64,12 @@ package java.lang.runtime; * floating-point type is considered exact. * * - * @jls 5.7.1 Exact Testing Conversions - * @jls 5.7.2 Unconditionally Exact Testing Conversions - * @jls 15.20.2 The instanceof Operator + * @see + * JLS 5.7.1 Exact Testing Conversions + * @see + * JLS 5.7.2 Unconditionally Exact Testing Conversions + * @see + * JLS 15.20.2 The instanceof Operator * * @implNote Some exactness checks describe a test which can be redirected * safely through one of the existing methods. Those are omitted too (i.e., From e4636d69e7e41477619a163e97fd3af2e5942dde Mon Sep 17 00:00:00 2001 From: Christian Hagedorn Date: Wed, 17 Dec 2025 11:17:39 +0000 Subject: [PATCH 337/706] 8373420: C2: Add true/false_proj*() methods for IfNode as a replacement for proj_out*(true/false) Reviewed-by: dfenacci, roland, epeter --- src/hotspot/share/opto/castnode.cpp | 7 +++---- src/hotspot/share/opto/castnode.hpp | 2 +- src/hotspot/share/opto/cfgnode.hpp | 22 ++++++++++++++++++++-- src/hotspot/share/opto/ifnode.cpp | 16 +++++++++------- src/hotspot/share/opto/loopTransform.cpp | 18 ++++++++---------- src/hotspot/share/opto/loopUnswitch.cpp | 2 +- src/hotspot/share/opto/loopnode.cpp | 17 ++++++++--------- src/hotspot/share/opto/loopnode.hpp | 2 +- src/hotspot/share/opto/loopopts.cpp | 16 ++++++++-------- src/hotspot/share/opto/macro.cpp | 4 ++-- src/hotspot/share/opto/stringopts.cpp | 2 +- 11 files changed, 62 insertions(+), 46 deletions(-) diff --git a/src/hotspot/share/opto/castnode.cpp b/src/hotspot/share/opto/castnode.cpp index 9c764f22e38..998b6a79903 100644 --- a/src/hotspot/share/opto/castnode.cpp +++ b/src/hotspot/share/opto/castnode.cpp @@ -313,8 +313,7 @@ void CastIINode::remove_range_check_cast(Compile* C) { } } - -bool CastLLNode::is_inner_loop_backedge(ProjNode* proj) { +bool CastLLNode::is_inner_loop_backedge(IfProjNode* proj) { if (proj != nullptr) { Node* ctrl_use = proj->unique_ctrl_out_or_null(); if (ctrl_use != nullptr && ctrl_use->Opcode() == Op_Loop && @@ -333,8 +332,8 @@ bool CastLLNode::cmp_used_at_inner_loop_exit_test(CmpNode* cmp) { for (DUIterator_Fast jmax, j = bol->fast_outs(jmax); j < jmax; j++) { Node* iff = bol->fast_out(j); if (iff->Opcode() == Op_If) { - ProjNode* true_proj = iff->as_If()->proj_out_or_null(true); - ProjNode* false_proj = iff->as_If()->proj_out_or_null(false); + IfTrueNode* true_proj = iff->as_If()->true_proj_or_null(); + IfFalseNode* false_proj = iff->as_If()->false_proj_or_null(); if (is_inner_loop_backedge(true_proj) || is_inner_loop_backedge(false_proj)) { return true; } diff --git a/src/hotspot/share/opto/castnode.hpp b/src/hotspot/share/opto/castnode.hpp index 2ff13e44780..f22df546f41 100644 --- a/src/hotspot/share/opto/castnode.hpp +++ b/src/hotspot/share/opto/castnode.hpp @@ -239,7 +239,7 @@ public: init_class_id(Class_CastLL); } - static bool is_inner_loop_backedge(ProjNode* proj); + static bool is_inner_loop_backedge(IfProjNode* proj); static bool cmp_used_at_inner_loop_exit_test(CmpNode* cmp); bool used_at_inner_loop_exit_test() const; diff --git a/src/hotspot/share/opto/cfgnode.hpp b/src/hotspot/share/opto/cfgnode.hpp index ef799f4c39a..5f7f4790443 100644 --- a/src/hotspot/share/opto/cfgnode.hpp +++ b/src/hotspot/share/opto/cfgnode.hpp @@ -354,7 +354,7 @@ class IfNode : public MultiBranchNode { static bool is_dominator_unc(CallStaticJavaNode* dom_unc, CallStaticJavaNode* unc); protected: - ProjNode* range_check_trap_proj(int& flip, Node*& l, Node*& r); + IfProjNode* range_check_trap_proj(int& flip, Node*& l, Node*& r) const; Node* Ideal_common(PhaseGVN *phase, bool can_reshape); Node* search_identical(int dist, PhaseIterGVN* igvn); @@ -433,6 +433,24 @@ public: static IfNode* make_with_same_profile(IfNode* if_node_profile, Node* ctrl, Node* bol); + IfTrueNode* true_proj() const { + return proj_out(true)->as_IfTrue(); + } + + IfTrueNode* true_proj_or_null() const { + ProjNode* true_proj = proj_out_or_null(true); + return true_proj == nullptr ? nullptr : true_proj->as_IfTrue(); + } + + IfFalseNode* false_proj() const { + return proj_out(false)->as_IfFalse(); + } + + IfFalseNode* false_proj_or_null() const { + ProjNode* false_proj = proj_out_or_null(false); + return false_proj == nullptr ? nullptr : false_proj->as_IfFalse(); + } + virtual int Opcode() const; virtual bool pinned() const { return true; } virtual const Type *bottom_type() const { return TypeTuple::IFBOTH; } @@ -523,7 +541,7 @@ class ParsePredicateNode : public IfNode { // Return the uncommon trap If projection of this Parse Predicate. ParsePredicateUncommonProj* uncommon_proj() const { - return proj_out(0)->as_IfFalse(); + return false_proj(); } Node* uncommon_trap() const; diff --git a/src/hotspot/share/opto/ifnode.cpp b/src/hotspot/share/opto/ifnode.cpp index 83e975b95a2..763888b65b2 100644 --- a/src/hotspot/share/opto/ifnode.cpp +++ b/src/hotspot/share/opto/ifnode.cpp @@ -487,7 +487,7 @@ IfNode* IfNode::make_with_same_profile(IfNode* if_node_profile, Node* ctrl, Node // if this IfNode follows a range check pattern return the projection // for the failed path -ProjNode* IfNode::range_check_trap_proj(int& flip_test, Node*& l, Node*& r) { +IfProjNode* IfNode::range_check_trap_proj(int& flip_test, Node*& l, Node*& r) const { if (outcnt() != 2) { return nullptr; } @@ -515,8 +515,10 @@ ProjNode* IfNode::range_check_trap_proj(int& flip_test, Node*& l, Node*& r) { // Flip 1: If (Bool[<] CmpU(l, LoadRange)) ... // Flip 2: If (Bool[<=] CmpU(LoadRange, l)) ... - ProjNode* iftrap = proj_out_or_null(flip_test == 2 ? true : false); - return iftrap; + if (flip_test == 2) { + return true_proj_or_null(); + } + return false_proj_or_null(); } @@ -528,7 +530,7 @@ int RangeCheckNode::is_range_check(Node* &range, Node* &index, jint &offset) { int flip_test = 0; Node* l = nullptr; Node* r = nullptr; - ProjNode* iftrap = range_check_trap_proj(flip_test, l, r); + IfProjNode* iftrap = range_check_trap_proj(flip_test, l, r); if (iftrap == nullptr) { return 0; @@ -1875,8 +1877,8 @@ static IfNode* idealize_test(PhaseGVN* phase, IfNode* iff) { assert(iff->in(0) != nullptr, "If must be live"); if (iff->outcnt() != 2) return nullptr; // Malformed projections. - Node* old_if_f = iff->proj_out(false); - Node* old_if_t = iff->proj_out(true); + IfFalseNode* old_if_f = iff->false_proj(); + IfTrueNode* old_if_t = iff->true_proj(); // CountedLoopEnds want the back-control test to be TRUE, regardless of // whether they are testing a 'gt' or 'lt' condition. The 'gt' condition @@ -2192,7 +2194,7 @@ void ParsePredicateNode::mark_useless(PhaseIterGVN& igvn) { } Node* ParsePredicateNode::uncommon_trap() const { - ParsePredicateUncommonProj* uncommon_proj = proj_out(0)->as_IfFalse(); + ParsePredicateUncommonProj* uncommon_proj = false_proj(); Node* uct_region_or_call = uncommon_proj->unique_ctrl_out(); assert(uct_region_or_call->is_Region() || uct_region_or_call->is_Call(), "must be a region or call uct"); return uct_region_or_call; diff --git a/src/hotspot/share/opto/loopTransform.cpp b/src/hotspot/share/opto/loopTransform.cpp index 41bce0fe9b5..fdb3ab89b82 100644 --- a/src/hotspot/share/opto/loopTransform.cpp +++ b/src/hotspot/share/opto/loopTransform.cpp @@ -87,7 +87,7 @@ void IdealLoopTree::record_for_igvn() { Node* outer_safepoint = l->outer_safepoint(); assert(outer_safepoint != nullptr, "missing piece of strip mined loop"); _phase->_igvn._worklist.push(outer_safepoint); - Node* cle_out = _head->as_CountedLoop()->loopexit()->proj_out(false); + IfFalseNode* cle_out = _head->as_CountedLoop()->loopexit()->false_proj(); assert(cle_out != nullptr, "missing piece of strip mined loop"); _phase->_igvn._worklist.push(cle_out); } @@ -1464,9 +1464,8 @@ void PhaseIdealLoop::insert_pre_post_loops(IdealLoopTree *loop, Node_List &old_n pre_end->_prob = PROB_FAIR; // Find the pre-loop normal exit. - Node* pre_exit = pre_end->proj_out(false); - assert(pre_exit->Opcode() == Op_IfFalse, ""); - IfFalseNode *new_pre_exit = new IfFalseNode(pre_end); + IfFalseNode* pre_exit = pre_end->false_proj(); + IfFalseNode* new_pre_exit = new IfFalseNode(pre_end); _igvn.register_new_node_with_optimizer(new_pre_exit); set_idom(new_pre_exit, pre_end, dd_main_head); set_loop(new_pre_exit, outer_loop->_parent); @@ -1707,8 +1706,7 @@ Node *PhaseIdealLoop::insert_post_loop(IdealLoopTree* loop, Node_List& old_new, //------------------------------ // Step A: Create a new post-Loop. - Node* main_exit = outer_main_end->proj_out(false); - assert(main_exit->Opcode() == Op_IfFalse, ""); + IfFalseNode* main_exit = outer_main_end->false_proj(); int dd_main_exit = dom_depth(main_exit); // Step A1: Clone the loop body of main. The clone becomes the post-loop. @@ -1721,7 +1719,7 @@ Node *PhaseIdealLoop::insert_post_loop(IdealLoopTree* loop, Node_List& old_new, post_head->set_post_loop(main_head); // clone_loop() above changes the exit projection - main_exit = outer_main_end->proj_out(false); + main_exit = outer_main_end->false_proj(); // Reduce the post-loop trip count. CountedLoopEndNode* post_end = old_new[main_end->_idx]->as_CountedLoopEnd(); @@ -1786,7 +1784,7 @@ Node *PhaseIdealLoop::insert_post_loop(IdealLoopTree* loop, Node_List& old_new, // right after the execution of the inner CountedLoop. // We have to make sure that such stores in the post loop have the right memory inputs from the main loop // The moved store node is always attached right after the inner loop exit, and just before the safepoint - const Node* if_false = main_end->proj_out(false); + const IfFalseNode* if_false = main_end->false_proj(); for (DUIterator j = if_false->outs(); if_false->has_out(j); j++) { Node* store = if_false->out(j); if (store->is_Store()) { @@ -3944,7 +3942,7 @@ bool PhaseIdealLoop::intrinsify_fill(IdealLoopTree* lpt) { return false; } - Node* exit = head->loopexit()->proj_out_or_null(0); + IfFalseNode* exit = head->loopexit()->false_proj_or_null(); if (exit == nullptr) { return false; } @@ -3988,7 +3986,7 @@ bool PhaseIdealLoop::intrinsify_fill(IdealLoopTree* lpt) { // If the store is on the backedge, it is not executed in the last // iteration, and we must subtract 1 from the len. - Node* backedge = head->loopexit()->proj_out(1); + IfTrueNode* backedge = head->loopexit()->true_proj(); if (store->in(0) == backedge) { len = new SubINode(len, _igvn.intcon(1)); _igvn.register_new_node_with_optimizer(len); diff --git a/src/hotspot/share/opto/loopUnswitch.cpp b/src/hotspot/share/opto/loopUnswitch.cpp index 287f8354dc1..cc83bdda561 100644 --- a/src/hotspot/share/opto/loopUnswitch.cpp +++ b/src/hotspot/share/opto/loopUnswitch.cpp @@ -488,7 +488,7 @@ IfTrueNode* PhaseIdealLoop::create_new_if_for_multiversion(IfTrueNode* multivers IfNode* multiversion_if = multiversioning_fast_proj->in(0)->as_If(); Node* entry = multiversion_if->in(0); OpaqueMultiversioningNode* opaque = multiversion_if->in(1)->as_OpaqueMultiversioning(); - IfFalseNode* multiversion_slow_proj = multiversion_if->proj_out(0)->as_IfFalse(); + IfFalseNode* multiversion_slow_proj = multiversion_if->false_proj(); Node* slow_path = multiversion_slow_proj->unique_ctrl_out(); // The slow_loop may still be delayed, and waiting for runtime-checks to be added to the diff --git a/src/hotspot/share/opto/loopnode.cpp b/src/hotspot/share/opto/loopnode.cpp index 42d3ee105f8..dacc1a1a734 100644 --- a/src/hotspot/share/opto/loopnode.cpp +++ b/src/hotspot/share/opto/loopnode.cpp @@ -79,11 +79,10 @@ bool LoopNode::is_valid_counted_loop(BasicType bt) const { BaseCountedLoopNode* l = as_BaseCountedLoop(); BaseCountedLoopEndNode* le = l->loopexit_or_null(); if (le != nullptr && - le->proj_out_or_null(1 /* true */) == l->in(LoopNode::LoopBackControl)) { + le->true_proj_or_null() == l->in(LoopNode::LoopBackControl)) { Node* phi = l->phi(); - Node* exit = le->proj_out_or_null(0 /* false */); - if (exit != nullptr && exit->Opcode() == Op_IfFalse && - phi != nullptr && phi->is_Phi() && + IfFalseNode* exit = le->false_proj_or_null(); + if (exit != nullptr && phi != nullptr && phi->is_Phi() && phi->in(LoopNode::LoopBackControl) == l->incr() && le->loopnode() == l && le->stride_is_con()) { return true; @@ -942,7 +941,7 @@ bool PhaseIdealLoop::create_loop_nest(IdealLoopTree* loop, Node_List &old_new) { safepoint = find_safepoint(back_control, x, loop); } - Node* exit_branch = exit_test->proj_out(false); + IfFalseNode* exit_branch = exit_test->false_proj(); Node* entry_control = head->in(LoopNode::EntryControl); // Clone the control flow of the loop to build an outer loop @@ -3087,7 +3086,7 @@ IfFalseNode* OuterStripMinedLoopNode::outer_loop_exit() const { if (le == nullptr) { return nullptr; } - Node* c = le->proj_out_or_null(false); + IfFalseNode* c = le->false_proj_or_null(); if (c == nullptr) { return nullptr; } @@ -3407,7 +3406,7 @@ void OuterStripMinedLoopNode::adjust_strip_mined_loop(PhaseIterGVN* igvn) { return; } - Node* cle_tail = inner_cle->proj_out(true); + IfTrueNode* cle_tail = inner_cle->true_proj(); ResourceMark rm; Node_List old_new; if (cle_tail->outcnt() > 1) { @@ -3549,7 +3548,7 @@ void OuterStripMinedLoopNode::transform_to_counted_loop(PhaseIterGVN* igvn, Phas iloop->replace_node_and_forward_ctrl(outer_le, new_end); } // the backedge of the inner loop must be rewired to the new loop end - Node* backedge = cle->proj_out(true); + IfTrueNode* backedge = cle->true_proj(); igvn->replace_input_of(backedge, 0, new_end); if (iloop != nullptr) { iloop->set_idom(backedge, new_end, iloop->dom_depth(new_end) + 1); @@ -3630,7 +3629,7 @@ const Type* OuterStripMinedLoopEndNode::Value(PhaseGVN* phase) const { bool OuterStripMinedLoopEndNode::is_expanded(PhaseGVN *phase) const { // The outer strip mined loop head only has Phi uses after expansion if (phase->is_IterGVN()) { - Node* backedge = proj_out_or_null(true); + IfTrueNode* backedge = true_proj_or_null(); if (backedge != nullptr) { Node* head = backedge->unique_ctrl_out_or_null(); if (head != nullptr && head->is_OuterStripMinedLoop()) { diff --git a/src/hotspot/share/opto/loopnode.hpp b/src/hotspot/share/opto/loopnode.hpp index 3b97d76773f..ffc283ac941 100644 --- a/src/hotspot/share/opto/loopnode.hpp +++ b/src/hotspot/share/opto/loopnode.hpp @@ -607,7 +607,7 @@ public: virtual SafePointNode* outer_safepoint() const; CountedLoopNode* inner_counted_loop() const { return unique_ctrl_out()->as_CountedLoop(); } CountedLoopEndNode* inner_counted_loop_end() const { return inner_counted_loop()->loopexit(); } - IfFalseNode* inner_loop_exit() const { return inner_counted_loop_end()->proj_out(false)->as_IfFalse(); } + IfFalseNode* inner_loop_exit() const { return inner_counted_loop_end()->false_proj(); } void adjust_strip_mined_loop(PhaseIterGVN* igvn); diff --git a/src/hotspot/share/opto/loopopts.cpp b/src/hotspot/share/opto/loopopts.cpp index b1422d5db20..8f85b7f270e 100644 --- a/src/hotspot/share/opto/loopopts.cpp +++ b/src/hotspot/share/opto/loopopts.cpp @@ -1321,8 +1321,8 @@ bool PhaseIdealLoop::identical_backtoback_ifs(Node *n) { return false; } IfNode* dom_if = dom->as_If(); - Node* proj_true = dom_if->proj_out(1); - Node* proj_false = dom_if->proj_out(0); + IfTrueNode* proj_true = dom_if->true_proj(); + IfFalseNode* proj_false = dom_if->false_proj(); for (uint i = 1; i < region->req(); i++) { if (is_dominator(proj_true, region->in(i))) { @@ -1585,8 +1585,8 @@ bool PhaseIdealLoop::try_merge_identical_ifs(Node* n) { dom_if->in(1)->in(1)->as_SubTypeCheck()->method() != nullptr), "only for subtype checks with profile data attached"); _igvn.replace_input_of(n, 1, dom_if->in(1)); } - ProjNode* dom_proj_true = dom_if->proj_out(1); - ProjNode* dom_proj_false = dom_if->proj_out(0); + IfTrueNode* dom_proj_true = dom_if->true_proj(); + IfFalseNode* dom_proj_false = dom_if->false_proj(); // Now split the IF RegionNode* new_false_region; @@ -1630,10 +1630,10 @@ bool PhaseIdealLoop::try_merge_identical_ifs(Node* n) { // unrelated control dependency. for (uint i = 1; i < new_false_region->req(); i++) { if (is_dominator(dom_proj_true, new_false_region->in(i))) { - dominated_by(dom_proj_true->as_IfProj(), new_false_region->in(i)->in(0)->as_If()); + dominated_by(dom_proj_true, new_false_region->in(i)->in(0)->as_If()); } else { assert(is_dominator(dom_proj_false, new_false_region->in(i)), "bad if"); - dominated_by(dom_proj_false->as_IfProj(), new_false_region->in(i)->in(0)->as_If()); + dominated_by(dom_proj_false, new_false_region->in(i)->in(0)->as_If()); } } return true; @@ -2394,7 +2394,7 @@ void PhaseIdealLoop::clone_outer_loop(LoopNode* head, CloneLoopMode mode, IdealL CountedLoopEndNode* cle = cl->loopexit(); CountedLoopNode* new_cl = old_new[cl->_idx]->as_CountedLoop(); CountedLoopEndNode* new_cle = new_cl->as_CountedLoop()->loopexit_or_null(); - Node* cle_out = cle->proj_out(false); + IfFalseNode* cle_out = cle->false_proj(); Node* new_sfpt = nullptr; Node* new_cle_out = cle_out->clone(); @@ -2691,7 +2691,7 @@ void PhaseIdealLoop::fix_ctrl_uses(const Node_List& body, const IdealLoopTree* l if (use->in(0) == cle) { IfFalseNode* cle_out = use->as_IfFalse(); IfNode* le = cl->outer_loop_end(); - use = le->proj_out(false); + use = le->false_proj(); use_loop = get_loop(use); if (mode == CloneIncludesStripMined) { nnn = old_new[le->_idx]; diff --git a/src/hotspot/share/opto/macro.cpp b/src/hotspot/share/opto/macro.cpp index bc07f937f1e..80818a4ddc7 100644 --- a/src/hotspot/share/opto/macro.cpp +++ b/src/hotspot/share/opto/macro.cpp @@ -2379,8 +2379,8 @@ void PhaseMacroExpand::expand_subtypecheck_node(SubTypeCheckNode *check) { continue; } - Node* iftrue = iff->as_If()->proj_out(1); - Node* iffalse = iff->as_If()->proj_out(0); + IfTrueNode* iftrue = iff->as_If()->true_proj(); + IfFalseNode* iffalse = iff->as_If()->false_proj(); Node* ctrl = iff->in(0); Node* subklass = nullptr; diff --git a/src/hotspot/share/opto/stringopts.cpp b/src/hotspot/share/opto/stringopts.cpp index 6b98c4ca2b0..e499ba932e1 100644 --- a/src/hotspot/share/opto/stringopts.cpp +++ b/src/hotspot/share/opto/stringopts.cpp @@ -255,7 +255,7 @@ void StringConcat::eliminate_unneeded_control() { Compile* C = _stringopts->C; C->gvn_replace_by(n, n->in(0)->in(0)); // get rid of the other projection - C->gvn_replace_by(n->in(0)->as_If()->proj_out(false), C->top()); + C->gvn_replace_by(n->in(0)->as_If()->false_proj(), C->top()); } else if (n->is_Region()) { Node* iff = n->in(1)->in(0); assert(n->req() == 3 && n->in(2)->in(0) == iff, "not a diamond"); From 5e7ae281326ca306339aaba101d4206dffdb9ca0 Mon Sep 17 00:00:00 2001 From: Daniel Fuchs Date: Wed, 17 Dec 2025 12:13:58 +0000 Subject: [PATCH 338/706] 8373677: Clear text HttpServer connection could fail fast if receiving SSL ClientHello Reviewed-by: jpai, djelinski --- .../classes/sun/net/httpserver/Request.java | 37 +++- .../sun/net/httpserver/ServerImpl.java | 12 +- .../net/httpserver/ClearTextServerSSL.java | 159 ++++++++++++++++++ 3 files changed, 206 insertions(+), 2 deletions(-) create mode 100644 test/jdk/com/sun/net/httpserver/ClearTextServerSSL.java diff --git a/src/jdk.httpserver/share/classes/sun/net/httpserver/Request.java b/src/jdk.httpserver/share/classes/sun/net/httpserver/Request.java index 4a4afc8d7ce..75eeb29f015 100644 --- a/src/jdk.httpserver/share/classes/sun/net/httpserver/Request.java +++ b/src/jdk.httpserver/share/classes/sun/net/httpserver/Request.java @@ -25,6 +25,7 @@ package sun.net.httpserver; +import java.net.ProtocolException; import java.nio.*; import java.io.*; import java.nio.channels.*; @@ -39,15 +40,18 @@ class Request { static final int BUF_LEN = 2048; static final byte CR = 13; static final byte LF = 10; + static final byte FIRST_CHAR = 32; private String startLine; private SocketChannel chan; private InputStream is; private OutputStream os; private final int maxReqHeaderSize; + private final boolean firstClearRequest; - Request(InputStream rawInputStream, OutputStream rawout) throws IOException { + Request(InputStream rawInputStream, OutputStream rawout, boolean firstClearRequest) throws IOException { this.maxReqHeaderSize = ServerConfig.getMaxReqHeaderSize(); + this.firstClearRequest = firstClearRequest; is = rawInputStream; os = rawout; do { @@ -78,6 +82,25 @@ class Request { boolean gotCR = false, gotLF = false; pos = 0; lineBuf = new StringBuffer(); long lsize = 32; + + // For the first request that comes on a clear connection + // we will check that the first non CR/LF char on the + // request line is eligible. This should be the first char + // of a method name, so it should be at least greater or equal + // to 32 (FIRST_CHAR) which is the space character. + // The main goal here is to fail fast if we receive 0x16 (22) which + // happens to be the first byte of a TLS handshake record. + // This is typically what would be received if a TLS client opened + // a TLS connection on a non-TLS server. + // If we receive 0x16 we should close the connection immediately as + // it indicates we're receiving a ClientHello on a clear + // connection, and we will never receive the expected CRLF that + // terminates the first request line. + // Though we could check only for 0x16, any characters < 32 + // (excluding CRLF) is not expected at this position in a + // request line, so we can still fail here early if any of + // those are detected. + int offset = 0; while (!gotLF) { int c = is.read(); if (c == -1) { @@ -89,6 +112,12 @@ class Request { } else { gotCR = false; consume(CR); + if (firstClearRequest && offset == 0) { + if (c < FIRST_CHAR) { + throw new ProtocolException("Unexpected start of request line"); + } + offset++; + } consume(c); lsize = lsize + 2; } @@ -96,6 +125,12 @@ class Request { if (c == CR) { gotCR = true; } else { + if (firstClearRequest && offset == 0) { + if (c < FIRST_CHAR) { + throw new ProtocolException("Unexpected start of request line"); + } + offset++; + } consume(c); lsize = lsize + 1; } diff --git a/src/jdk.httpserver/share/classes/sun/net/httpserver/ServerImpl.java b/src/jdk.httpserver/share/classes/sun/net/httpserver/ServerImpl.java index 1eb918b4e66..e8c8d336e03 100644 --- a/src/jdk.httpserver/share/classes/sun/net/httpserver/ServerImpl.java +++ b/src/jdk.httpserver/share/classes/sun/net/httpserver/ServerImpl.java @@ -45,6 +45,7 @@ import java.lang.System.Logger; import java.lang.System.Logger.Level; import java.net.BindException; import java.net.InetSocketAddress; +import java.net.ProtocolException; import java.net.ServerSocket; import java.net.URI; import java.net.URISyntaxException; @@ -733,7 +734,16 @@ class ServerImpl { connection.raw = rawin; connection.rawout = rawout; } - Request req = new Request(rawin, rawout); + + Request req; + try { + req = new Request(rawin, rawout, newconnection && !https); + } catch (ProtocolException pe) { + logger.log(Level.DEBUG, "closing due to: " + pe); + reject(Code.HTTP_BAD_REQUEST, "", pe.getMessage()); + return; + } + requestLine = req.requestLine(); if (requestLine == null) { /* connection closed */ diff --git a/test/jdk/com/sun/net/httpserver/ClearTextServerSSL.java b/test/jdk/com/sun/net/httpserver/ClearTextServerSSL.java new file mode 100644 index 00000000000..75e4f3fcf45 --- /dev/null +++ b/test/jdk/com/sun/net/httpserver/ClearTextServerSSL.java @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2025, 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 8373677 + * @summary Tests for verifying that a non-SSL server can detect + * when a client attempts to use SSL. + * @library /test/lib + * @run junit/othervm ${test.main.class} + */ + +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; +import com.sun.net.httpserver.HttpServer; +import jdk.test.lib.net.SimpleSSLContext; +import jdk.test.lib.net.URIBuilder; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.util.logging.ConsoleHandler; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.net.ssl.SSLException; + +import static com.sun.net.httpserver.HttpExchange.RSPBODY_EMPTY; +import static java.net.http.HttpClient.Builder.NO_PROXY; +import static org.junit.jupiter.api.Assertions.*; + +public class ClearTextServerSSL { + + static final InetAddress LOOPBACK_ADDR = InetAddress.getLoopbackAddress(); + static final boolean ENABLE_LOGGING = true; + static final Logger logger = Logger.getLogger("com.sun.net.httpserver"); + + static final String CTXT_PATH = "/ClearTextServerSSL"; + + @BeforeAll + public static void setup() { + if (ENABLE_LOGGING) { + ConsoleHandler ch = new ConsoleHandler(); + logger.setLevel(Level.ALL); + ch.setLevel(Level.ALL); + logger.addHandler(ch); + } + } + + @Test + public void test() throws Exception { + var sslContext = new SimpleSSLContext().get(); + var handler = new TestHandler(); + var server = HttpServer.create(new InetSocketAddress(LOOPBACK_ADDR, 0), 0); + server.createContext(path(""), handler); + server.start(); + try (var client = HttpClient.newBuilder() + .sslContext(sslContext) + .proxy(NO_PROXY) + .build()) { + var request = HttpRequest.newBuilder() + .uri(uri("http", server, path("/clear"))) + .build(); + var response = client.send(request, HttpResponse.BodyHandlers.ofString()); + assertEquals(200, response.statusCode()); + var sslRequest = HttpRequest.newBuilder() + .uri(uri("https", server, path("/ssl"))) + .build(); + Assertions.assertThrows(SSLException.class, () -> { + client.send(sslRequest, HttpResponse.BodyHandlers.ofString()); + }); + try (var socket = new Socket()) { + socket.connect(server.getAddress()); + byte[] badRequest = { + 22, 'B', 'A', 'D', ' ', + '/', ' ' , + 'H', 'T', 'T', 'P', '/', '1', '.', '1' }; + socket.getOutputStream().write(badRequest); + socket.getOutputStream().flush(); + var reader = new InputStreamReader(socket.getInputStream()); + var line = reader.readAllLines(); + Assertions.assertEquals("HTTP/1.1 400 Bad Request", line.get(0)); + System.out.println("Got expected response:"); + line.stream().map(l -> "\t" + l).forEach(System.out::println); + } + + } finally { + server.stop(0); + } + } + + // --- infra --- + + static String path(String path) { + assert CTXT_PATH.startsWith("/"); + assert !CTXT_PATH.endsWith("/"); + if (path.startsWith("/")) { + return CTXT_PATH + path; + } else { + return CTXT_PATH + "/" + path; + } + } + + static URI uri(String scheme, HttpServer server, String path) throws URISyntaxException { + return URIBuilder.newBuilder() + .scheme(scheme) + .loopback() + .port(server.getAddress().getPort()) + .path(path) + .build(); + } + + /** + * A test handler that reads any request bytes and sends + * an empty 200 response + */ + static class TestHandler implements HttpHandler { + @java.lang.Override + public void handle(HttpExchange exchange) throws IOException { + try (var reqBody = exchange.getRequestBody()) { + reqBody.readAllBytes(); + exchange.sendResponseHeaders(200, RSPBODY_EMPTY); + } catch (Throwable t) { + t.printStackTrace(); + exchange.sendResponseHeaders(500, RSPBODY_EMPTY); + } + } + } +} From 39306d7ab901a1d27d9bfd80f04d917b4d17d07f Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Wed, 17 Dec 2025 13:19:49 +0000 Subject: [PATCH 339/706] 8373800: Remove ScopedValueBindingsResolver Reviewed-by: alanb, liach --- src/hotspot/share/classfile/vmClassMacros.hpp | 3 +++ src/hotspot/share/prims/jvm.cpp | 13 +------------ 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/src/hotspot/share/classfile/vmClassMacros.hpp b/src/hotspot/share/classfile/vmClassMacros.hpp index 04f0aaaaa44..71d6b9f22b2 100644 --- a/src/hotspot/share/classfile/vmClassMacros.hpp +++ b/src/hotspot/share/classfile/vmClassMacros.hpp @@ -190,6 +190,9 @@ /* GC support */ \ do_klass(FillerObject_klass, jdk_internal_vm_FillerObject ) \ \ + /* Scoped Values */ \ + do_klass(ScopedValue_Carrier_klass, java_lang_ScopedValue_Carrier ) \ + \ /*end*/ #endif // SHARE_CLASSFILE_VMCLASSMACROS_HPP diff --git a/src/hotspot/share/prims/jvm.cpp b/src/hotspot/share/prims/jvm.cpp index 48d89235c98..ef5aca96a57 100644 --- a/src/hotspot/share/prims/jvm.cpp +++ b/src/hotspot/share/prims/jvm.cpp @@ -1211,22 +1211,11 @@ JVM_ENTRY(jboolean, JVM_IsHiddenClass(JNIEnv *env, jclass cls)) JVM_END -class ScopedValueBindingsResolver { -public: - InstanceKlass* Carrier_klass; - ScopedValueBindingsResolver(JavaThread* THREAD) { - Klass *k = SystemDictionary::resolve_or_fail(vmSymbols::java_lang_ScopedValue_Carrier(), true, THREAD); - Carrier_klass = InstanceKlass::cast(k); - } -}; - JVM_ENTRY(jobject, JVM_FindScopedValueBindings(JNIEnv *env, jclass cls)) ResourceMark rm(THREAD); GrowableArray* local_array = new GrowableArray(12); JvmtiVMObjectAllocEventCollector oam; - static ScopedValueBindingsResolver resolver(THREAD); - // Iterate through Java frames vframeStream vfst(thread); for(; !vfst.at_end(); vfst.next()) { @@ -1239,7 +1228,7 @@ JVM_ENTRY(jobject, JVM_FindScopedValueBindings(JNIEnv *env, jclass cls)) InstanceKlass* holder = method->method_holder(); if (name == vmSymbols::runWith_method_name()) { if (holder == vmClasses::Thread_klass() - || holder == resolver.Carrier_klass) { + || holder == vmClasses::ScopedValue_Carrier_klass()) { loc = 1; } } From 9862f8f0d351448803f8930333d5a7286e6c3565 Mon Sep 17 00:00:00 2001 From: Christian Hagedorn Date: Wed, 17 Dec 2025 13:38:37 +0000 Subject: [PATCH 340/706] 8373513: C2: Move ProjNode::other_if_proj() to IfProjNode Reviewed-by: epeter, roland --- src/hotspot/share/opto/cfgnode.cpp | 4 +- src/hotspot/share/opto/cfgnode.hpp | 21 +++++---- src/hotspot/share/opto/ifnode.cpp | 57 +++++++++++++------------ src/hotspot/share/opto/library_call.cpp | 2 +- src/hotspot/share/opto/memnode.cpp | 2 +- src/hotspot/share/opto/multnode.cpp | 7 +-- src/hotspot/share/opto/multnode.hpp | 3 -- src/hotspot/share/opto/predicates.cpp | 4 +- 8 files changed, 49 insertions(+), 51 deletions(-) diff --git a/src/hotspot/share/opto/cfgnode.cpp b/src/hotspot/share/opto/cfgnode.cpp index 776a2d4c90b..ad5adfca8e5 100644 --- a/src/hotspot/share/opto/cfgnode.cpp +++ b/src/hotspot/share/opto/cfgnode.cpp @@ -933,8 +933,8 @@ bool RegionNode::optimize_trichotomy(PhaseIterGVN* igvn) { } // At this point we know that region->in(idx1) and region->(idx2) map to the same // value and control flow. Now search for ifs that feed into these region inputs. - ProjNode* proj1 = region->in(idx1)->isa_Proj(); - ProjNode* proj2 = region->in(idx2)->isa_Proj(); + IfProjNode* proj1 = region->in(idx1)->isa_IfProj(); + IfProjNode* proj2 = region->in(idx2)->isa_IfProj(); if (proj1 == nullptr || proj1->outcnt() != 1 || proj2 == nullptr || proj2->outcnt() != 1) { return false; // No projection inputs with region as unique user found diff --git a/src/hotspot/share/opto/cfgnode.hpp b/src/hotspot/share/opto/cfgnode.hpp index 5f7f4790443..fd40123078a 100644 --- a/src/hotspot/share/opto/cfgnode.hpp +++ b/src/hotspot/share/opto/cfgnode.hpp @@ -342,15 +342,15 @@ class IfNode : public MultiBranchNode { // Helper methods for fold_compares bool cmpi_folds(PhaseIterGVN* igvn, bool fold_ne = false); bool is_ctrl_folds(Node* ctrl, PhaseIterGVN* igvn); - bool has_shared_region(ProjNode* proj, ProjNode*& success, ProjNode*& fail); - bool has_only_uncommon_traps(ProjNode* proj, ProjNode*& success, ProjNode*& fail, PhaseIterGVN* igvn); - Node* merge_uncommon_traps(ProjNode* proj, ProjNode* success, ProjNode* fail, PhaseIterGVN* igvn); + bool has_shared_region(IfProjNode* proj, IfProjNode*& success, IfProjNode*& fail) const; + bool has_only_uncommon_traps(IfProjNode* proj, IfProjNode*& success, IfProjNode*& fail, PhaseIterGVN* igvn) const; + Node* merge_uncommon_traps(IfProjNode* proj, IfProjNode* success, IfProjNode* fail, PhaseIterGVN* igvn); static void improve_address_types(Node* l, Node* r, ProjNode* fail, PhaseIterGVN* igvn); - bool is_cmp_with_loadrange(ProjNode* proj); - 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); - bool fold_compares_helper(ProjNode* proj, ProjNode* success, ProjNode* fail, PhaseIterGVN* igvn); + bool is_cmp_with_loadrange(IfProjNode* proj) const; + bool is_null_check(IfProjNode* proj, PhaseIterGVN* igvn) const; + bool is_side_effect_free_test(IfProjNode* proj, PhaseIterGVN* igvn) const; + static void reroute_side_effect_free_unc(IfProjNode* proj, IfProjNode* dom_proj, PhaseIterGVN* igvn); + bool fold_compares_helper(IfProjNode* proj, IfProjNode* success, IfProjNode* fail, PhaseIterGVN* igvn); static bool is_dominator_unc(CallStaticJavaNode* dom_unc, CallStaticJavaNode* unc); protected: @@ -559,6 +559,11 @@ public: IfProjNode(IfNode *ifnode, uint idx) : CProjNode(ifnode,idx) {} virtual Node* Identity(PhaseGVN* phase); + // Return the other IfProj node. + IfProjNode* other_if_proj() const { + return in(0)->as_If()->proj_out(1 - _con)->as_IfProj(); + } + void pin_array_access_nodes(PhaseIterGVN* igvn); protected: diff --git a/src/hotspot/share/opto/ifnode.cpp b/src/hotspot/share/opto/ifnode.cpp index 763888b65b2..cd8017f9fb3 100644 --- a/src/hotspot/share/opto/ifnode.cpp +++ b/src/hotspot/share/opto/ifnode.cpp @@ -771,7 +771,7 @@ bool IfNode::cmpi_folds(PhaseIterGVN* igvn, bool fold_ne) { // Is a dominating control suitable for folding with this if? bool IfNode::is_ctrl_folds(Node* ctrl, PhaseIterGVN* igvn) { return ctrl != nullptr && - ctrl->is_Proj() && + ctrl->is_IfProj() && ctrl->outcnt() == 1 && // No side-effects ctrl->in(0) != nullptr && ctrl->in(0)->Opcode() == Op_If && @@ -784,8 +784,8 @@ bool IfNode::is_ctrl_folds(Node* ctrl, PhaseIterGVN* igvn) { } // Do this If and the dominating If share a region? -bool IfNode::has_shared_region(ProjNode* proj, ProjNode*& success, ProjNode*& fail) { - ProjNode* otherproj = proj->other_if_proj(); +bool IfNode::has_shared_region(IfProjNode* proj, IfProjNode*& success, IfProjNode*& fail) const { + IfProjNode* otherproj = proj->other_if_proj(); Node* otherproj_ctrl_use = otherproj->unique_ctrl_out_or_null(); RegionNode* region = (otherproj_ctrl_use != nullptr && otherproj_ctrl_use->is_Region()) ? otherproj_ctrl_use->as_Region() : nullptr; success = nullptr; @@ -793,13 +793,14 @@ bool IfNode::has_shared_region(ProjNode* proj, ProjNode*& success, ProjNode*& fa if (otherproj->outcnt() == 1 && region != nullptr && !region->has_phi()) { for (int i = 0; i < 2; i++) { - ProjNode* proj = proj_out(i); - if (success == nullptr && proj->outcnt() == 1 && proj->unique_out() == region) { - success = proj; + IfProjNode* next_proj = proj_out(i)->as_IfProj(); + if (success == nullptr && next_proj->outcnt() == 1 && next_proj->unique_out() == region) { + success = next_proj; } else if (fail == nullptr) { - fail = proj; + fail = next_proj; } else { - success = fail = nullptr; + success = nullptr; + fail = nullptr; } } } @@ -850,8 +851,8 @@ ProjNode* IfNode::uncommon_trap_proj(CallStaticJavaNode*& call, Deoptimization:: } // Do this If and the dominating If both branch out to an uncommon trap -bool IfNode::has_only_uncommon_traps(ProjNode* proj, ProjNode*& success, ProjNode*& fail, PhaseIterGVN* igvn) { - ProjNode* otherproj = proj->other_if_proj(); +bool IfNode::has_only_uncommon_traps(IfProjNode* proj, IfProjNode*& success, IfProjNode*& fail, PhaseIterGVN* igvn) const { + IfProjNode* otherproj = proj->other_if_proj(); CallStaticJavaNode* dom_unc = otherproj->is_uncommon_trap_proj(); if (otherproj->outcnt() == 1 && dom_unc != nullptr) { @@ -888,8 +889,8 @@ bool IfNode::has_only_uncommon_traps(ProjNode* proj, ProjNode*& success, ProjNod !igvn->C->too_many_traps(dom_method, dom_bci, Deoptimization::Reason_range_check) && // Return true if c2 manages to reconcile with UnstableIf optimization. See the comments for it. igvn->C->remove_unstable_if_trap(dom_unc, true/*yield*/)) { - success = unc_proj; - fail = unc_proj->other_if_proj(); + success = unc_proj->as_IfProj(); + fail = unc_proj->as_IfProj()->other_if_proj(); return true; } } @@ -898,7 +899,7 @@ bool IfNode::has_only_uncommon_traps(ProjNode* proj, ProjNode*& success, ProjNod } // Check that the 2 CmpI can be folded into as single CmpU and proceed with the folding -bool IfNode::fold_compares_helper(ProjNode* proj, ProjNode* success, ProjNode* fail, PhaseIterGVN* igvn) { +bool IfNode::fold_compares_helper(IfProjNode* proj, IfProjNode* success, IfProjNode* fail, PhaseIterGVN* igvn) { Node* this_cmp = in(1)->in(1); BoolNode* this_bool = in(1)->as_Bool(); IfNode* dom_iff = proj->in(0)->as_If(); @@ -906,7 +907,7 @@ bool IfNode::fold_compares_helper(ProjNode* proj, ProjNode* success, ProjNode* f Node* lo = dom_iff->in(1)->in(1)->in(2); Node* hi = this_cmp->in(2); Node* n = this_cmp->in(1); - ProjNode* otherproj = proj->other_if_proj(); + IfProjNode* otherproj = proj->other_if_proj(); const TypeInt* lo_type = IfNode::filtered_int_type(igvn, n, otherproj); const TypeInt* hi_type = IfNode::filtered_int_type(igvn, n, success); @@ -1108,11 +1109,11 @@ bool IfNode::fold_compares_helper(ProjNode* proj, ProjNode* success, ProjNode* f // Merge the branches that trap for this If and the dominating If into // a single region that branches to the uncommon trap for the // dominating If -Node* IfNode::merge_uncommon_traps(ProjNode* proj, ProjNode* success, ProjNode* fail, PhaseIterGVN* igvn) { +Node* IfNode::merge_uncommon_traps(IfProjNode* proj, IfProjNode* success, IfProjNode* fail, PhaseIterGVN* igvn) { Node* res = this; assert(success->in(0) == this, "bad projection"); - ProjNode* otherproj = proj->other_if_proj(); + IfProjNode* otherproj = proj->other_if_proj(); CallStaticJavaNode* unc = success->is_uncommon_trap_proj(); CallStaticJavaNode* dom_unc = otherproj->is_uncommon_trap_proj(); @@ -1239,7 +1240,7 @@ void IfNode::improve_address_types(Node* l, Node* r, ProjNode* fail, PhaseIterGV #endif } -bool IfNode::is_cmp_with_loadrange(ProjNode* proj) { +bool IfNode::is_cmp_with_loadrange(IfProjNode* proj) const { if (in(1) != nullptr && in(1)->in(1) != nullptr && in(1)->in(1)->in(2) != nullptr) { @@ -1258,7 +1259,7 @@ bool IfNode::is_cmp_with_loadrange(ProjNode* proj) { return false; } -bool IfNode::is_null_check(ProjNode* proj, PhaseIterGVN* igvn) { +bool IfNode::is_null_check(IfProjNode* proj, PhaseIterGVN* igvn) const { Node* other = in(1)->in(1)->in(2); if (other->in(MemNode::Address) != nullptr && proj->in(0)->in(1) != nullptr && @@ -1275,7 +1276,7 @@ bool IfNode::is_null_check(ProjNode* proj, PhaseIterGVN* igvn) { // Check that the If that is in between the 2 integer comparisons has // no side effect -bool IfNode::is_side_effect_free_test(ProjNode* proj, PhaseIterGVN* igvn) { +bool IfNode::is_side_effect_free_test(IfProjNode* proj, PhaseIterGVN* igvn) const { if (proj == nullptr) { return false; } @@ -1315,9 +1316,9 @@ bool IfNode::is_side_effect_free_test(ProjNode* proj, PhaseIterGVN* igvn) { // won't be guarded by the first CmpI anymore. It can trap in cases // where the first CmpI would have prevented it from executing: on a // trap, we need to restart execution at the state of the first CmpI -void IfNode::reroute_side_effect_free_unc(ProjNode* proj, ProjNode* dom_proj, PhaseIterGVN* igvn) { +void IfNode::reroute_side_effect_free_unc(IfProjNode* proj, IfProjNode* dom_proj, PhaseIterGVN* igvn) { CallStaticJavaNode* dom_unc = dom_proj->is_uncommon_trap_if_pattern(); - ProjNode* otherproj = proj->other_if_proj(); + IfProjNode* otherproj = proj->other_if_proj(); CallStaticJavaNode* unc = proj->is_uncommon_trap_if_pattern(); Node* call_proj = dom_unc->unique_ctrl_out(); Node* halt = call_proj->unique_ctrl_out(); @@ -1348,9 +1349,9 @@ Node* IfNode::fold_compares(PhaseIterGVN* igvn) { if (is_ctrl_folds(ctrl, igvn)) { // A integer comparison immediately dominated by another integer // comparison - ProjNode* success = nullptr; - ProjNode* fail = nullptr; - ProjNode* dom_cmp = ctrl->as_Proj(); + IfProjNode* success = nullptr; + IfProjNode* fail = nullptr; + IfProjNode* dom_cmp = ctrl->as_IfProj(); if (has_shared_region(dom_cmp, success, fail) && // Next call modifies graph so must be last fold_compares_helper(dom_cmp, success, fail, igvn)) { @@ -1364,11 +1365,11 @@ Node* IfNode::fold_compares(PhaseIterGVN* igvn) { return nullptr; } else if (ctrl->in(0) != nullptr && ctrl->in(0)->in(0) != nullptr) { - ProjNode* success = nullptr; - ProjNode* fail = nullptr; + IfProjNode* success = nullptr; + IfProjNode* fail = nullptr; Node* dom = ctrl->in(0)->in(0); - ProjNode* dom_cmp = dom->isa_Proj(); - ProjNode* other_cmp = ctrl->isa_Proj(); + IfProjNode* dom_cmp = dom->isa_IfProj(); + IfProjNode* other_cmp = ctrl->isa_IfProj(); // Check if it's an integer comparison dominated by another // integer comparison with another test in between diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index 2263fa720ce..a057f66a989 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -6171,7 +6171,7 @@ LibraryCallKit::tightly_coupled_allocation(Node* ptr) { CallStaticJavaNode* LibraryCallKit::get_uncommon_trap_from_success_proj(Node* node) { if (node->is_IfProj()) { - Node* other_proj = node->as_IfProj()->other_if_proj(); + IfProjNode* other_proj = node->as_IfProj()->other_if_proj(); for (DUIterator_Fast jmax, j = other_proj->fast_outs(jmax); j < jmax; j++) { Node* obs = other_proj->fast_out(j); if (obs->in(0) == other_proj && obs->is_CallStaticJava() && diff --git a/src/hotspot/share/opto/memnode.cpp b/src/hotspot/share/opto/memnode.cpp index 19ff90df5ed..5b76f5b42cf 100644 --- a/src/hotspot/share/opto/memnode.cpp +++ b/src/hotspot/share/opto/memnode.cpp @@ -3103,7 +3103,7 @@ MergePrimitiveStores::CFGStatus MergePrimitiveStores::cfg_status_for_pair(const ctrl_use->in(0)->outcnt() != 2) { return CFGStatus::Failure; // Not RangeCheck. } - ProjNode* other_proj = ctrl_use->as_IfProj()->other_if_proj(); + IfProjNode* other_proj = ctrl_use->as_IfProj()->other_if_proj(); Node* trap = other_proj->is_uncommon_trap_proj(Deoptimization::Reason_range_check); if (trap != merge_mem->unique_out() || ctrl_use->in(0)->in(0) != ctrl_def) { diff --git a/src/hotspot/share/opto/multnode.cpp b/src/hotspot/share/opto/multnode.cpp index 9409a2f6af3..05867a35268 100644 --- a/src/hotspot/share/opto/multnode.cpp +++ b/src/hotspot/share/opto/multnode.cpp @@ -260,12 +260,7 @@ CallStaticJavaNode* ProjNode::is_uncommon_trap_if_pattern(Deoptimization::DeoptR // Not a projection of an If or variation of a dead If node. return nullptr; } - return other_if_proj()->is_uncommon_trap_proj(reason); -} - -ProjNode* ProjNode::other_if_proj() const { - assert(_con == 0 || _con == 1, "not an if?"); - return in(0)->as_If()->proj_out(1-_con); + return as_IfProj()->other_if_proj()->is_uncommon_trap_proj(reason); } NarrowMemProjNode::NarrowMemProjNode(InitializeNode* src, const TypePtr* adr_type) diff --git a/src/hotspot/share/opto/multnode.hpp b/src/hotspot/share/opto/multnode.hpp index be1351cc5b1..692b69118c9 100644 --- a/src/hotspot/share/opto/multnode.hpp +++ b/src/hotspot/share/opto/multnode.hpp @@ -200,9 +200,6 @@ public: // other_proj->[region->..]call_uct" // null otherwise CallStaticJavaNode* is_uncommon_trap_if_pattern(Deoptimization::DeoptReason reason = Deoptimization::Reason_none) const; - - // Return other proj node when this is a If proj node - ProjNode* other_if_proj() const; }; // A ProjNode variant that captures an adr_type(). Used as a projection of InitializeNode to have the right adr_type() diff --git a/src/hotspot/share/opto/predicates.cpp b/src/hotspot/share/opto/predicates.cpp index 2489ff563a9..89bc4374ca6 100644 --- a/src/hotspot/share/opto/predicates.cpp +++ b/src/hotspot/share/opto/predicates.cpp @@ -65,7 +65,7 @@ bool AssertionPredicate::has_assertion_predicate_opaque(const Node* predicate_pr // Check if the other projection (UCT projection) of `success_proj` has a Halt node as output. bool AssertionPredicate::has_halt(const IfTrueNode* success_proj) { - ProjNode* other_proj = success_proj->other_if_proj(); + IfProjNode* other_proj = success_proj->other_if_proj(); return other_proj->outcnt() == 1 && other_proj->unique_out()->Opcode() == Op_Halt; } @@ -396,7 +396,7 @@ bool InitializedAssertionPredicate::is_predicate(const Node* maybe_success_proj) #ifdef ASSERT bool InitializedAssertionPredicate::has_halt(const IfTrueNode* success_proj) { - ProjNode* other_proj = success_proj->other_if_proj(); + IfProjNode* other_proj = success_proj->other_if_proj(); if (other_proj->outcnt() != 1) { return false; } From 4e05748f0899cabb235c71ecdf4256d4ad137a0d Mon Sep 17 00:00:00 2001 From: Justin Lu Date: Wed, 17 Dec 2025 18:17:24 +0000 Subject: [PATCH 341/706] 8373716: Refactor further java/util tests from TestNG to JUnit Reviewed-by: naoto --- .../Calendar/CalendarDisplayNamesTest.java | 12 +++--- .../util/Calendar/JapaneseLenientEraTest.java | 21 +++++----- .../SupplementalJapaneseEraTestRun.java | 16 ++++---- .../util/Properties/CompatibilityTest.java | 19 +++++----- .../java/util/Properties/EncodingTest.java | 18 +++++---- .../java/util/Properties/InitialCapacity.java | 14 ++++--- .../Properties/PropertiesEntrySetTest.java | 38 +++++++++---------- .../util/Properties/PropertiesStoreTest.java | 38 ++++++++++--------- .../modules/basic/BasicTest.java | 18 +++++---- .../modules/cache/CacheTest.java | 15 ++++---- .../CaseInsensitiveNameClash.java | 14 ++++--- .../modules/visibility/VisibilityTest.java | 36 +++++++++--------- .../java/util/TimeZone/NegativeDSTTest.java | 23 +++++------ .../util/TimeZone/ZoneIdRoundTripTest.java | 21 +++++----- 14 files changed, 162 insertions(+), 141 deletions(-) diff --git a/test/jdk/java/util/Calendar/CalendarDisplayNamesTest.java b/test/jdk/java/util/Calendar/CalendarDisplayNamesTest.java index 7c40714fc02..171bea55fcf 100644 --- a/test/jdk/java/util/Calendar/CalendarDisplayNamesTest.java +++ b/test/jdk/java/util/Calendar/CalendarDisplayNamesTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, 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 @@ -21,21 +21,21 @@ * questions. */ -import org.testng.Assert; -import org.testng.annotations.Test; import java.util.Calendar; import java.util.Locale; import java.util.Map; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; /** * @test * @bug 8262108 8174269 * @summary Verify the results returned by Calendar.getDisplayNames() API * @comment Locale providers: CLDR,SPI - * @run testng/othervm -Djava.locale.providers=CLDR,SPI CalendarDisplayNamesTest + * @run junit/othervm -Djava.locale.providers=CLDR,SPI CalendarDisplayNamesTest * @comment Locale providers: default - * @run testng CalendarDisplayNamesTest + * @run junit CalendarDisplayNamesTest */ public class CalendarDisplayNamesTest { @@ -55,7 +55,7 @@ public class CalendarDisplayNamesTest { continue; } for (final Integer fieldValue : names.values()) { - Assert.assertTrue(fieldValue == Calendar.AM || fieldValue == Calendar.PM, + Assertions.assertTrue(fieldValue == Calendar.AM || fieldValue == Calendar.PM, "Invalid field value " + fieldValue + " for calendar field AM_PM, in locale " + locale + " with style " + style); } diff --git a/test/jdk/java/util/Calendar/JapaneseLenientEraTest.java b/test/jdk/java/util/Calendar/JapaneseLenientEraTest.java index 6a909a23a18..ca726afc29b 100644 --- a/test/jdk/java/util/Calendar/JapaneseLenientEraTest.java +++ b/test/jdk/java/util/Calendar/JapaneseLenientEraTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, 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,7 +25,7 @@ * @test * @bug 8206120 * @summary Test whether lenient era is accepted in JapaneseImperialCalendar - * @run testng/othervm JapaneseLenientEraTest + * @run junit/othervm JapaneseLenientEraTest */ import java.text.DateFormat; @@ -34,15 +34,15 @@ import java.util.Calendar; import java.util.Date; import java.util.Locale; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; -import static org.testng.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; -@Test +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class JapaneseLenientEraTest { - @DataProvider(name="lenientEra") - Object[][] names() { + Object[][] lenientEra() { return new Object[][] { // lenient era/year, strict era/year { "Meiji 123", "Heisei 2" }, @@ -51,7 +51,8 @@ public class JapaneseLenientEraTest { }; } - @Test(dataProvider="lenientEra") + @ParameterizedTest + @MethodSource("lenientEra") public void testLenientEra(String lenient, String strict) throws Exception { Calendar c = new Calendar.Builder() .setCalendarType("japanese") @@ -61,6 +62,6 @@ public class JapaneseLenientEraTest { Date lenDate = df.parse(lenient + "-01-01"); df.setLenient(false); Date strDate = df.parse(strict + "-01-01"); - assertEquals(lenDate, strDate); + assertEquals(strDate, lenDate); } } diff --git a/test/jdk/java/util/Calendar/SupplementalJapaneseEraTestRun.java b/test/jdk/java/util/Calendar/SupplementalJapaneseEraTestRun.java index 8eac4a97ef7..878955fdcc4 100644 --- a/test/jdk/java/util/Calendar/SupplementalJapaneseEraTestRun.java +++ b/test/jdk/java/util/Calendar/SupplementalJapaneseEraTestRun.java @@ -27,7 +27,7 @@ * @summary Test for jdk.calendar.japanese.supplemental.era support * @library /test/lib * @build SupplementalJapaneseEraTest - * @run testng/othervm SupplementalJapaneseEraTestRun + * @run junit/othervm SupplementalJapaneseEraTestRun */ import java.util.Calendar; @@ -45,11 +45,12 @@ import static java.util.Calendar.YEAR; import jdk.test.lib.process.ProcessTools; import jdk.test.lib.Utils; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class SupplementalJapaneseEraTestRun { - @DataProvider(name = "validprop") Object[][] validPropertyData() { return new Object[][] { //Tests with valid property values @@ -58,7 +59,6 @@ public class SupplementalJapaneseEraTestRun { }; } - @DataProvider(name = "invalidprop") Object[][] invalidPropertyData() { return new Object[][] { //Tests with invalid property values @@ -76,7 +76,8 @@ public class SupplementalJapaneseEraTestRun { }; } - @Test(dataProvider = "validprop") + @ParameterizedTest + @MethodSource("validPropertyData") public void ValidPropertyValuesTest(String prop) throws Throwable { //get the start time of the fictional next era @@ -84,7 +85,8 @@ public class SupplementalJapaneseEraTestRun { testRun(prop + startTime, List.of("-t")); } - @Test(dataProvider = "invalidprop") + @ParameterizedTest + @MethodSource("invalidPropertyData") public void InvalidPropertyValuesTest(String prop) throws Throwable { //get the start time of the fictional next era diff --git a/test/jdk/java/util/Properties/CompatibilityTest.java b/test/jdk/java/util/Properties/CompatibilityTest.java index 29c7be6fbcd..839680806c1 100644 --- a/test/jdk/java/util/Properties/CompatibilityTest.java +++ b/test/jdk/java/util/Properties/CompatibilityTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, 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,19 +24,19 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.Properties; -import org.testng.Assert; - -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; /* * @test * @bug 8252354 - * @run testng CompatibilityTest + * @run junit CompatibilityTest * @summary Verify compatibility. */ +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class CompatibilityTest { - @DataProvider(name = "entries") public Object[][] getEntries() throws IOException { return new Object[][]{ {8, 238923}, @@ -53,9 +53,10 @@ public class CompatibilityTest { * @param value the value * @throws IOException */ - @Test(dataProvider = "entries") + @ParameterizedTest + @MethodSource("getEntries") void testThrows(Object key, Object value) throws IOException { - Assert.assertThrows(ClassCastException.class, () -> storeToXML(key, value)); + Assertions.assertThrows(ClassCastException.class, () -> storeToXML(key, value)); } void storeToXML(Object key, Object value) throws IOException { diff --git a/test/jdk/java/util/Properties/EncodingTest.java b/test/jdk/java/util/Properties/EncodingTest.java index d97730a37c7..069d16155f0 100644 --- a/test/jdk/java/util/Properties/EncodingTest.java +++ b/test/jdk/java/util/Properties/EncodingTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, 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,19 +27,20 @@ import java.io.IOException; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.Properties; -import org.testng.Assert; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; /** * @test * @bug 8183743 * @summary Test to verify the new overload method with Charset functions the * same as the existing method that takes a charset name. - * @run testng EncodingTest + * @run junit EncodingTest */ +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class EncodingTest { - @DataProvider(name = "parameters") public Object[][] getParameters() throws IOException { return new Object[][]{ {StandardCharsets.UTF_8.name(), null}, @@ -51,7 +52,8 @@ public class EncodingTest { * encoding name or a charset can be read with Properties#loadFromXML that * returns the same Properties object. */ - @Test(dataProvider = "parameters") + @ParameterizedTest + @MethodSource("getParameters") void testLoadAndStore(String encoding, Charset charset) throws IOException { Properties props = new Properties(); props.put("k0", "\u6C34"); @@ -74,6 +76,6 @@ public class EncodingTest { } } - Assert.assertEquals(props, p); + Assertions.assertEquals(p, props); } } diff --git a/test/jdk/java/util/Properties/InitialCapacity.java b/test/jdk/java/util/Properties/InitialCapacity.java index 81e5421bbef..d684c37adf4 100644 --- a/test/jdk/java/util/Properties/InitialCapacity.java +++ b/test/jdk/java/util/Properties/InitialCapacity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, 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,18 +22,22 @@ */ import java.util.Properties; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; /* * @test * @bug 8189319 * @summary Test that Properties(int initialCapacity) throws exceptions (or doesn't) as expected - * @run testng InitialCapacity + * @run junit InitialCapacity */ public class InitialCapacity { - @Test(expectedExceptions = IllegalArgumentException.class) - public void negativeInitCap() { Properties p = new Properties(-1); } + @Test + public void negativeInitCap() { Assertions.assertThrows(IllegalArgumentException.class, () -> { + Properties p = new Properties(-1); + }); +} @Test public void positiveInitCap() { Properties p = new Properties(10); } diff --git a/test/jdk/java/util/Properties/PropertiesEntrySetTest.java b/test/jdk/java/util/Properties/PropertiesEntrySetTest.java index d7d58be44dd..f3262f734e3 100644 --- a/test/jdk/java/util/Properties/PropertiesEntrySetTest.java +++ b/test/jdk/java/util/Properties/PropertiesEntrySetTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, 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,17 +26,17 @@ * @bug 8245694 * @summary tests the entrySet() method of Properties class * @author Yu Li - * @run testng PropertiesEntrySetTest + * @run junit PropertiesEntrySetTest */ -import org.testng.annotations.Test; import java.util.Properties; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertFalse; -import static org.testng.Assert.assertThrows; -import static org.testng.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.Test; public class PropertiesEntrySetTest { @@ -99,13 +99,13 @@ public class PropertiesEntrySetTest { public void testToString() { Properties a = new Properties(); var aEntrySet = a.entrySet(); - assertEquals(aEntrySet.toString(), "[]"); + assertEquals("[]", aEntrySet.toString()); a.setProperty("p1", "1"); - assertEquals(aEntrySet.toString(), "[p1=1]"); + assertEquals("[p1=1]", aEntrySet.toString()); a.setProperty("p2", "2"); - assertEquals(aEntrySet.size(), 2); + assertEquals(2, aEntrySet.size()); assertTrue(aEntrySet.toString().trim().startsWith("[")); assertTrue(aEntrySet.toString().contains("p1=1")); assertTrue(aEntrySet.toString().contains("p2=2")); @@ -115,18 +115,18 @@ public class PropertiesEntrySetTest { b.setProperty("p2", "2"); b.setProperty("p1", "1"); var bEntrySet = b.entrySet(); - assertEquals(bEntrySet.size(), 2); + assertEquals(2, bEntrySet.size()); assertTrue(bEntrySet.toString().trim().startsWith("[")); assertTrue(bEntrySet.toString().contains("p1=1")); assertTrue(bEntrySet.toString().contains("p2=2")); assertTrue(bEntrySet.toString().trim().endsWith("]")); b.setProperty("p0", "0"); - assertEquals(bEntrySet.size(), 3); + assertEquals(3, bEntrySet.size()); assertTrue(bEntrySet.toString().contains("p0=0")); b.remove("p1"); - assertEquals(bEntrySet.size(), 2); + assertEquals(2, bEntrySet.size()); assertFalse(bEntrySet.toString().contains("p1=1")); assertTrue(bEntrySet.toString().trim().startsWith("[")); assertTrue(bEntrySet.toString().contains("p0=0")); @@ -134,7 +134,7 @@ public class PropertiesEntrySetTest { assertTrue(bEntrySet.toString().trim().endsWith("]")); b.remove("p0", "0"); - assertEquals(bEntrySet.size(), 1); + assertEquals(1, bEntrySet.size()); assertFalse(bEntrySet.toString().contains("p0=0")); assertTrue(bEntrySet.toString().trim().startsWith("[")); assertTrue(bEntrySet.toString().contains("p2=2")); @@ -151,13 +151,13 @@ public class PropertiesEntrySetTest { a.setProperty("p1", "1"); a.setProperty("p2", "2"); var aEntrySet = a.entrySet(); - assertEquals(aEntrySet.size(), 2); + assertEquals(2, aEntrySet.size()); var i = aEntrySet.iterator(); var e1 = i.next(); i.remove(); assertFalse(aEntrySet.contains(e1)); - assertEquals(aEntrySet.size(), 1); + assertEquals(1, aEntrySet.size()); var e2 = i.next(); aEntrySet.remove(e2); @@ -172,14 +172,14 @@ public class PropertiesEntrySetTest { var bEntrySet = b.entrySet(); assertFalse(bEntrySet.containsAll(aEntrySet)); - assertEquals(bEntrySet.size(), 2); + assertEquals(2, bEntrySet.size()); assertTrue(bEntrySet.removeAll(aEntrySet)); - assertEquals(bEntrySet.size(), 1); + assertEquals(1, bEntrySet.size()); assertTrue(bEntrySet.retainAll(aEntrySet)); assertTrue(bEntrySet.isEmpty()); - assertEquals(aEntrySet.size(), 2); + assertEquals(2, aEntrySet.size()); aEntrySet.clear(); assertTrue(aEntrySet.isEmpty()); diff --git a/test/jdk/java/util/Properties/PropertiesStoreTest.java b/test/jdk/java/util/Properties/PropertiesStoreTest.java index b5a5b5a45aa..88c24698a14 100644 --- a/test/jdk/java/util/Properties/PropertiesStoreTest.java +++ b/test/jdk/java/util/Properties/PropertiesStoreTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, 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 @@ -21,9 +21,6 @@ * questions. */ -import org.testng.Assert; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import java.io.BufferedReader; import java.io.IOException; @@ -45,13 +42,18 @@ import java.util.Properties; import java.util.Set; import java.util.TreeSet; import java.util.stream.Collectors; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; /* * @test * @summary tests the order in which the Properties.store() method writes out the properties * @bug 8231640 8282023 - * @run testng/othervm PropertiesStoreTest + * @run junit/othervm PropertiesStoreTest */ +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class PropertiesStoreTest { private static final String DATE_FORMAT_PATTERN = "EEE MMM dd HH:mm:ss zzz uuuu"; @@ -60,7 +62,6 @@ public class PropertiesStoreTest { private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern(DATE_FORMAT_PATTERN, Locale.US); private static final Locale PREV_LOCALE = Locale.getDefault(); - @DataProvider(name = "propsProvider") private Object[][] createProps() { final Properties simple = new Properties(); simple.setProperty("1", "one"); @@ -101,7 +102,6 @@ public class PropertiesStoreTest { /** * Returns a {@link Locale} to use for testing */ - @DataProvider(name = "localeProvider") private Object[][] provideLocales() { // pick a non-english locale for testing Set locales = Arrays.stream(Locale.getAvailableLocales()) @@ -122,7 +122,8 @@ public class PropertiesStoreTest { * Tests that the {@link Properties#store(Writer, String)} API writes out the properties * in the expected order */ - @Test(dataProvider = "propsProvider") + @ParameterizedTest + @MethodSource("createProps") public void testStoreWriterKeyOrder(final Properties props, final String[] expectedOrder) throws Exception { // Properties.store(...) to a temp file final Path tmpFile = Files.createTempFile("8231640", "props"); @@ -136,7 +137,8 @@ public class PropertiesStoreTest { * Tests that the {@link Properties#store(OutputStream, String)} API writes out the properties * in the expected order */ - @Test(dataProvider = "propsProvider") + @ParameterizedTest + @MethodSource("createProps") public void testStoreOutputStreamKeyOrder(final Properties props, final String[] expectedOrder) throws Exception { // Properties.store(...) to a temp file final Path tmpFile = Files.createTempFile("8231640", "props"); @@ -161,7 +163,7 @@ public class PropertiesStoreTest { try (final InputStream is = Files.newInputStream(storedProps)) { loaded.load(is); } - Assert.assertEquals(loaded, props, "Unexpected properties loaded from stored state"); + Assertions.assertEquals(props, loaded, "Unexpected properties loaded from stored state"); // now read lines from the stored file and keep track of the order in which the keys were // found in that file. Compare that order with the expected store order of the keys. @@ -169,10 +171,10 @@ public class PropertiesStoreTest { try (final BufferedReader reader = Files.newBufferedReader(storedProps)) { actualOrder = readInOrder(reader); } - Assert.assertEquals(actualOrder.size(), expectedOrder.length, + Assertions.assertEquals(expectedOrder.length, actualOrder.size(), "Unexpected number of keys read from stored properties"); if (!Arrays.equals(actualOrder.toArray(new String[0]), expectedOrder)) { - Assert.fail("Unexpected order of stored property keys. Expected order: " + Arrays.toString(expectedOrder) + Assertions.fail("Unexpected order of stored property keys. Expected order: " + Arrays.toString(expectedOrder) + ", found order: " + actualOrder); } } @@ -180,7 +182,8 @@ public class PropertiesStoreTest { /** * Tests that {@link Properties#store(Writer, String)} writes out a proper date comment */ - @Test(dataProvider = "localeProvider") + @ParameterizedTest + @MethodSource("provideLocales") public void testStoreWriterDateComment(final Locale testLocale) throws Exception { // switch the default locale to the one being tested Locale.setDefault(testLocale); @@ -202,7 +205,8 @@ public class PropertiesStoreTest { /** * Tests that {@link Properties#store(OutputStream, String)} writes out a proper date comment */ - @Test(dataProvider = "localeProvider") + @ParameterizedTest + @MethodSource("provideLocales") public void testStoreOutputStreamDateComment(final Locale testLocale) throws Exception { // switch the default locale to the one being tested Locale.setDefault(testLocale); @@ -232,19 +236,19 @@ public class PropertiesStoreTest { while ((line = reader.readLine()) != null) { if (line.startsWith("#")) { if (comment != null) { - Assert.fail("More than one comment line found in the stored properties file " + file); + Assertions.fail("More than one comment line found in the stored properties file " + file); } comment = line.substring(1); } } } if (comment == null) { - Assert.fail("No comment line found in the stored properties file " + file); + Assertions.fail("No comment line found in the stored properties file " + file); } try { FORMATTER.parse(comment); } catch (DateTimeParseException pe) { - Assert.fail("Unexpected date comment: " + comment, pe); + Assertions.fail("Unexpected date comment: " + comment, pe); } } diff --git a/test/jdk/java/util/ResourceBundle/modules/basic/BasicTest.java b/test/jdk/java/util/ResourceBundle/modules/basic/BasicTest.java index 69f0db83258..c17c4622ecb 100644 --- a/test/jdk/java/util/ResourceBundle/modules/basic/BasicTest.java +++ b/test/jdk/java/util/ResourceBundle/modules/basic/BasicTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, 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 @@ * jdk.test.lib.compiler.CompilerUtils * jdk.test.lib.process.ProcessTools * ModuleTestUtil - * @run testng BasicTest + * @run junit BasicTest */ import java.nio.file.Path; @@ -54,13 +54,15 @@ import jdk.test.lib.JDKToolLauncher; import jdk.test.lib.Utils; import jdk.test.lib.compiler.CompilerUtils; import jdk.test.lib.process.ProcessTools; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import static jdk.test.lib.Asserts.assertEquals; -import static org.testng.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; -@Test +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class BasicTest { private static final String SRC_DIR_APPBASIC = "srcAppbasic"; private static final String SRC_DIR_APPBASIC2 = "srcAppbasic2"; @@ -92,7 +94,6 @@ public class BasicTest { private static final String MAIN = "test/jdk.test.Main"; - @DataProvider(name = "basicTestData") Object[][] basicTestData() { return new Object[][] { // Named module "test" contains resource bundles for root and en, @@ -122,7 +123,8 @@ public class BasicTest { }; } - @Test(dataProvider = "basicTestData") + @ParameterizedTest + @MethodSource("basicTestData") public void runBasicTest(String src, String mod, List moduleList, List localeList, String resFormat) throws Throwable { Path srcPath = Paths.get(Utils.TEST_SRC, src); diff --git a/test/jdk/java/util/ResourceBundle/modules/cache/CacheTest.java b/test/jdk/java/util/ResourceBundle/modules/cache/CacheTest.java index 5655eb5de2d..df72af38855 100644 --- a/test/jdk/java/util/ResourceBundle/modules/cache/CacheTest.java +++ b/test/jdk/java/util/ResourceBundle/modules/cache/CacheTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, 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,7 +27,7 @@ * @library /test/lib * @modules jdk.compiler * @build CacheTest jdk.test.lib.compiler.CompilerUtils - * @run testng CacheTest + * @run junit CacheTest */ import java.nio.file.Files; @@ -37,11 +37,12 @@ import java.nio.file.Paths; import static jdk.test.lib.process.ProcessTools.*; import jdk.test.lib.compiler.CompilerUtils; -import org.testng.annotations.BeforeTest; -import org.testng.annotations.Test; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; -@Test +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class CacheTest { private static final String TEST_SRC = System.getProperty("test.src"); @@ -55,7 +56,7 @@ public class CacheTest { private static final String MAIN = "test/jdk.test.Main"; private static final String MAIN_CLASS = "jdk.test.Main"; - @BeforeTest + @BeforeAll public void compileTestModules() throws Exception { for (String mn : new String[] {MAIN_BUNDLES_MODULE, TEST_MODULE}) { diff --git a/test/jdk/java/util/ResourceBundle/modules/casesensitive/CaseInsensitiveNameClash.java b/test/jdk/java/util/ResourceBundle/modules/casesensitive/CaseInsensitiveNameClash.java index 914ebf6bbf0..45f52b512c8 100644 --- a/test/jdk/java/util/ResourceBundle/modules/casesensitive/CaseInsensitiveNameClash.java +++ b/test/jdk/java/util/ResourceBundle/modules/casesensitive/CaseInsensitiveNameClash.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, 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,7 +28,7 @@ * @modules jdk.compiler * @build jdk.test.lib.compiler.CompilerUtils * jdk.test.lib.process.ProcessTools CaseInsensitiveNameClash - * @run testng CaseInsensitiveNameClash + * @run junit CaseInsensitiveNameClash */ import java.nio.file.Files; @@ -37,10 +37,12 @@ import java.nio.file.Paths; import jdk.test.lib.process.ProcessTools; import jdk.test.lib.compiler.CompilerUtils; -import org.testng.annotations.BeforeTest; -import org.testng.annotations.Test; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class CaseInsensitiveNameClash { private static final String TEST_SRC = System.getProperty("test.src"); @@ -54,7 +56,7 @@ public class CaseInsensitiveNameClash { /** * Compiles the module used by the test */ - @BeforeTest + @BeforeAll public void compileAll() throws Exception { Path msrc = SRC_DIR.resolve(MODULE); assertTrue(CompilerUtils.compile(msrc, MODS_DIR, diff --git a/test/jdk/java/util/ResourceBundle/modules/visibility/VisibilityTest.java b/test/jdk/java/util/ResourceBundle/modules/visibility/VisibilityTest.java index e0fdb9a93ab..ee9da88d705 100644 --- a/test/jdk/java/util/ResourceBundle/modules/visibility/VisibilityTest.java +++ b/test/jdk/java/util/ResourceBundle/modules/visibility/VisibilityTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, 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 @@ * jdk.test.lib.compiler.CompilerUtils * jdk.test.lib.process.ProcessTools * ModuleTestUtil - * @run testng VisibilityTest + * @run junit VisibilityTest */ import java.nio.file.Path; @@ -46,13 +46,13 @@ import jdk.test.lib.JDKToolLauncher; import jdk.test.lib.Utils; import jdk.test.lib.process.ProcessTools; -import org.testng.annotations.BeforeTest; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; -import static org.testng.Assert.assertEquals; - -@Test +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class VisibilityTest { private static final Path SRC_DIR = Paths.get(Utils.TEST_SRC, "src"); private static final Path MODS_DIR = Paths.get(Utils.TEST_CLASSES, "mods"); @@ -63,7 +63,7 @@ public class VisibilityTest { private static final List MODULE_LIST = List.of("embargo", "exported.named.bundles", "named.bundles", "test"); - @BeforeTest + @BeforeAll public void prepareTestEnv() throws Throwable { MODULE_LIST.forEach(mn -> ModuleTestUtil.prepareModule(SRC_DIR, MODS_DIR, mn, ".properties")); @@ -93,7 +93,6 @@ public class VisibilityTest { * "exported.named.bundle" are exported to unnamed modules. */ - @DataProvider(name = "RunWithTestResData") Object[][] RunWithTestResData() { return new Object[][] { // Tests using jdk.test.TestWithNoModuleArg and jdk.embargo.TestWithNoModuleArg. @@ -188,7 +187,6 @@ public class VisibilityTest { }; } - @DataProvider(name = "RunWithExportedResData") Object[][] RunWithExportedResData() { return new Object[][] { // Tests using jdk.test.TestWithNoModuleArg and jdk.embargo.TestWithNoModuleArg @@ -285,7 +283,6 @@ public class VisibilityTest { }; } - @DataProvider(name = "RunWithPkgResData") Object[][] RunWithPkgResData() { return new Object[][] { // jdk.pkg.resources.* are in an unnamed module. @@ -300,10 +297,11 @@ public class VisibilityTest { /** * Test cases with jdk.test.resources.* */ - @Test(dataProvider = "RunWithTestResData") + @ParameterizedTest + @MethodSource("RunWithTestResData") public void RunWithTestRes(List argsList) throws Throwable { int exitCode = runCmd(argsList); - assertEquals(exitCode, 0, "Execution of the tests with " + assertEquals(0, exitCode, "Execution of the tests with " + "jdk.test.resources.* failed. " + "Unexpected exit code: " + exitCode); } @@ -311,10 +309,11 @@ public class VisibilityTest { /** * Test cases with jdk.test.resources.exported.* */ - @Test(dataProvider = "RunWithExportedResData") + @ParameterizedTest + @MethodSource("RunWithExportedResData") public void RunWithExportedRes(List argsList) throws Throwable { int exitCode = runCmd(argsList); - assertEquals(exitCode, 0, "Execution of the tests with " + assertEquals(0, exitCode, "Execution of the tests with " + "jdk.test.resources.exported.* failed. " + "Unexpected exit code: " + exitCode); } @@ -322,10 +321,11 @@ public class VisibilityTest { /** * Test cases with jdk.pkg.resources.* */ - @Test(dataProvider = "RunWithPkgResData") + @ParameterizedTest + @MethodSource("RunWithPkgResData") public void RunWithPkgRes(List argsList) throws Throwable { int exitCode = runCmd(argsList); - assertEquals(exitCode, 0, "Execution of the tests with " + assertEquals(0, exitCode, "Execution of the tests with " + "jdk.pkg.resources.* failed. " + "Unexpected exit code: " + exitCode); } diff --git a/test/jdk/java/util/TimeZone/NegativeDSTTest.java b/test/jdk/java/util/TimeZone/NegativeDSTTest.java index eb46b8d4b29..ab9438f2388 100644 --- a/test/jdk/java/util/TimeZone/NegativeDSTTest.java +++ b/test/jdk/java/util/TimeZone/NegativeDSTTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, 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 @@ -21,7 +21,7 @@ * questions. */ -import static org.testng.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; import java.time.Instant; import java.time.LocalDate; @@ -31,18 +31,19 @@ import java.time.ZoneId; import java.util.Date; import java.util.TimeZone; -import org.testng.annotations.Test; -import org.testng.annotations.DataProvider; -import static org.testng.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; /** * @test * @bug 8212970 8324065 * @summary Test whether the savings are positive in time zones that have * negative savings in the source TZ files. - * @run testng NegativeDSTTest + * @run junit NegativeDSTTest */ -@Test +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class NegativeDSTTest { private static final TimeZone DUBLIN = TimeZone.getTimeZone("Europe/Dublin"); @@ -51,7 +52,6 @@ public class NegativeDSTTest { private static final TimeZone CASABLANCA = TimeZone.getTimeZone("Africa/Casablanca"); private static final int ONE_HOUR = 3600_000; - @DataProvider private Object[][] negativeDST () { return new Object[][] { // TimeZone, localDate, offset, isDaylightSavings @@ -88,10 +88,11 @@ public class NegativeDSTTest { }; } - @Test(dataProvider="negativeDST") + @ParameterizedTest + @MethodSource("negativeDST") public void test_NegativeDST(TimeZone tz, LocalDate ld, int offset, boolean isDST) { Date d = Date.from(Instant.from(ZonedDateTime.of(ld, LocalTime.MIN, tz.toZoneId()))); - assertEquals(tz.getOffset(d.getTime()), offset); - assertEquals(tz.inDaylightTime(d), isDST); + assertEquals(offset, tz.getOffset(d.getTime())); + assertEquals(isDST, tz.inDaylightTime(d)); } } diff --git a/test/jdk/java/util/TimeZone/ZoneIdRoundTripTest.java b/test/jdk/java/util/TimeZone/ZoneIdRoundTripTest.java index 0f1eeb88328..16e24f7cb27 100644 --- a/test/jdk/java/util/TimeZone/ZoneIdRoundTripTest.java +++ b/test/jdk/java/util/TimeZone/ZoneIdRoundTripTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, 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,20 +25,20 @@ import java.time.ZoneId; import java.time.ZoneOffset; import java.util.TimeZone; -import org.testng.annotations.Test; -import org.testng.annotations.DataProvider; -import static org.testng.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; /** * @test * @bug 8285844 * @summary Checks round-trips between TimeZone and ZoneId are consistent - * @run testng ZoneIdRoundTripTest + * @run junit ZoneIdRoundTripTest */ -@Test +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class ZoneIdRoundTripTest { - @DataProvider private Object[][] testZoneIds() { return new Object[][] { {ZoneId.of("Z"), 0}, @@ -60,11 +60,12 @@ public class ZoneIdRoundTripTest { }; } - @Test(dataProvider="testZoneIds") + @ParameterizedTest + @MethodSource("testZoneIds") public void test_ZoneIdRoundTrip(ZoneId zid, int offset) { var tz = TimeZone.getTimeZone(zid); - assertEquals(tz.getRawOffset(), offset); - assertEquals(tz.toZoneId().normalized(), zid.normalized()); + assertEquals(offset, tz.getRawOffset()); + assertEquals(zid.normalized(), tz.toZoneId().normalized()); } } From f3a48560b5e3a280f6f76031eb3d475ff9ee49f4 Mon Sep 17 00:00:00 2001 From: Daniel Fuchs Date: Wed, 17 Dec 2025 18:44:49 +0000 Subject: [PATCH 342/706] 8373807: test/jdk/java/net/httpclient/websocket/DummyWebSocketServer.java getURI() uses "localhost" Reviewed-by: jpai --- .../net/httpclient/websocket/DummyWebSocketServer.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/test/jdk/java/net/httpclient/websocket/DummyWebSocketServer.java b/test/jdk/java/net/httpclient/websocket/DummyWebSocketServer.java index 9034cf9f28a..abc1748e3f2 100644 --- a/test/jdk/java/net/httpclient/websocket/DummyWebSocketServer.java +++ b/test/jdk/java/net/httpclient/websocket/DummyWebSocketServer.java @@ -351,7 +351,14 @@ public class DummyWebSocketServer implements Closeable { if (!started.get()) { throw new IllegalStateException("Not yet started"); } - return URI.create("ws://localhost:" + address.getPort()); + String ip = address.getAddress().isAnyLocalAddress() + ? InetAddress.getLoopbackAddress().getHostAddress() + : address.getAddress().getHostAddress(); + if (ip.indexOf(':') >= 0) { + ip = String.format("[%s]", ip); + } + + return URI.create("ws://" + ip + ":" + address.getPort()); } private boolean readRequest(SocketChannel channel, StringBuilder request) From e75726ee03ca4664827ca5d680c02bcf2a96f4ea Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Wed, 17 Dec 2025 20:52:14 +0000 Subject: [PATCH 343/706] 8373832: Test java/lang/invoke/TestVHInvokerCaching.java tests nothing Reviewed-by: jvernee, shade --- test/jdk/java/lang/invoke/TestVHInvokerCaching.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/test/jdk/java/lang/invoke/TestVHInvokerCaching.java b/test/jdk/java/lang/invoke/TestVHInvokerCaching.java index ccd97f82e9b..0a1ae5914ca 100644 --- a/test/jdk/java/lang/invoke/TestVHInvokerCaching.java +++ b/test/jdk/java/lang/invoke/TestVHInvokerCaching.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, 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,7 +37,7 @@ import java.util.ArrayList; import java.util.List; import static java.lang.invoke.MethodHandles.lookup; -import static org.testng.Assert.assertSame; +import static org.testng.Assert.*; public class TestVHInvokerCaching { @@ -74,7 +74,7 @@ public class TestVHInvokerCaching { MethodHandles.Lookup lookup = lookup(); - for (Field field : Holder.class.getFields()) { + for (Field field : Holder.class.getDeclaredFields()) { String fieldName = field.getName(); Class fieldType = field.getType(); @@ -82,6 +82,8 @@ public class TestVHInvokerCaching { testHandles.add(lookup.findVarHandle(Holder.class, fieldName, fieldType)); } + assertFalse(testHandles.isEmpty()); + return testHandles.stream().map(vh -> new Object[]{ vh }).toArray(Object[][]::new); } } From b3fab41460eabf253879d140b55b6b12036c7c10 Mon Sep 17 00:00:00 2001 From: David Holmes Date: Wed, 17 Dec 2025 22:14:39 +0000 Subject: [PATCH 344/706] 8373654: Tests in sources/ should only run once Reviewed-by: shade, lmesnik --- test/hotspot/jtreg/sources/TestIncludesAreSorted.java | 2 ++ test/hotspot/jtreg/sources/TestNoNULL.java | 2 ++ 2 files changed, 4 insertions(+) diff --git a/test/hotspot/jtreg/sources/TestIncludesAreSorted.java b/test/hotspot/jtreg/sources/TestIncludesAreSorted.java index e0e77992ace..f8694da6c5a 100644 --- a/test/hotspot/jtreg/sources/TestIncludesAreSorted.java +++ b/test/hotspot/jtreg/sources/TestIncludesAreSorted.java @@ -24,6 +24,8 @@ /* * @test * @bug 8343802 + * @comment Only need to run this once, in tier1. + * @requires vm.flagless & vm.debug * @summary Tests that HotSpot C++ files have sorted includes * @build SortIncludes * @run main TestIncludesAreSorted diff --git a/test/hotspot/jtreg/sources/TestNoNULL.java b/test/hotspot/jtreg/sources/TestNoNULL.java index 9c993572aea..b914ea6c799 100644 --- a/test/hotspot/jtreg/sources/TestNoNULL.java +++ b/test/hotspot/jtreg/sources/TestNoNULL.java @@ -24,6 +24,8 @@ /* * @test * @bug 8343802 + * @comment Only need to run this once, in tier1. + * @requires vm.flagless & vm.debug * @summary Test prevent NULL backsliding in hotspot code and tests * @run main TestNoNULL */ From 232b41b2227bc9d03d88d316aa28d0cbe87086f7 Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Wed, 17 Dec 2025 22:16:38 +0000 Subject: [PATCH 345/706] 8373392: Replace CDS object subgraphs with @AOTSafeClassInitializer Reviewed-by: liach, heidinga --- src/hotspot/share/cds/aotArtifactFinder.cpp | 6 +- src/hotspot/share/cds/aotClassInitializer.cpp | 6 +- src/hotspot/share/cds/aotMetaspace.cpp | 2 +- src/hotspot/share/cds/cdsConfig.cpp | 10 +- src/hotspot/share/cds/cdsConfig.hpp | 1 - src/hotspot/share/cds/cdsEnumKlass.cpp | 4 +- src/hotspot/share/cds/cdsEnumKlass.hpp | 2 +- src/hotspot/share/cds/cdsHeapVerifier.cpp | 2 +- src/hotspot/share/cds/finalImageRecipes.cpp | 2 + src/hotspot/share/cds/heapShared.cpp | 48 ++-- .../share/classes/java/lang/Byte.java | 2 + .../share/classes/java/lang/Character.java | 2 + .../share/classes/java/lang/Integer.java | 75 +++-- .../share/classes/java/lang/Long.java | 2 + .../share/classes/java/lang/Module.java | 2 + .../share/classes/java/lang/ModuleLayer.java | 2 + .../share/classes/java/lang/Short.java | 2 + .../java/lang/module/Configuration.java | 2 + .../java/util/ImmutableCollections.java | 15 +- .../classes/java/util/jar/Attributes.java | 4 + .../internal/loader/ArchivedClassLoaders.java | 2 + .../jdk/internal/math/FDBigInteger.java | 3 + .../internal/module/ArchivedBootLayer.java | 4 +- .../internal/module/ArchivedModuleGraph.java | 5 +- .../classes/sun/util/locale/BaseLocale.java | 14 +- test/hotspot/jtreg/TEST.groups | 1 + .../cds/SharedSymbolTableBucketSize.java | 44 ++- .../cds/appcds/aotCache/AOTLoggingTag.java | 11 - .../appcds/aotCache/HeapObjectIdentity.java | 261 ++++++++++++++++++ .../cacheObject/ArchiveHeapTestClass.java | 156 +---------- 30 files changed, 456 insertions(+), 236 deletions(-) create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/aotCache/HeapObjectIdentity.java diff --git a/src/hotspot/share/cds/aotArtifactFinder.cpp b/src/hotspot/share/cds/aotArtifactFinder.cpp index 5f346e832a8..f85f1e46520 100644 --- a/src/hotspot/share/cds/aotArtifactFinder.cpp +++ b/src/hotspot/share/cds/aotArtifactFinder.cpp @@ -145,7 +145,7 @@ void AOTArtifactFinder::find_artifacts() { #if INCLUDE_CDS_JAVA_HEAP // Keep scanning until we discover no more class that need to be AOT-initialized. - if (CDSConfig::is_initing_classes_at_dump_time()) { + if (CDSConfig::is_dumping_aot_linked_classes()) { while (_pending_aot_inited_classes->length() > 0) { InstanceKlass* ik = _pending_aot_inited_classes->pop(); HeapShared::copy_and_rescan_aot_inited_mirror(ik); @@ -188,7 +188,7 @@ void AOTArtifactFinder::end_scanning_for_oops() { } void AOTArtifactFinder::add_aot_inited_class(InstanceKlass* ik) { - if (CDSConfig::is_initing_classes_at_dump_time()) { + if (CDSConfig::is_dumping_aot_linked_classes()) { if (RegeneratedClasses::is_regenerated_object(ik)) { precond(RegeneratedClasses::get_original_object(ik)->is_initialized()); } else { @@ -258,7 +258,7 @@ void AOTArtifactFinder::add_cached_instance_class(InstanceKlass* ik) { return; } scan_oops_in_instance_class(ik); - if (ik->is_hidden() && CDSConfig::is_initing_classes_at_dump_time()) { + if (ik->is_hidden() && CDSConfig::is_dumping_aot_linked_classes()) { bool succeed = AOTClassLinker::try_add_candidate(ik); guarantee(succeed, "All cached hidden classes must be aot-linkable"); add_aot_inited_class(ik); diff --git a/src/hotspot/share/cds/aotClassInitializer.cpp b/src/hotspot/share/cds/aotClassInitializer.cpp index 00db747622f..06fc3af6f30 100644 --- a/src/hotspot/share/cds/aotClassInitializer.cpp +++ b/src/hotspot/share/cds/aotClassInitializer.cpp @@ -40,7 +40,7 @@ DEBUG_ONLY(InstanceKlass* _aot_init_class = nullptr;) bool AOTClassInitializer::can_archive_initialized_mirror(InstanceKlass* ik) { assert(!ArchiveBuilder::is_active() || !ArchiveBuilder::current()->is_in_buffer_space(ik), "must be source klass"); - if (!CDSConfig::is_initing_classes_at_dump_time()) { + if (!CDSConfig::is_dumping_aot_linked_classes()) { return false; } @@ -64,7 +64,7 @@ bool AOTClassInitializer::can_archive_initialized_mirror(InstanceKlass* ik) { // Automatic selection for aot-inited classes // ========================================== // - // When CDSConfig::is_initing_classes_at_dump_time is enabled, + // When CDSConfig::is_dumping_aot_linked_classes is enabled, // AOTArtifactFinder::find_artifacts() finds the classes of all // heap objects that are reachable from HeapShared::_run_time_special_subgraph, // and mark these classes as aot-inited. This preserves the initialized @@ -310,7 +310,7 @@ void AOTClassInitializer::init_test_class(TRAPS) { // // -XX:AOTInitTestClass is NOT a general mechanism for including user-defined objects into // the AOT cache. Therefore, this option is NOT available in product JVM. - if (AOTInitTestClass != nullptr && CDSConfig::is_initing_classes_at_dump_time()) { + if (AOTInitTestClass != nullptr && CDSConfig::is_dumping_aot_linked_classes()) { log_info(aot)("Debug build only: force initialization of AOTInitTestClass %s", AOTInitTestClass); TempNewSymbol class_name = SymbolTable::new_symbol(AOTInitTestClass); Handle app_loader(THREAD, SystemDictionary::java_system_loader()); diff --git a/src/hotspot/share/cds/aotMetaspace.cpp b/src/hotspot/share/cds/aotMetaspace.cpp index 098d3baed58..3824a2be3e2 100644 --- a/src/hotspot/share/cds/aotMetaspace.cpp +++ b/src/hotspot/share/cds/aotMetaspace.cpp @@ -1141,7 +1141,7 @@ void AOTMetaspace::dump_static_archive_impl(StaticArchiveBuilder& builder, TRAPS AOTReferenceObjSupport::initialize(CHECK); AOTReferenceObjSupport::stabilize_cached_reference_objects(CHECK); - if (CDSConfig::is_initing_classes_at_dump_time()) { + if (CDSConfig::is_dumping_aot_linked_classes()) { // java.lang.Class::reflectionFactory cannot be archived yet. We set this field // to null, and it will be initialized again at runtime. log_debug(aot)("Resetting Class::reflectionFactory"); diff --git a/src/hotspot/share/cds/cdsConfig.cpp b/src/hotspot/share/cds/cdsConfig.cpp index 86533e212d8..5f6b568dd6e 100644 --- a/src/hotspot/share/cds/cdsConfig.cpp +++ b/src/hotspot/share/cds/cdsConfig.cpp @@ -1026,23 +1026,19 @@ void CDSConfig::set_has_aot_linked_classes(bool has_aot_linked_classes) { _has_aot_linked_classes |= has_aot_linked_classes; } -bool CDSConfig::is_initing_classes_at_dump_time() { - return is_dumping_heap() && is_dumping_aot_linked_classes(); -} - bool CDSConfig::is_dumping_invokedynamic() { // Requires is_dumping_aot_linked_classes(). Otherwise the classes of some archived heap // objects used by the archive indy callsites may be replaced at runtime. return AOTInvokeDynamicLinking && is_dumping_aot_linked_classes() && is_dumping_heap(); } -// When we are dumping aot-linked classes and we are able to write archived heap objects, we automatically -// enable the archiving of MethodHandles. This will in turn enable the archiving of MethodTypes and hidden +// When we are dumping aot-linked classes, we automatically enable the archiving of MethodHandles. +// This will in turn enable the archiving of MethodTypes and hidden // classes that are used in the implementation of MethodHandles. // Archived MethodHandles are required for higher-level optimizations such as AOT resolution of invokedynamic // and dynamic proxies. bool CDSConfig::is_dumping_method_handles() { - return is_initing_classes_at_dump_time(); + return is_dumping_aot_linked_classes(); } #endif // INCLUDE_CDS_JAVA_HEAP diff --git a/src/hotspot/share/cds/cdsConfig.hpp b/src/hotspot/share/cds/cdsConfig.hpp index d199e97eefd..202904e8231 100644 --- a/src/hotspot/share/cds/cdsConfig.hpp +++ b/src/hotspot/share/cds/cdsConfig.hpp @@ -187,7 +187,6 @@ public: static void disable_heap_dumping() { CDS_ONLY(_disable_heap_dumping = true); } static bool is_dumping_heap() NOT_CDS_JAVA_HEAP_RETURN_(false); static bool is_loading_heap() NOT_CDS_JAVA_HEAP_RETURN_(false); - static bool is_initing_classes_at_dump_time() NOT_CDS_JAVA_HEAP_RETURN_(false); static bool is_dumping_invokedynamic() NOT_CDS_JAVA_HEAP_RETURN_(false); static bool is_dumping_method_handles() NOT_CDS_JAVA_HEAP_RETURN_(false); diff --git a/src/hotspot/share/cds/cdsEnumKlass.cpp b/src/hotspot/share/cds/cdsEnumKlass.cpp index 1bf6ba4eba8..177d1d6e3ad 100644 --- a/src/hotspot/share/cds/cdsEnumKlass.cpp +++ b/src/hotspot/share/cds/cdsEnumKlass.cpp @@ -40,7 +40,7 @@ bool CDSEnumKlass::is_enum_obj(oop orig_obj) { } // !!! This is legacy support for enum classes before JEP 483. This file is not used when -// !!! CDSConfig::is_initing_classes_at_dump_time()==true. +// !!! CDSConfig::is_dumping_aot_linked_classes()==true. // // Java Enum classes have synthetic methods that look like this // enum MyEnum {FOO, BAR} @@ -63,7 +63,7 @@ bool CDSEnumKlass::is_enum_obj(oop orig_obj) { void CDSEnumKlass::handle_enum_obj(int level, KlassSubGraphInfo* subgraph_info, oop orig_obj) { - assert(!CDSConfig::is_initing_classes_at_dump_time(), "only for legacy support of enums"); + assert(!CDSConfig::is_dumping_aot_linked_classes(), "only for legacy support of enums"); assert(level > 1, "must never be called at the first (outermost) level"); assert(is_enum_obj(orig_obj), "must be"); diff --git a/src/hotspot/share/cds/cdsEnumKlass.hpp b/src/hotspot/share/cds/cdsEnumKlass.hpp index e6019ff705e..a4829368430 100644 --- a/src/hotspot/share/cds/cdsEnumKlass.hpp +++ b/src/hotspot/share/cds/cdsEnumKlass.hpp @@ -35,7 +35,7 @@ class JavaFieldStream; class KlassSubGraphInfo; // This is legacy support for enum classes before JEP 483. This code is not needed when -// CDSConfig::is_initing_classes_at_dump_time()==true. +// CDSConfig::is_dumping_aot_linked_classes()==true. class CDSEnumKlass: AllStatic { public: static bool is_enum_obj(oop orig_obj); diff --git a/src/hotspot/share/cds/cdsHeapVerifier.cpp b/src/hotspot/share/cds/cdsHeapVerifier.cpp index 65063b4b005..3ed0dce1f66 100644 --- a/src/hotspot/share/cds/cdsHeapVerifier.cpp +++ b/src/hotspot/share/cds/cdsHeapVerifier.cpp @@ -156,7 +156,7 @@ CDSHeapVerifier::CDSHeapVerifier() : _archived_objs(0), _problems(0) # undef ADD_EXCL - if (CDSConfig::is_initing_classes_at_dump_time()) { + if (CDSConfig::is_dumping_aot_linked_classes()) { add_shared_secret_accessors(); } ClassLoaderDataGraph::classes_do(this); diff --git a/src/hotspot/share/cds/finalImageRecipes.cpp b/src/hotspot/share/cds/finalImageRecipes.cpp index bf8a760904c..8ba4514dfed 100644 --- a/src/hotspot/share/cds/finalImageRecipes.cpp +++ b/src/hotspot/share/cds/finalImageRecipes.cpp @@ -206,6 +206,8 @@ void FinalImageRecipes::load_all_classes(TRAPS) { if (ik->has_aot_safe_initializer() && (flags & WAS_INITED) != 0) { assert(ik->class_loader() == nullptr, "supported only for boot classes for now"); + ResourceMark rm(THREAD); + log_info(aot, init)("Initializing %s", ik->external_name()); ik->initialize(CHECK); } } diff --git a/src/hotspot/share/cds/heapShared.cpp b/src/hotspot/share/cds/heapShared.cpp index f2382289c7d..fdc335f3799 100644 --- a/src/hotspot/share/cds/heapShared.cpp +++ b/src/hotspot/share/cds/heapShared.cpp @@ -209,8 +209,14 @@ static bool is_subgraph_root_class_of(ArchivableStaticFieldInfo fields[], Instan } bool HeapShared::is_subgraph_root_class(InstanceKlass* ik) { - return is_subgraph_root_class_of(archive_subgraph_entry_fields, ik) || - is_subgraph_root_class_of(fmg_archive_subgraph_entry_fields, ik); + assert(CDSConfig::is_dumping_heap(), "dump-time only"); + if (!CDSConfig::is_dumping_aot_linked_classes()) { + // Legacy CDS archive support (to be deprecated) + return is_subgraph_root_class_of(archive_subgraph_entry_fields, ik) || + is_subgraph_root_class_of(fmg_archive_subgraph_entry_fields, ik); + } else { + return false; + } } oop HeapShared::CachedOopInfo::orig_referrer() const { @@ -934,12 +940,16 @@ void HeapShared::scan_java_class(Klass* orig_k) { void HeapShared::archive_subgraphs() { assert(CDSConfig::is_dumping_heap(), "must be"); - archive_object_subgraphs(archive_subgraph_entry_fields, - false /* is_full_module_graph */); + if (!CDSConfig::is_dumping_aot_linked_classes()) { + archive_object_subgraphs(archive_subgraph_entry_fields, + false /* is_full_module_graph */); + if (CDSConfig::is_dumping_full_module_graph()) { + archive_object_subgraphs(fmg_archive_subgraph_entry_fields, + true /* is_full_module_graph */); + } + } if (CDSConfig::is_dumping_full_module_graph()) { - archive_object_subgraphs(fmg_archive_subgraph_entry_fields, - true /* is_full_module_graph */); Modules::verify_archived_modules(); } } @@ -1295,8 +1305,10 @@ void HeapShared::resolve_classes(JavaThread* current) { if (!is_archived_heap_in_use()) { return; // nothing to do } - resolve_classes_for_subgraphs(current, archive_subgraph_entry_fields); - resolve_classes_for_subgraphs(current, fmg_archive_subgraph_entry_fields); + if (!CDSConfig::is_using_aot_linked_classes()) { + resolve_classes_for_subgraphs(current, archive_subgraph_entry_fields); + resolve_classes_for_subgraphs(current, fmg_archive_subgraph_entry_fields); + } } void HeapShared::resolve_classes_for_subgraphs(JavaThread* current, ArchivableStaticFieldInfo fields[]) { @@ -1734,13 +1746,13 @@ bool HeapShared::walk_one_object(PendingOopStack* stack, int level, KlassSubGrap } } - if (CDSConfig::is_initing_classes_at_dump_time()) { + if (CDSConfig::is_dumping_aot_linked_classes()) { if (java_lang_Class::is_instance(orig_obj)) { orig_obj = scratch_java_mirror(orig_obj); assert(orig_obj != nullptr, "must be archived"); } } else if (java_lang_Class::is_instance(orig_obj) && subgraph_info != _dump_time_special_subgraph) { - // Without CDSConfig::is_initing_classes_at_dump_time(), we only allow archived objects to + // Without CDSConfig::is_dumping_aot_linked_classes(), we only allow archived objects to // point to the mirrors of (1) j.l.Object, (2) primitive classes, and (3) box classes. These are initialized // very early by HeapShared::init_box_classes(). if (orig_obj == vmClasses::Object_klass()->java_mirror() @@ -1808,9 +1820,9 @@ bool HeapShared::walk_one_object(PendingOopStack* stack, int level, KlassSubGrap orig_obj->oop_iterate(&pusher); } - if (CDSConfig::is_initing_classes_at_dump_time()) { - // The classes of all archived enum instances have been marked as aot-init, - // so there's nothing else to be done in the production run. + if (CDSConfig::is_dumping_aot_linked_classes()) { + // The enum klasses are archived with aot-initialized mirror. + // See AOTClassInitializer::can_archive_initialized_mirror(). } else { // This is legacy support for enum classes before JEP 483 -- we cannot rerun // the enum's in the production run, so special handling is needed. @@ -1949,7 +1961,7 @@ void HeapShared::verify_reachable_objects_from(oop obj) { #endif void HeapShared::check_special_subgraph_classes() { - if (CDSConfig::is_initing_classes_at_dump_time()) { + if (CDSConfig::is_dumping_aot_linked_classes()) { // We can have aot-initialized classes (such as Enums) that can reference objects // of arbitrary types. Currently, we trust the JEP 483 implementation to only // aot-initialize classes that are "safe". @@ -2136,9 +2148,11 @@ void HeapShared::init_subgraph_entry_fields(ArchivableStaticFieldInfo fields[], void HeapShared::init_subgraph_entry_fields(TRAPS) { assert(CDSConfig::is_dumping_heap(), "must be"); _dump_time_subgraph_info_table = new (mtClass)DumpTimeKlassSubGraphInfoTable(); - init_subgraph_entry_fields(archive_subgraph_entry_fields, CHECK); - if (CDSConfig::is_dumping_full_module_graph()) { - init_subgraph_entry_fields(fmg_archive_subgraph_entry_fields, CHECK); + if (!CDSConfig::is_dumping_aot_linked_classes()) { + init_subgraph_entry_fields(archive_subgraph_entry_fields, CHECK); + if (CDSConfig::is_dumping_full_module_graph()) { + init_subgraph_entry_fields(fmg_archive_subgraph_entry_fields, CHECK); + } } } diff --git a/src/java.base/share/classes/java/lang/Byte.java b/src/java.base/share/classes/java/lang/Byte.java index d9913e354a4..0f3f7f40d05 100644 --- a/src/java.base/share/classes/java/lang/Byte.java +++ b/src/java.base/share/classes/java/lang/Byte.java @@ -26,6 +26,7 @@ package java.lang; import jdk.internal.misc.CDS; +import jdk.internal.vm.annotation.AOTSafeClassInitializer; import jdk.internal.vm.annotation.IntrinsicCandidate; import jdk.internal.vm.annotation.Stable; @@ -103,6 +104,7 @@ public final class Byte extends Number implements Comparable, Constable { return Optional.of(DynamicConstantDesc.ofNamed(BSM_EXPLICIT_CAST, DEFAULT_NAME, CD_byte, intValue())); } + @AOTSafeClassInitializer private static final class ByteCache { private ByteCache() {} diff --git a/src/java.base/share/classes/java/lang/Character.java b/src/java.base/share/classes/java/lang/Character.java index b71849eaee7..ffda729a45a 100644 --- a/src/java.base/share/classes/java/lang/Character.java +++ b/src/java.base/share/classes/java/lang/Character.java @@ -26,6 +26,7 @@ package java.lang; import jdk.internal.misc.CDS; +import jdk.internal.vm.annotation.AOTSafeClassInitializer; import jdk.internal.vm.annotation.IntrinsicCandidate; import jdk.internal.vm.annotation.Stable; @@ -9379,6 +9380,7 @@ class Character implements java.io.Serializable, Comparable, Constabl this.value = value; } + @AOTSafeClassInitializer private static final class CharacterCache { private CharacterCache(){} diff --git a/src/java.base/share/classes/java/lang/Integer.java b/src/java.base/share/classes/java/lang/Integer.java index 2742ec40abf..a9da1c32490 100644 --- a/src/java.base/share/classes/java/lang/Integer.java +++ b/src/java.base/share/classes/java/lang/Integer.java @@ -28,6 +28,8 @@ package java.lang; import jdk.internal.misc.CDS; import jdk.internal.misc.VM; import jdk.internal.util.DecimalDigits; +import jdk.internal.vm.annotation.AOTRuntimeSetup; +import jdk.internal.vm.annotation.AOTSafeClassInitializer; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.annotation.IntrinsicCandidate; import jdk.internal.vm.annotation.Stable; @@ -891,15 +893,20 @@ public final class Integer extends Number * with new Integer object(s) after initialization. */ + @AOTSafeClassInitializer private static final class IntegerCache { static final int low = -128; - static final int high; + @Stable static int high; - @Stable - static final Integer[] cache; + @Stable static Integer[] cache; static Integer[] archivedCache; static { + runtimeSetup(); + } + + @AOTRuntimeSetup + private static void runtimeSetup() { // high value may be configured by property int h = 127; String integerCacheHighPropValue = @@ -915,34 +922,50 @@ public final class Integer extends Number } high = h; - // Load IntegerCache.archivedCache from archive, if possible - CDS.initializeFromArchive(IntegerCache.class); - int size = (high - low) + 1; - - // Use the archived cache if it exists and is large enough - if (archivedCache == null || size > archivedCache.length) { - Integer[] c = new Integer[size]; - int j = low; - // If archive has Integer cache, we must use all instances from it. - // Otherwise, the identity checks between archived Integers and - // runtime-cached Integers would fail. - int archivedSize = (archivedCache == null) ? 0 : archivedCache.length; - for (int i = 0; i < archivedSize; i++) { - c[i] = archivedCache[i]; - assert j == archivedCache[i]; - j++; - } - // Fill the rest of the cache. - for (int i = archivedSize; i < size; i++) { - c[i] = new Integer(j++); - } - archivedCache = c; + Integer[] precomputed = null; + if (cache != null) { + // IntegerCache has been AOT-initialized. + precomputed = cache; + } else { + // Legacy CDS archive support (to be deprecated): + // Load IntegerCache.archivedCache from archive, if possible + CDS.initializeFromArchive(IntegerCache.class); + precomputed = archivedCache; } - cache = archivedCache; + + cache = loadOrInitializeCache(precomputed); + archivedCache = cache; // Legacy CDS archive support (to be deprecated) // range [-128, 127] must be interned (JLS7 5.1.7) assert IntegerCache.high >= 127; } + private static Integer[] loadOrInitializeCache(Integer[] precomputed) { + int size = (high - low) + 1; + + // Use the precomputed cache if it exists and is large enough + if (precomputed != null && size <= precomputed.length) { + return precomputed; + } + + Integer[] c = new Integer[size]; + int j = low; + // If we loading a precomputed cache (from AOT cache or CDS archive), + // we must use all instances from it. + // Otherwise, the Integers from the AOT cache (or CDS archive) will not + // have the same object identity as items in IntegerCache.cache[]. + int precomputedSize = (precomputed == null) ? 0 : precomputed.length; + for (int i = 0; i < precomputedSize; i++) { + c[i] = precomputed[i]; + assert j == precomputed[i]; + j++; + } + // Fill the rest of the cache. + for (int i = precomputedSize; i < size; i++) { + c[i] = new Integer(j++); + } + return c; + } + private IntegerCache() {} } diff --git a/src/java.base/share/classes/java/lang/Long.java b/src/java.base/share/classes/java/lang/Long.java index 3077e7c0a38..c5cd9650f2d 100644 --- a/src/java.base/share/classes/java/lang/Long.java +++ b/src/java.base/share/classes/java/lang/Long.java @@ -35,6 +35,7 @@ import java.util.Optional; import jdk.internal.misc.CDS; import jdk.internal.util.DecimalDigits; +import jdk.internal.vm.annotation.AOTSafeClassInitializer; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.annotation.IntrinsicCandidate; import jdk.internal.vm.annotation.Stable; @@ -911,6 +912,7 @@ public final class Long extends Number return Long.valueOf(parseLong(s, 10)); } + @AOTSafeClassInitializer private static final class LongCache { private LongCache() {} diff --git a/src/java.base/share/classes/java/lang/Module.java b/src/java.base/share/classes/java/lang/Module.java index cd2b8095ee4..bd04345554b 100644 --- a/src/java.base/share/classes/java/lang/Module.java +++ b/src/java.base/share/classes/java/lang/Module.java @@ -69,6 +69,7 @@ import jdk.internal.module.ServicesCatalog; import jdk.internal.module.Resources; import jdk.internal.reflect.CallerSensitive; import jdk.internal.reflect.Reflection; +import jdk.internal.vm.annotation.AOTSafeClassInitializer; import jdk.internal.vm.annotation.Stable; /** @@ -391,6 +392,7 @@ public final class Module implements AnnotatedElement { private static final Module EVERYONE_MODULE; private static final Set EVERYONE_SET; + @AOTSafeClassInitializer private static class ArchivedData { private static ArchivedData archivedData; private final Module allUnnamedModule; diff --git a/src/java.base/share/classes/java/lang/ModuleLayer.java b/src/java.base/share/classes/java/lang/ModuleLayer.java index 9d922f787a6..a073de6b14a 100644 --- a/src/java.base/share/classes/java/lang/ModuleLayer.java +++ b/src/java.base/share/classes/java/lang/ModuleLayer.java @@ -53,6 +53,7 @@ import jdk.internal.module.ServicesCatalog; import jdk.internal.misc.CDS; import jdk.internal.reflect.CallerSensitive; import jdk.internal.reflect.Reflection; +import jdk.internal.vm.annotation.AOTSafeClassInitializer; import jdk.internal.vm.annotation.Stable; /** @@ -145,6 +146,7 @@ import jdk.internal.vm.annotation.Stable; * @see Module#getLayer() */ +@AOTSafeClassInitializer public final class ModuleLayer { // the empty layer (may be initialized from the CDS archive) diff --git a/src/java.base/share/classes/java/lang/Short.java b/src/java.base/share/classes/java/lang/Short.java index 4c64427b6df..920500a7fa3 100644 --- a/src/java.base/share/classes/java/lang/Short.java +++ b/src/java.base/share/classes/java/lang/Short.java @@ -26,6 +26,7 @@ package java.lang; import jdk.internal.misc.CDS; +import jdk.internal.vm.annotation.AOTSafeClassInitializer; import jdk.internal.vm.annotation.IntrinsicCandidate; import jdk.internal.vm.annotation.Stable; @@ -230,6 +231,7 @@ public final class Short extends Number implements Comparable, Constable return Optional.of(DynamicConstantDesc.ofNamed(BSM_EXPLICIT_CAST, DEFAULT_NAME, CD_short, intValue())); } + @AOTSafeClassInitializer private static final class ShortCache { private ShortCache() {} diff --git a/src/java.base/share/classes/java/lang/module/Configuration.java b/src/java.base/share/classes/java/lang/module/Configuration.java index a76a32cfb28..40eeddc3f0b 100644 --- a/src/java.base/share/classes/java/lang/module/Configuration.java +++ b/src/java.base/share/classes/java/lang/module/Configuration.java @@ -44,6 +44,7 @@ import java.util.stream.Stream; import jdk.internal.misc.CDS; import jdk.internal.module.ModuleReferenceImpl; import jdk.internal.module.ModuleTarget; +import jdk.internal.vm.annotation.AOTSafeClassInitializer; import jdk.internal.vm.annotation.Stable; /** @@ -155,6 +156,7 @@ import jdk.internal.vm.annotation.Stable; * @since 9 * @see java.lang.ModuleLayer */ +@AOTSafeClassInitializer public final class Configuration { // @see Configuration#empty() diff --git a/src/java.base/share/classes/java/util/ImmutableCollections.java b/src/java.base/share/classes/java/util/ImmutableCollections.java index abc48ff5ed9..e7fe22490da 100644 --- a/src/java.base/share/classes/java/util/ImmutableCollections.java +++ b/src/java.base/share/classes/java/util/ImmutableCollections.java @@ -42,6 +42,9 @@ import java.util.function.UnaryOperator; import jdk.internal.access.JavaUtilCollectionAccess; import jdk.internal.access.SharedSecrets; import jdk.internal.misc.CDS; +import jdk.internal.vm.annotation.AOTRuntimeSetup; +import jdk.internal.vm.annotation.AOTSafeClassInitializer; +import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.annotation.Stable; /** @@ -52,6 +55,7 @@ import jdk.internal.vm.annotation.Stable; * classes use a serial proxy and thus have no need to declare serialVersionUID. */ @SuppressWarnings("serial") +@AOTSafeClassInitializer class ImmutableCollections { /** * A "salt" value used for randomizing iteration order. This is initialized once @@ -59,14 +63,20 @@ class ImmutableCollections { * it needs to vary sufficiently from one run to the next so that iteration order * will vary between JVM runs. */ - private static final long SALT32L; + @Stable private static long SALT32L; /** * For set and map iteration, we will iterate in "reverse" stochastically, * decided at bootstrap time. */ - private static final boolean REVERSE; + @Stable private static boolean REVERSE; + static { + runtimeSetup(); + } + + @AOTRuntimeSetup + private static void runtimeSetup() { // to generate a reasonably random and well-mixed SALT, use an arbitrary // value (a slice of pi), multiply with a random seed, then pick // the mid 32-bits from the product. By picking a SALT value in the @@ -102,6 +112,7 @@ class ImmutableCollections { static final MapN EMPTY_MAP; static { + // Legacy CDS archive support (to be deprecated) CDS.initializeFromArchive(ImmutableCollections.class); if (archivedObjects == null) { EMPTY = new Object(); diff --git a/src/java.base/share/classes/java/util/jar/Attributes.java b/src/java.base/share/classes/java/util/jar/Attributes.java index 9322bb9acac..20ff81676c9 100644 --- a/src/java.base/share/classes/java/util/jar/Attributes.java +++ b/src/java.base/share/classes/java/util/jar/Attributes.java @@ -36,6 +36,7 @@ import java.util.Objects; import java.util.Set; import jdk.internal.misc.CDS; +import jdk.internal.vm.annotation.AOTSafeClassInitializer; import jdk.internal.vm.annotation.Stable; import sun.nio.cs.UTF_8; @@ -60,6 +61,7 @@ import sun.util.logging.PlatformLogger; * @see Manifest * @since 1.2 */ +@AOTSafeClassInitializer public class Attributes implements Map, Cloneable { /** * The attribute name-value mappings. @@ -450,6 +452,7 @@ public class Attributes implements Map, Cloneable { * * @spec jar/jar.html JAR File Specification */ + @AOTSafeClassInitializer public static class Name { private final String name; private final int hashCode; @@ -669,6 +672,7 @@ public class Attributes implements Map, Cloneable { static { + // Legacy CDS archive support (to be deprecated) CDS.initializeFromArchive(Attributes.Name.class); if (KNOWN_NAMES == null) { diff --git a/src/java.base/share/classes/jdk/internal/loader/ArchivedClassLoaders.java b/src/java.base/share/classes/jdk/internal/loader/ArchivedClassLoaders.java index be3425590fc..439772a8789 100644 --- a/src/java.base/share/classes/jdk/internal/loader/ArchivedClassLoaders.java +++ b/src/java.base/share/classes/jdk/internal/loader/ArchivedClassLoaders.java @@ -27,11 +27,13 @@ package jdk.internal.loader; import java.util.Map; import jdk.internal.misc.CDS; import jdk.internal.module.ServicesCatalog; +import jdk.internal.vm.annotation.AOTSafeClassInitializer; /** * Used to archive the built-in class loaders, their services catalogs, and the * package-to-module map used by the built-in class loaders. */ +@AOTSafeClassInitializer class ArchivedClassLoaders { private static ArchivedClassLoaders archivedClassLoaders; diff --git a/src/java.base/share/classes/jdk/internal/math/FDBigInteger.java b/src/java.base/share/classes/jdk/internal/math/FDBigInteger.java index 1ef9dee3a8a..5413226c112 100644 --- a/src/java.base/share/classes/jdk/internal/math/FDBigInteger.java +++ b/src/java.base/share/classes/jdk/internal/math/FDBigInteger.java @@ -26,6 +26,7 @@ package jdk.internal.math; import jdk.internal.misc.CDS; +import jdk.internal.vm.annotation.AOTSafeClassInitializer; import jdk.internal.vm.annotation.Stable; import java.util.Arrays; @@ -33,6 +34,7 @@ import java.util.Arrays; /** * A simple big integer class specifically for floating point base conversion. */ +@AOTSafeClassInitializer final class FDBigInteger { @Stable @@ -53,6 +55,7 @@ final class FDBigInteger { // Initialize FDBigInteger cache of powers of 5. static { + // Legacy CDS archive support (to be deprecated) CDS.initializeFromArchive(FDBigInteger.class); Object[] caches = archivedCaches; if (caches == null) { diff --git a/src/java.base/share/classes/jdk/internal/module/ArchivedBootLayer.java b/src/java.base/share/classes/jdk/internal/module/ArchivedBootLayer.java index 5c806f81dcd..425238dd521 100644 --- a/src/java.base/share/classes/jdk/internal/module/ArchivedBootLayer.java +++ b/src/java.base/share/classes/jdk/internal/module/ArchivedBootLayer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, 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,10 +25,12 @@ package jdk.internal.module; import jdk.internal.misc.CDS; +import jdk.internal.vm.annotation.AOTSafeClassInitializer; /** * Used by ModuleBootstrap for archiving the boot layer. */ +@AOTSafeClassInitializer class ArchivedBootLayer { private static ArchivedBootLayer archivedBootLayer; diff --git a/src/java.base/share/classes/jdk/internal/module/ArchivedModuleGraph.java b/src/java.base/share/classes/jdk/internal/module/ArchivedModuleGraph.java index 4f9223d0171..deb280c878d 100644 --- a/src/java.base/share/classes/jdk/internal/module/ArchivedModuleGraph.java +++ b/src/java.base/share/classes/jdk/internal/module/ArchivedModuleGraph.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, 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,11 +30,13 @@ import java.util.function.Function; import java.lang.module.Configuration; import java.lang.module.ModuleFinder; import jdk.internal.misc.CDS; +import jdk.internal.vm.annotation.AOTSafeClassInitializer; /** * Used by ModuleBootstrap for archiving the configuration for the boot layer, * and the system module finder. */ +@AOTSafeClassInitializer class ArchivedModuleGraph { private static ArchivedModuleGraph archivedModuleGraph; @@ -126,6 +128,7 @@ class ArchivedModuleGraph { } static { + // Legacy CDS archive support (to be deprecated) CDS.initializeFromArchive(ArchivedModuleGraph.class); } } diff --git a/src/java.base/share/classes/sun/util/locale/BaseLocale.java b/src/java.base/share/classes/sun/util/locale/BaseLocale.java index 58ec6d76aa5..31078720ddc 100644 --- a/src/java.base/share/classes/sun/util/locale/BaseLocale.java +++ b/src/java.base/share/classes/sun/util/locale/BaseLocale.java @@ -34,11 +34,14 @@ package sun.util.locale; import jdk.internal.misc.CDS; import jdk.internal.util.ReferencedKeySet; +import jdk.internal.vm.annotation.AOTRuntimeSetup; +import jdk.internal.vm.annotation.AOTSafeClassInitializer; import jdk.internal.vm.annotation.Stable; import java.util.StringJoiner; import java.util.function.Supplier; +@AOTSafeClassInitializer public final class BaseLocale { public static @Stable BaseLocale[] constantBaseLocales; @@ -63,6 +66,7 @@ public final class BaseLocale { CANADA_FRENCH = 18, NUM_CONSTANTS = 19; static { + // Legacy CDS archive support (to be deprecated) CDS.initializeFromArchive(BaseLocale.class); BaseLocale[] baseLocales = constantBaseLocales; if (baseLocales == null) { @@ -91,13 +95,21 @@ public final class BaseLocale { } // Interned BaseLocale cache - private static final LazyConstant> CACHE = + @Stable private static LazyConstant> CACHE; + static { + runtimeSetup(); + } + + @AOTRuntimeSetup + private static void runtimeSetup() { + CACHE = LazyConstant.of(new Supplier<>() { @Override public ReferencedKeySet get() { return ReferencedKeySet.create(true, ReferencedKeySet.concurrentHashMapSupplier()); } }); + } public static final String SEP = "_"; diff --git a/test/hotspot/jtreg/TEST.groups b/test/hotspot/jtreg/TEST.groups index d4f1470aea5..2288e8f8876 100644 --- a/test/hotspot/jtreg/TEST.groups +++ b/test/hotspot/jtreg/TEST.groups @@ -522,6 +522,7 @@ hotspot_aot_classlinking = \ -runtime/cds/appcds/aotFlags \ -runtime/cds/appcds/aotProfile \ -runtime/cds/appcds/BadBSM.java \ + -runtime/cds/appcds/cacheObject/ArchiveHeapTestClass.java \ -runtime/cds/appcds/cacheObject/ArchivedIntegerCacheTest.java \ -runtime/cds/appcds/cacheObject/ArchivedModuleCompareTest.java \ -runtime/cds/appcds/CDSandJFR.java \ diff --git a/test/hotspot/jtreg/runtime/cds/SharedSymbolTableBucketSize.java b/test/hotspot/jtreg/runtime/cds/SharedSymbolTableBucketSize.java index 2db4ab2df23..070384a2703 100644 --- a/test/hotspot/jtreg/runtime/cds/SharedSymbolTableBucketSize.java +++ b/test/hotspot/jtreg/runtime/cds/SharedSymbolTableBucketSize.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, 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,8 @@ * java.management */ +import java.util.regex.Matcher; +import java.util.regex.Pattern; import jdk.test.lib.cds.CDSTestUtils; import jdk.test.lib.process.OutputAnalyzer; @@ -43,8 +45,44 @@ public class SharedSymbolTableBucketSize { + Integer.valueOf(bucket_size)); CDSTestUtils.checkMappingFailure(output); - String regex = "Average bucket size : ([0-9]+\\.[0-9]+).*"; - String s = output.firstMatch(regex, 1); + /* [1] There may be other table stats that precede the symbol tabble. + Skip all thse until we find this: + + [0.677s][info][aot,hashtables] Shared symbol table stats -------- base: 0x0000000800000000 + [0.677s][info][aot,hashtables] Number of entries : 46244 + [0.677s][info][aot,hashtables] Total bytes used : 393792 + [0.677s][info][aot,hashtables] Average bytes per entry : 8.516 + [0.677s][info][aot,hashtables] Average bucket size : 7.734 + [0.677s][info][aot,hashtables] Variance of bucket size : 7.513 + [0.677s][info][aot,hashtables] Std. dev. of bucket size: 2.741 + [0.677s][info][aot,hashtables] Maximum bucket size : 20 + [0.677s][info][aot,hashtables] Empty buckets : 2 + [0.677s][info][aot,hashtables] Value_Only buckets : 24 + [0.677s][info][aot,hashtables] Other buckets : 5953 + .... + */ + Pattern pattern0 = Pattern.compile("Shared symbol table stats.*", Pattern.DOTALL); + Matcher matcher0 = pattern0.matcher(output.getStdout()); + String stat = null; + if (matcher0.find()) { + stat = matcher0.group(0); + } + if (stat == null) { + throw new Exception("FAILED: pattern \"" + pattern0 + "\" not found"); + } + + /* (2) The first "Average bucket size" line in the remaining output is for the + shared symbol table */ + Pattern pattern = Pattern.compile("Average bucket size *: *([0-9]+\\.[0-9]+).*", Pattern.MULTILINE); + Matcher matcher = pattern.matcher(stat); + String s = null; + if (matcher.find()) { + s = matcher.group(1); + } + if (s == null) { + throw new Exception("FAILED: pattern \"" + pattern + "\" not found"); + } + Float f = Float.parseFloat(s); int size = Math.round(f); if (size != bucket_size) { diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/AOTLoggingTag.java b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/AOTLoggingTag.java index 896df7ca496..4cc6ef81c45 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/AOTLoggingTag.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/AOTLoggingTag.java @@ -83,17 +83,6 @@ public class AOTLoggingTag { out.shouldContain("[aot] Opened AOT cache hello.aot"); out.shouldHaveExitValue(0); - //---------------------------------------------------------------------- - printTestCase("All old -Xlog:cds+heap logs have been changed to -Xlog:aot+heap should alias to -Xlog:cds+heap"); - pb = ProcessTools.createLimitedTestJavaProcessBuilder( - "-XX:AOTCache=" + aotCacheFile, - "-Xlog:aot+heap", - "-cp", appJar, helloClass); - out = CDSTestUtils.executeAndLog(pb, "prod"); - out.shouldNotContain("No tag set matches selection: aot+heap"); - out.shouldContain("[aot,heap] resolve subgraph java.lang.Integer$IntegerCache"); - out.shouldHaveExitValue(0); - //---------------------------------------------------------------------- printTestCase("Production Run: errors should be printed with [aot] decoration"); pb = ProcessTools.createLimitedTestJavaProcessBuilder( diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/HeapObjectIdentity.java b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/HeapObjectIdentity.java new file mode 100644 index 00000000000..cdd0921627a --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/HeapObjectIdentity.java @@ -0,0 +1,261 @@ +/* + * Copyright (c) 2025, 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 AOT cache should preserve heap object identity when required by JLS. For example, Enums and Integers. + * @requires vm.cds + * @requires vm.cds.supports.aot.class.linking + * @requires vm.debug + * @library /test/lib + * @build HeapObjectIdentity + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar dummy.jar + * Dummy + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar boot.jar + * HeapObjectIdentityApp + * MyAOTInitedClass + * MyAOTInitedClass$MyEnum + * MyAOTInitedClass$Wrapper + * @run driver HeapObjectIdentity AOT --two-step-training + */ + +import jdk.test.lib.cds.CDSAppTester; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.helpers.ClassFileInstaller; + +public class HeapObjectIdentity { + static final String appJar = ClassFileInstaller.getJarPath("dummy.jar"); + static final String bootJar = ClassFileInstaller.getJarPath("boot.jar"); + static final String mainClass = "HeapObjectIdentityApp"; // Loaded from boot.jar + + public static void main(String[] args) throws Exception { + Tester t = new Tester(); + t.run(args); + + // Integer$IntegerCache should preserve the object identity of cached Integer objects, + // even when the cache size is different between assembly and production. + t.productionRun(new String[] { + "-XX:AutoBoxCacheMax=2048" + }); + } + + static class Tester extends CDSAppTester { + public Tester() { + super(mainClass); + } + + @Override + public String classpath(RunMode runMode) { + return appJar; + } + + @Override + public String[] vmArgs(RunMode runMode) { + String bootcp = "-Xbootclasspath/a:" + bootJar; + if (runMode == RunMode.ASSEMBLY) { + return new String[] { + "-Xlog:aot+class=debug", + "-XX:AOTInitTestClass=MyAOTInitedClass", + bootcp + }; + } else { + return new String[] {bootcp}; + } + } + + @Override + public String[] appCommandLine(RunMode runMode) { + return new String[] { + mainClass, + runMode.toString(), + }; + } + + @Override + public void checkExecution(OutputAnalyzer out, RunMode runMode) throws Exception { + if (runMode == RunMode.ASSEMBLY) { + out.shouldContain("MyAOTInitedClass aot-linked inited"); + } + } + } +} + +class HeapObjectIdentityApp { + public static void main(String... args) { + MyAOTInitedClass.test(); + } +} + +// This class is loaded by the boot loader, as -XX:AOTInitTestClass is not too friendly +// with classes by other loaders. +class MyAOTInitedClass { + static Object[] archivedObjects; + static { + if (archivedObjects == null) { + archivedObjects = new Object[14]; + archivedObjects[0] = Wrapper.BOOLEAN; + archivedObjects[1] = Wrapper.INT.zero(); + archivedObjects[2] = Wrapper.DOUBLE.zero(); + archivedObjects[3] = MyEnum.DUMMY1; + + archivedObjects[4] = Boolean.class; + archivedObjects[5] = Byte.class; + archivedObjects[6] = Character.class; + archivedObjects[7] = Short.class; + archivedObjects[8] = Integer.class; + archivedObjects[9] = Long.class; + archivedObjects[10] = Float.class; + archivedObjects[11] = Double.class; + archivedObjects[12] = Void.class; + + archivedObjects[13] = Integer.valueOf(1); + } else { + System.out.println("Initialized from CDS"); + } + } + + public static void test() { + if (archivedObjects[0] != Wrapper.BOOLEAN) { + throw new RuntimeException("Huh 0"); + } + + if (archivedObjects[1] != Wrapper.INT.zero()) { + throw new RuntimeException("Huh 1"); + } + + if (archivedObjects[2] != Wrapper.DOUBLE.zero()) { + throw new RuntimeException("Huh 2"); + } + + if (archivedObjects[3] != MyEnum.DUMMY1) { + throw new RuntimeException("Huh 3"); + } + + if (MyEnum.BOOLEAN != true) { + throw new RuntimeException("Huh 10.1"); + } + if (MyEnum.BYTE != -128) { + throw new RuntimeException("Huh 10.2"); + } + if (MyEnum.CHAR != 'c') { + throw new RuntimeException("Huh 10.3"); + } + if (MyEnum.SHORT != -12345) { + throw new RuntimeException("Huh 10.4"); + } + if (MyEnum.INT != -123456) { + throw new RuntimeException("Huh 10.5"); + } + if (MyEnum.LONG != 0x1234567890L) { + throw new RuntimeException("Huh 10.6"); + } + if (MyEnum.LONG2 != -0x1234567890L) { + throw new RuntimeException("Huh 10.7"); + } + if (MyEnum.FLOAT != 567891.0f) { + throw new RuntimeException("Huh 10.8"); + } + if (MyEnum.DOUBLE != 12345678905678.890) { + throw new RuntimeException("Huh 10.9"); + } + + checkClass(4, Boolean.class); + checkClass(5, Byte.class); + checkClass(6, Character.class); + checkClass(7, Short.class); + checkClass(8, Integer.class); + checkClass(9, Long.class); + checkClass(10, Float.class); + checkClass(11, Double.class); + checkClass(12, Void.class); + + if (archivedObjects[13] != Integer.valueOf(1)) { + throw new RuntimeException("Integer cache identity test failed"); + } + + System.out.println("Success!"); + } + + static void checkClass(int index, Class c) { + if (archivedObjects[index] != c) { + throw new RuntimeException("archivedObjects[" + index + "] should be " + c); + } + } + + // Simplified version of sun.invoke.util.Wrapper + public enum Wrapper { + // wrapperType simple primitiveType simple char emptyArray + BOOLEAN( Boolean.class, "Boolean", boolean.class, "boolean", 'Z', new boolean[0]), + INT ( Integer.class, "Integer", int.class, "int", 'I', new int[0]), + DOUBLE ( Double.class, "Double", double.class, "double", 'D', new double[0]) + ; + + public static final int COUNT = 10; + private static final Object DOUBLE_ZERO = (Double)(double)0; + + private final Class wrapperType; + private final Class primitiveType; + private final char basicTypeChar; + private final String basicTypeString; + private final Object emptyArray; + + Wrapper(Class wtype, + String wtypeName, + Class ptype, + String ptypeName, + char tchar, + Object emptyArray) { + this.wrapperType = wtype; + this.primitiveType = ptype; + this.basicTypeChar = tchar; + this.basicTypeString = String.valueOf(this.basicTypeChar); + this.emptyArray = emptyArray; + } + + public Object zero() { + return switch (this) { + case BOOLEAN -> Boolean.FALSE; + case INT -> (Integer)0; + case DOUBLE -> DOUBLE_ZERO; + default -> null; + }; + } + } + + enum MyEnum { + DUMMY1, + DUMMY2; + + static final boolean BOOLEAN = true; + static final byte BYTE = -128; + static final short SHORT = -12345; + static final char CHAR = 'c'; + static final int INT = -123456; + static final long LONG = 0x1234567890L; + static final long LONG2 = -0x1234567890L; + static final float FLOAT = 567891.0f; + static final double DOUBLE = 12345678905678.890; + } +} + +class Dummy {} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/cacheObject/ArchiveHeapTestClass.java b/test/hotspot/jtreg/runtime/cds/appcds/cacheObject/ArchiveHeapTestClass.java index fed56937f2f..3b1ccff1bfa 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/cacheObject/ArchiveHeapTestClass.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/cacheObject/ArchiveHeapTestClass.java @@ -36,7 +36,7 @@ * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar boot.jar * CDSTestClassA CDSTestClassA$XX CDSTestClassA$YY * CDSTestClassB CDSTestClassC CDSTestClassD - * CDSTestClassE CDSTestClassF CDSTestClassG CDSTestClassG$MyEnum CDSTestClassG$Wrapper + * CDSTestClassE CDSTestClassF * pkg.ClassInPackage * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar app.jar Hello * @run driver ArchiveHeapTestClass @@ -58,7 +58,6 @@ public class ArchiveHeapTestClass { static final String CDSTestClassD_name = CDSTestClassD.class.getName(); static final String CDSTestClassE_name = CDSTestClassE.class.getName(); static final String CDSTestClassF_name = CDSTestClassF.class.getName(); - static final String CDSTestClassG_name = CDSTestClassG.class.getName(); static final String ClassInPackage_name = pkg.ClassInPackage.class.getName().replace('.', '/'); static final String ARCHIVE_TEST_FIELD_NAME = "archivedObjects"; @@ -162,15 +161,6 @@ public class ArchiveHeapTestClass { output = dumpBootAndHello(CDSTestClassF_name); mustFail(output, "Class java.util.logging.Level not allowed in archive heap"); } - - testCase("Complex enums"); - output = dumpBootAndHello(CDSTestClassG_name, "-XX:+AOTClassLinking", "-Xlog:cds+class=debug"); - mustSucceed(output); - - TestCommon.run("-Xbootclasspath/a:" + bootJar, "-cp", appJar, "-Xlog:aot+heap,cds+init", - CDSTestClassG_name) - .assertNormalExit("init subgraph " + CDSTestClassG_name, - "Initialized from CDS"); } } @@ -287,147 +277,3 @@ class CDSTestClassF { archivedObjects[0] = java.util.logging.Level.OFF; } } - -class CDSTestClassG { - static Object[] archivedObjects; - static { - if (archivedObjects == null) { - archivedObjects = new Object[13]; - archivedObjects[0] = Wrapper.BOOLEAN; - archivedObjects[1] = Wrapper.INT.zero(); - archivedObjects[2] = Wrapper.DOUBLE.zero(); - archivedObjects[3] = MyEnum.DUMMY1; - - archivedObjects[4] = Boolean.class; - archivedObjects[5] = Byte.class; - archivedObjects[6] = Character.class; - archivedObjects[7] = Short.class; - archivedObjects[8] = Integer.class; - archivedObjects[9] = Long.class; - archivedObjects[10] = Float.class; - archivedObjects[11] = Double.class; - archivedObjects[12] = Void.class; - } else { - System.out.println("Initialized from CDS"); - } - } - - public static void main(String args[]) { - if (archivedObjects[0] != Wrapper.BOOLEAN) { - throw new RuntimeException("Huh 0"); - } - - if (archivedObjects[1] != Wrapper.INT.zero()) { - throw new RuntimeException("Huh 1"); - } - - if (archivedObjects[2] != Wrapper.DOUBLE.zero()) { - throw new RuntimeException("Huh 2"); - } - - if (archivedObjects[3] != MyEnum.DUMMY1) { - throw new RuntimeException("Huh 3"); - } - - if (MyEnum.BOOLEAN != true) { - throw new RuntimeException("Huh 10.1"); - } - if (MyEnum.BYTE != -128) { - throw new RuntimeException("Huh 10.2"); - } - if (MyEnum.CHAR != 'c') { - throw new RuntimeException("Huh 10.3"); - } - if (MyEnum.SHORT != -12345) { - throw new RuntimeException("Huh 10.4"); - } - if (MyEnum.INT != -123456) { - throw new RuntimeException("Huh 10.5"); - } - if (MyEnum.LONG != 0x1234567890L) { - throw new RuntimeException("Huh 10.6"); - } - if (MyEnum.LONG2 != -0x1234567890L) { - throw new RuntimeException("Huh 10.7"); - } - if (MyEnum.FLOAT != 567891.0f) { - throw new RuntimeException("Huh 10.8"); - } - if (MyEnum.DOUBLE != 12345678905678.890) { - throw new RuntimeException("Huh 10.9"); - } - - checkClass(4, Boolean.class); - checkClass(5, Byte.class); - checkClass(6, Character.class); - checkClass(7, Short.class); - checkClass(8, Integer.class); - checkClass(9, Long.class); - checkClass(10, Float.class); - checkClass(11, Double.class); - checkClass(12, Void.class); - - System.out.println("Success!"); - } - - static void checkClass(int index, Class c) { - if (archivedObjects[index] != c) { - throw new RuntimeException("archivedObjects[" + index + "] should be " + c); - } - } - - // Simplified version of sun.invoke.util.Wrapper - public enum Wrapper { - // wrapperType simple primitiveType simple char emptyArray - BOOLEAN( Boolean.class, "Boolean", boolean.class, "boolean", 'Z', new boolean[0]), - INT ( Integer.class, "Integer", int.class, "int", 'I', new int[0]), - DOUBLE ( Double.class, "Double", double.class, "double", 'D', new double[0]) - ; - - public static final int COUNT = 10; - private static final Object DOUBLE_ZERO = (Double)(double)0; - - private final Class wrapperType; - private final Class primitiveType; - private final char basicTypeChar; - private final String basicTypeString; - private final Object emptyArray; - - Wrapper(Class wtype, - String wtypeName, - Class ptype, - String ptypeName, - char tchar, - Object emptyArray) { - this.wrapperType = wtype; - this.primitiveType = ptype; - this.basicTypeChar = tchar; - this.basicTypeString = String.valueOf(this.basicTypeChar); - this.emptyArray = emptyArray; - } - - public Object zero() { - return switch (this) { - case BOOLEAN -> Boolean.FALSE; - case INT -> (Integer)0; - case DOUBLE -> DOUBLE_ZERO; - default -> null; - }; - } - } - - enum MyEnum { - DUMMY1, - DUMMY2; - - static final boolean BOOLEAN = true; - static final byte BYTE = -128; - static final short SHORT = -12345; - static final char CHAR = 'c'; - static final int INT = -123456; - static final long LONG = 0x1234567890L; - static final long LONG2 = -0x1234567890L; - static final float FLOAT = 567891.0f; - static final double DOUBLE = 12345678905678.890; - } -} From 17d633a8ee7538625501a90469cb6a68b9ba4820 Mon Sep 17 00:00:00 2001 From: Kelvin Nilsen Date: Wed, 17 Dec 2025 22:21:24 +0000 Subject: [PATCH 346/706] 8373720: GenShen: Count live-at-old mark using Snapshot at Beginning Reviewed-by: ysr --- .../heuristics/shenandoahOldHeuristics.cpp | 9 +++++++-- .../shenandoahGenerationalEvacuationTask.cpp | 3 ++- .../share/gc/shenandoah/shenandoahHeapRegion.hpp | 16 ++++++++++++++++ .../shenandoah/shenandoahHeapRegion.inline.hpp | 1 + 4 files changed, 26 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahOldHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahOldHeuristics.cpp index 1f257560bcb..8bf068df0a8 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahOldHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahOldHeuristics.cpp @@ -335,7 +335,13 @@ void ShenandoahOldHeuristics::prepare_for_old_collections() { size_t garbage = region->garbage(); size_t live_bytes = region->get_live_data_bytes(); - live_data += live_bytes; + if (!region->was_promoted_in_place()) { + // As currently implemented, region->get_live_data_bytes() represents bytes concurrently marked. + // Expansion of the region by promotion during concurrent marking is above TAMS, and is not included + // as live-data at [start of] old marking. + live_data += live_bytes; + } + // else, regions that were promoted in place had 0 old live data at mark start if (region->is_regular() || region->is_regular_pinned()) { // Only place regular or pinned regions with live data into the candidate set. @@ -374,7 +380,6 @@ void ShenandoahOldHeuristics::prepare_for_old_collections() { } } - // TODO: subtract from live_data bytes promoted during concurrent GC. _old_generation->set_live_bytes_at_last_mark(live_data); // Unlike young, we are more interested in efficiently packing OLD-gen than in reclaiming garbage first. We sort by live-data. diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalEvacuationTask.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalEvacuationTask.cpp index de45877994c..c9b956f9c2f 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalEvacuationTask.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalEvacuationTask.cpp @@ -223,7 +223,6 @@ void ShenandoahGenerationalEvacuationTask::promote_in_place(ShenandoahHeapRegion // We do not need to scan above TAMS because restored top equals tams assert(obj_addr == tams, "Expect loop to terminate when obj_addr equals tams"); - { ShenandoahHeapLocker locker(_heap->lock()); @@ -251,6 +250,7 @@ void ShenandoahGenerationalEvacuationTask::promote_in_place(ShenandoahHeapRegion // Transfer this region from young to old, increasing promoted_reserve if available space exceeds plab_min_size() _heap->free_set()->add_promoted_in_place_region_to_old_collector(region); region->set_affiliation(OLD_GENERATION); + region->set_promoted_in_place(); } } @@ -289,6 +289,7 @@ void ShenandoahGenerationalEvacuationTask::promote_humongous(ShenandoahHeapRegio r->index(), p2i(r->bottom()), p2i(r->top())); // We mark the entire humongous object's range as dirty after loop terminates, so no need to dirty the range here r->set_affiliation(OLD_GENERATION); + r->set_promoted_in_place(); } ShenandoahFreeSet* freeset = _heap->free_set(); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp index 2ed5614c698..cf0dc5476d0 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp @@ -262,6 +262,7 @@ private: HeapWord* volatile _update_watermark; uint _age; + bool _promoted_in_place; CENSUS_NOISE(uint _youth;) // tracks epochs of retrograde ageing (rejuvenation) ShenandoahSharedFlag _recycling; // Used to indicate that the region is being recycled; see try_recycle*(). @@ -354,6 +355,15 @@ public: inline void save_top_before_promote(); inline HeapWord* get_top_before_promote() const { return _top_before_promoted; } + + inline void set_promoted_in_place() { + _promoted_in_place = true; + } + + // Returns true iff this region was promoted in place subsequent to the most recent start of concurrent old marking. + inline bool was_promoted_in_place() { + return _promoted_in_place; + } inline void restore_top_before_promote(); inline size_t garbage_before_padded_for_promote() const; @@ -379,7 +389,13 @@ public: inline void increase_live_data_gc_words(size_t s); inline bool has_live() const; + + // Represents the number of live bytes identified by most recent marking effort. Does not include the bytes + // above TAMS. inline size_t get_live_data_bytes() const; + + // Represents the number of live words identified by most recent marking effort. Does not include the words + // above TAMS. inline size_t get_live_data_words() const; inline size_t garbage() const; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.inline.hpp index 69673eb7a60..b9304ee9daa 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.inline.hpp @@ -152,6 +152,7 @@ inline void ShenandoahHeapRegion::internal_increase_live_data(size_t s) { inline void ShenandoahHeapRegion::clear_live_data() { AtomicAccess::store(&_live_data, (size_t)0); + _promoted_in_place = false; } inline size_t ShenandoahHeapRegion::get_live_data_words() const { From c16ce929c7bc127fe18d3faa037d81c2760a44a2 Mon Sep 17 00:00:00 2001 From: Dan Smith Date: Wed, 17 Dec 2025 22:38:50 +0000 Subject: [PATCH 347/706] 8370970: DocCheck failure in jdkDoctypeBadcharsCheck.java and jdkCheckHtml.java Reviewed-by: liach --- test/docs/ProblemList.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/docs/ProblemList.txt b/test/docs/ProblemList.txt index 4df8bbcc53c..83693eacbd1 100644 --- a/test/docs/ProblemList.txt +++ b/test/docs/ProblemList.txt @@ -41,5 +41,3 @@ ############################################################################# jdk/javadoc/doccheck/checks/jdkCheckLinks.java 8370249 generic-all -jdk/javadoc/doccheck/checks/jdkCheckHtml.java 8370970 generic-all -jdk/javadoc/doccheck/checks/jdkDoctypeBadcharsCheck.java 8370970 generic-all From ea5834415db6410c73271c496811ff6b5dcc87ef Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Thu, 18 Dec 2025 01:46:45 +0000 Subject: [PATCH 348/706] 8373887: jpackage tests may potentially deadlock Reviewed-by: almatvee --- .../jdk/jpackage/test/ExecutorTest.java | 8 +++- .../helpers/jdk/jpackage/test/Executor.java | 38 +++++++++++++++++-- 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/ExecutorTest.java b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/ExecutorTest.java index c5d8aed845c..2b075e0f13c 100644 --- a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/ExecutorTest.java +++ b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/ExecutorTest.java @@ -210,7 +210,13 @@ public class ExecutorTest extends JUnitAdapter { assertEquals(0, result[0].getExitCode()); - assertEquals(expectedCapturedSystemOut(commandWithDiscardedStreams), outputCapture.outLines()); + // If we dump the subprocesses's output, and the command produced both STDOUT and STDERR, + // then the captured STDOUT may contain interleaved command's STDOUT and STDERR, + // not in sequential order (STDOUT followed by STDERR). + // In this case don't check the contents of the captured command's STDOUT. + if (toolProvider || outputCapture.outLines().isEmpty() || (command.stdout().isEmpty() || command.stderr().isEmpty())) { + assertEquals(expectedCapturedSystemOut(commandWithDiscardedStreams), outputCapture.outLines()); + } assertEquals(expectedCapturedSystemErr(commandWithDiscardedStreams), outputCapture.errLines()); assertEquals(expectedResultStdout(commandWithDiscardedStreams), result[0].stdout().getOutput()); diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Executor.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Executor.java index 91625603a2b..ef118e525c5 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Executor.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Executor.java @@ -32,6 +32,7 @@ import java.io.InputStreamReader; import java.io.OutputStream; import java.io.PrintStream; import java.io.StringReader; +import java.io.UncheckedIOException; import java.io.Writer; import java.nio.file.Path; import java.util.ArrayList; @@ -42,12 +43,15 @@ import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; import java.util.function.Supplier; import java.util.regex.Pattern; import java.util.spi.ToolProvider; import java.util.stream.Collectors; import java.util.stream.Stream; import jdk.jpackage.internal.util.function.ThrowingSupplier; +import jdk.jpackage.internal.util.function.ExceptionBox; public final class Executor extends CommandArguments { @@ -465,9 +469,37 @@ public final class Executor extends CommandArguments { trace("Execute " + sb.toString() + "..."); Process process = builder.start(); - final var output = combine( - processProcessStream(outputStreamsControl.stdout(), process.getInputStream()), - processProcessStream(outputStreamsControl.stderr(), process.getErrorStream())); + var stdoutGobbler = CompletableFuture.>>supplyAsync(() -> { + try { + return processProcessStream(outputStreamsControl.stdout(), process.getInputStream()); + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + }); + + var stderrGobbler = CompletableFuture.>>supplyAsync(() -> { + try { + return processProcessStream(outputStreamsControl.stderr(), process.getErrorStream()); + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + }); + + final CommandOutput output; + + try { + output = combine(stdoutGobbler.join(), stderrGobbler.join()); + } catch (CompletionException ex) { + var cause = ex.getCause(); + switch (cause) { + case UncheckedIOException uioex -> { + throw uioex.getCause(); + } + default -> { + throw ExceptionBox.toUnchecked(ExceptionBox.unbox(cause)); + } + } + } final int exitCode = process.waitFor(); trace("Done. Exit code: " + exitCode); From 0146077a51635500de771e9cf2c9788ae931b7a0 Mon Sep 17 00:00:00 2001 From: Leonid Mesnik Date: Thu, 18 Dec 2025 04:27:18 +0000 Subject: [PATCH 349/706] 8373723: Deadlock with JvmtiTagMap::flush_object_free_events() Reviewed-by: dholmes, coleenp --- src/hotspot/share/prims/jvmtiTagMap.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/prims/jvmtiTagMap.cpp b/src/hotspot/share/prims/jvmtiTagMap.cpp index 90a3461f321..04cb70863cd 100644 --- a/src/hotspot/share/prims/jvmtiTagMap.cpp +++ b/src/hotspot/share/prims/jvmtiTagMap.cpp @@ -1204,8 +1204,10 @@ void JvmtiTagMap::flush_object_free_events() { assert_not_at_safepoint(); if (env()->is_enabled(JVMTI_EVENT_OBJECT_FREE)) { { + // The other thread can block for safepoints during event callbacks, so ensure we + // are safepoint-safe while waiting. + ThreadBlockInVM tbivm(JavaThread::current()); MonitorLocker ml(lock(), Mutex::_no_safepoint_check_flag); - // If another thread is posting events, let it finish while (_posting_events) { ml.wait(); } From b4462625413e7c2c12778eaad1f2f21d81f59c52 Mon Sep 17 00:00:00 2001 From: Emanuel Peter Date: Thu, 18 Dec 2025 07:04:40 +0000 Subject: [PATCH 350/706] 8373682: Test compiler/loopopts/superword/TestReinterpretAndCast.java fails on x86_64 with AVX but without f16c Reviewed-by: kvn, jsikstro, chagedorn --- .../compiler/loopopts/superword/TestReinterpretAndCast.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestReinterpretAndCast.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestReinterpretAndCast.java index ab2801179f2..9c5140d2aaa 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/TestReinterpretAndCast.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestReinterpretAndCast.java @@ -162,7 +162,7 @@ public class TestReinterpretAndCast { IRNode.STORE_VECTOR, "> 0", IRNode.VECTOR_REINTERPRET, "> 0"}, // We have at least I2F applyIfPlatform = {"64-bit", "true"}, - applyIfCPUFeature = {"avx", "true"}) + applyIfCPUFeatureAnd = {"avx", "true", "f16c", "true"}) @IR(counts = {IRNode.LOAD_VECTOR_I, IRNode.VECTOR_SIZE + "min(max_int, max_float, max_short)", "> 0", IRNode.VECTOR_CAST_F2HF, IRNode.VECTOR_SIZE + "min(max_int, max_float, max_short)", "> 0", IRNode.STORE_VECTOR, "> 0", @@ -208,7 +208,7 @@ public class TestReinterpretAndCast { IRNode.STORE_VECTOR, "> 0", IRNode.VECTOR_REINTERPRET, "> 0"}, // We have at least F2I applyIfPlatform = {"64-bit", "true"}, - applyIfCPUFeature = {"avx", "true"}) + applyIfCPUFeatureAnd = {"avx", "true", "f16c", "true"}) @IR(counts = {IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE + "min(max_float, max_short, max_long)", "> 0", IRNode.VECTOR_CAST_HF2F, IRNode.VECTOR_SIZE + "min(max_float, max_short, max_long)", "> 0", IRNode.VECTOR_CAST_I2L, IRNode.VECTOR_SIZE + "min(max_float, max_short, max_long)", "> 0", From 00050f84d44f3ec23e9c6da52bffd68770010749 Mon Sep 17 00:00:00 2001 From: Emanuel Peter Date: Thu, 18 Dec 2025 07:05:05 +0000 Subject: [PATCH 351/706] 8373502: C2 SuperWord: speculative check uses VPointer variable was pinned after speculative check, leading to bad graph Reviewed-by: thartmann, roland --- src/hotspot/share/opto/vectorization.cpp | 25 +++++++ src/hotspot/share/opto/vectorization.hpp | 16 +++++ ...ingCheckVPointerVariablesNotAvailable.java | 71 +++++++++++++++++++ 3 files changed, 112 insertions(+) create mode 100644 test/hotspot/jtreg/compiler/loopopts/superword/TestAliasingCheckVPointerVariablesNotAvailable.java diff --git a/src/hotspot/share/opto/vectorization.cpp b/src/hotspot/share/opto/vectorization.cpp index 15b2df663b6..230ff280f03 100644 --- a/src/hotspot/share/opto/vectorization.cpp +++ b/src/hotspot/share/opto/vectorization.cpp @@ -1060,6 +1060,29 @@ bool VPointer::can_make_speculative_aliasing_check_with(const VPointer& other) c return false; } + // The speculative check also needs to create the pointer expressions for both + // VPointers. We must check that we can do that, i.e. that all variables of the + // VPointers are available at the speculative check (and not just pre-loop invariant). + if (!this->can_make_pointer_expression_at_speculative_check()) { +#ifdef ASSERT + if (_vloop.is_trace_speculative_aliasing_analysis()) { + tty->print_cr("VPointer::can_make_speculative_aliasing_check_with: not all variables of VPointer are avaialbe at speculative check!"); + this->print_on(tty); + } +#endif + return false; + } + + if (!other.can_make_pointer_expression_at_speculative_check()) { +#ifdef ASSERT + if (_vloop.is_trace_speculative_aliasing_analysis()) { + tty->print_cr("VPointer::can_make_speculative_aliasing_check_with: not all variables of VPointer are avaialbe at speculative check!"); + other.print_on(tty); + } +#endif + return false; + } + return true; } @@ -1147,6 +1170,8 @@ BoolNode* VPointer::make_speculative_aliasing_check_with(const VPointer& other, Node* main_init = new ConvL2INode(main_initL); phase->register_new_node_with_ctrl_of(main_init, pre_init); + assert(vp1.can_make_pointer_expression_at_speculative_check(), "variables must be available early enough to avoid cycles"); + assert(vp2.can_make_pointer_expression_at_speculative_check(), "variables must be available early enough to avoid cycles"); Node* p1_init = vp1.make_pointer_expression(main_init, ctrl); Node* p2_init = vp2.make_pointer_expression(main_init, ctrl); Node* size1 = igvn.longcon(vp1.size()); diff --git a/src/hotspot/share/opto/vectorization.hpp b/src/hotspot/share/opto/vectorization.hpp index aacd406f798..9308712f78a 100644 --- a/src/hotspot/share/opto/vectorization.hpp +++ b/src/hotspot/share/opto/vectorization.hpp @@ -1188,6 +1188,22 @@ private: return true; } + // We already know that all non-iv summands are pre loop invariant. + // See init_are_non_iv_summands_pre_loop_invariant + // That is good enough for alignment computations in the pre-loop limit. But it is not + // sufficient if we want to use the variables of the VPointer at the speculative check, + // which is further up before the pre-loop. + bool can_make_pointer_expression_at_speculative_check() const { + bool success = true; + mem_pointer().for_each_non_empty_summand([&] (const MemPointerSummand& s) { + Node* variable = s.variable(); + if (variable != _vloop.iv() && !_vloop.is_available_for_speculative_check(variable)) { + success = false; + } + }); + return success; + } + // In the pointer analysis, and especially the AlignVector analysis, we assume that // stride and scale are not too large. For example, we multiply "iv_scale * iv_stride", // and assume that this does not overflow the int range. We also take "abs(iv_scale)" diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestAliasingCheckVPointerVariablesNotAvailable.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestAliasingCheckVPointerVariablesNotAvailable.java new file mode 100644 index 00000000000..47540da5648 --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestAliasingCheckVPointerVariablesNotAvailable.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2025, 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 id=with-flags + * @bug 8373502 + * @summary Test where a VPointer variable was pinned at the pre-loop, but not available at the + * Auto_Vectorization_Check, and so it should not be used for the auto vectorization + * aliasing check, to avoid a bad (circular) graph. + * @run main/othervm + * -XX:CompileCommand=compileonly,*TestAliasingCheckVPointerVariablesNotAvailable::test + * -XX:-TieredCompilation + * -Xcomp + * ${test.main.class} + */ + +/* + * @test id=vanilla + * @bug 8373502 + * @run main ${test.main.class} + */ + +package compiler.loopopts.superword; + +public class TestAliasingCheckVPointerVariablesNotAvailable { + static int iFld; + + public static void main(String[] strArr) { + test(); + } + + static void test() { + int iArr[] = new int[400]; + boolean flag = false; + for (int i = 6; i < 50000; i++) { // Trigger OSR + try { + int x = 234 / iFld; + iFld = iArr[3]; + } catch (ArithmeticException a_e) { + } + for (int j = i; j < 2; j++) { + if (flag) { + iArr[j] = 117; + } else { + iArr[1] = 34; + } + iArr[1] += i; + } + } + } +} From e67805067a8f537862200e808e20464f12d21c9c Mon Sep 17 00:00:00 2001 From: Quan Anh Mai Date: Thu, 18 Dec 2025 07:31:06 +0000 Subject: [PATCH 352/706] 8367341: C2: apply KnownBits and unsigned bounds to And / Or operations Reviewed-by: hgreule, epeter --- src/hotspot/share/opto/addnode.cpp | 91 +--- src/hotspot/share/opto/mulnode.cpp | 78 +--- src/hotspot/share/opto/rangeinference.cpp | 8 +- src/hotspot/share/opto/rangeinference.hpp | 231 +++++++++- src/hotspot/share/opto/type.hpp | 2 + src/hotspot/share/opto/utilities/xor.hpp | 47 -- src/hotspot/share/utilities/intn_t.hpp | 1 + .../gtest/opto/test_rangeinference.cpp | 425 +++++++++++++++++- test/hotspot/gtest/opto/test_xor_node.cpp | 102 ----- 9 files changed, 651 insertions(+), 334 deletions(-) delete mode 100644 src/hotspot/share/opto/utilities/xor.hpp delete mode 100644 test/hotspot/gtest/opto/test_xor_node.cpp diff --git a/src/hotspot/share/opto/addnode.cpp b/src/hotspot/share/opto/addnode.cpp index 6075317d86e..accb3d32b67 100644 --- a/src/hotspot/share/opto/addnode.cpp +++ b/src/hotspot/share/opto/addnode.cpp @@ -31,8 +31,8 @@ #include "opto/movenode.hpp" #include "opto/mulnode.hpp" #include "opto/phaseX.hpp" +#include "opto/rangeinference.hpp" #include "opto/subnode.hpp" -#include "opto/utilities/xor.hpp" #include "runtime/stubRoutines.hpp" // Portions of code courtesy of Clifford Click @@ -1011,35 +1011,8 @@ Node* OrINode::Ideal(PhaseGVN* phase, bool can_reshape) { // the logical operations the ring's ADD is really a logical OR function. // This also type-checks the inputs for sanity. Guaranteed never to // be passed a TOP or BOTTOM type, these are filtered out by pre-check. -const Type *OrINode::add_ring( const Type *t0, const Type *t1 ) const { - const TypeInt *r0 = t0->is_int(); // Handy access - const TypeInt *r1 = t1->is_int(); - - // If both args are bool, can figure out better types - if ( r0 == TypeInt::BOOL ) { - if ( r1 == TypeInt::ONE) { - return TypeInt::ONE; - } else if ( r1 == TypeInt::BOOL ) { - return TypeInt::BOOL; - } - } else if ( r0 == TypeInt::ONE ) { - if ( r1 == TypeInt::BOOL ) { - return TypeInt::ONE; - } - } - - // If either input is all ones, the output is all ones. - // x | ~0 == ~0 <==> x | -1 == -1 - if (r0 == TypeInt::MINUS_1 || r1 == TypeInt::MINUS_1) { - return TypeInt::MINUS_1; - } - - // If either input is not a constant, just return all integers. - if( !r0->is_con() || !r1->is_con() ) - return TypeInt::INT; // Any integer, but still no symbols. - - // Otherwise just OR them bits. - return TypeInt::make( r0->get_con() | r1->get_con() ); +const Type* OrINode::add_ring(const Type* t1, const Type* t2) const { + return RangeInference::infer_or(t1->is_int(), t2->is_int()); } //============================================================================= @@ -1087,22 +1060,8 @@ Node* OrLNode::Ideal(PhaseGVN* phase, bool can_reshape) { } //------------------------------add_ring--------------------------------------- -const Type *OrLNode::add_ring( const Type *t0, const Type *t1 ) const { - const TypeLong *r0 = t0->is_long(); // Handy access - const TypeLong *r1 = t1->is_long(); - - // If either input is all ones, the output is all ones. - // x | ~0 == ~0 <==> x | -1 == -1 - if (r0 == TypeLong::MINUS_1 || r1 == TypeLong::MINUS_1) { - return TypeLong::MINUS_1; - } - - // If either input is not a constant, just return all integers. - if( !r0->is_con() || !r1->is_con() ) - return TypeLong::LONG; // Any integer, but still no symbols. - - // Otherwise just OR them bits. - return TypeLong::make( r0->get_con() | r1->get_con() ); +const Type* OrLNode::add_ring(const Type* t1, const Type* t2) const { + return RangeInference::infer_or(t1->is_long(), t2->is_long()); } //---------------------------Helper ------------------------------------------- @@ -1189,46 +1148,14 @@ const Type* XorINode::Value(PhaseGVN* phase) const { // the logical operations the ring's ADD is really a logical OR function. // This also type-checks the inputs for sanity. Guaranteed never to // be passed a TOP or BOTTOM type, these are filtered out by pre-check. -const Type *XorINode::add_ring( const Type *t0, const Type *t1 ) const { - const TypeInt *r0 = t0->is_int(); // Handy access - const TypeInt *r1 = t1->is_int(); - - if (r0->is_con() && r1->is_con()) { - // compute constant result - return TypeInt::make(r0->get_con() ^ r1->get_con()); - } - - // At least one of the arguments is not constant - - if (r0->_lo >= 0 && r1->_lo >= 0) { - // Combine [r0->_lo, r0->_hi] ^ [r0->_lo, r1->_hi] -> [0, upper_bound] - jint upper_bound = xor_upper_bound_for_ranges(r0->_hi, r1->_hi); - return TypeInt::make(0, upper_bound, MAX2(r0->_widen, r1->_widen)); - } - - return TypeInt::INT; +const Type* XorINode::add_ring(const Type* t1, const Type* t2) const { + return RangeInference::infer_xor(t1->is_int(), t2->is_int()); } //============================================================================= //------------------------------add_ring--------------------------------------- -const Type *XorLNode::add_ring( const Type *t0, const Type *t1 ) const { - const TypeLong *r0 = t0->is_long(); // Handy access - const TypeLong *r1 = t1->is_long(); - - if (r0->is_con() && r1->is_con()) { - // compute constant result - return TypeLong::make(r0->get_con() ^ r1->get_con()); - } - - // At least one of the arguments is not constant - - if (r0->_lo >= 0 && r1->_lo >= 0) { - // Combine [r0->_lo, r0->_hi] ^ [r0->_lo, r1->_hi] -> [0, upper_bound] - julong upper_bound = xor_upper_bound_for_ranges(r0->_hi, r1->_hi); - return TypeLong::make(0, upper_bound, MAX2(r0->_widen, r1->_widen)); - } - - return TypeLong::LONG; +const Type* XorLNode::add_ring(const Type* t1, const Type* t2) const { + return RangeInference::infer_xor(t1->is_long(), t2->is_long()); } Node* XorLNode::Ideal(PhaseGVN* phase, bool can_reshape) { diff --git a/src/hotspot/share/opto/mulnode.cpp b/src/hotspot/share/opto/mulnode.cpp index 280781f686b..aa8d6cfce2e 100644 --- a/src/hotspot/share/opto/mulnode.cpp +++ b/src/hotspot/share/opto/mulnode.cpp @@ -29,6 +29,7 @@ #include "opto/memnode.hpp" #include "opto/mulnode.hpp" #include "opto/phaseX.hpp" +#include "opto/rangeinference.hpp" #include "opto/subnode.hpp" #include "utilities/powerOfTwo.hpp" @@ -620,80 +621,14 @@ const Type* MulHiValue(const Type *t1, const Type *t2, const Type *bot) { return TypeLong::LONG; } -template -static const IntegerType* and_value(const IntegerType* r0, const IntegerType* r1) { - typedef typename IntegerType::NativeType NativeType; - static_assert(std::is_signed::value, "Native type of IntegerType must be signed!"); - - int widen = MAX2(r0->_widen, r1->_widen); - - // If both types are constants, we can calculate a constant result. - if (r0->is_con() && r1->is_con()) { - return IntegerType::make(r0->get_con() & r1->get_con()); - } - - // If both ranges are positive, the result will range from 0 up to the hi value of the smaller range. The minimum - // of the two constrains the upper bound because any higher value in the other range will see all zeroes, so it will be masked out. - if (r0->_lo >= 0 && r1->_lo >= 0) { - return IntegerType::make(0, MIN2(r0->_hi, r1->_hi), widen); - } - - // If only one range is positive, the result will range from 0 up to that range's maximum value. - // For the operation 'x & C' where C is a positive constant, the result will be in the range [0..C]. With that observation, - // we can say that for any integer c such that 0 <= c <= C will also be in the range [0..C]. Therefore, 'x & [c..C]' - // where c >= 0 will be in the range [0..C]. - if (r0->_lo >= 0) { - return IntegerType::make(0, r0->_hi, widen); - } - - if (r1->_lo >= 0) { - return IntegerType::make(0, r1->_hi, widen); - } - - // At this point, all positive ranges will have already been handled, so the only remaining cases will be negative ranges - // and constants. - - assert(r0->_lo < 0 && r1->_lo < 0, "positive ranges should already be handled!"); - - // As two's complement means that both numbers will start with leading 1s, the lower bound of both ranges will contain - // the common leading 1s of both minimum values. In order to count them with count_leading_zeros, the bits are inverted. - NativeType sel_val = ~MIN2(r0->_lo, r1->_lo); - - NativeType min; - if (sel_val == 0) { - // Since count_leading_zeros is undefined at 0, we short-circuit the condition where both ranges have a minimum of -1. - min = -1; - } else { - // To get the number of bits to shift, we count the leading 0-bits and then subtract one, as the sign bit is already set. - int shift_bits = count_leading_zeros(sel_val) - 1; - min = std::numeric_limits::min() >> shift_bits; - } - - NativeType max; - if (r0->_hi < 0 && r1->_hi < 0) { - // If both ranges are negative, then the same optimization as both positive ranges will apply, and the smaller hi - // value will mask off any bits set by higher values. - max = MIN2(r0->_hi, r1->_hi); - } else { - // In the case of ranges that cross zero, negative values can cause the higher order bits to be set, so the maximum - // positive value can be as high as the larger hi value. - max = MAX2(r0->_hi, r1->_hi); - } - - return IntegerType::make(min, max, widen); -} - //============================================================================= //------------------------------mul_ring--------------------------------------- // Supplied function returns the product of the inputs IN THE CURRENT RING. // For the logical operations the ring's MUL is really a logical AND function. // This also type-checks the inputs for sanity. Guaranteed never to // be passed a TOP or BOTTOM type, these are filtered out by pre-check. -const Type *AndINode::mul_ring( const Type *t0, const Type *t1 ) const { - const TypeInt* r0 = t0->is_int(); - const TypeInt* r1 = t1->is_int(); - - return and_value(r0, r1); +const Type* AndINode::mul_ring(const Type* t1, const Type* t2) const { + return RangeInference::infer_and(t1->is_int(), t2->is_int()); } static bool AndIL_is_zero_element_under_mask(const PhaseGVN* phase, const Node* expr, const Node* mask, BasicType bt); @@ -822,11 +757,8 @@ Node *AndINode::Ideal(PhaseGVN *phase, bool can_reshape) { // For the logical operations the ring's MUL is really a logical AND function. // This also type-checks the inputs for sanity. Guaranteed never to // be passed a TOP or BOTTOM type, these are filtered out by pre-check. -const Type *AndLNode::mul_ring( const Type *t0, const Type *t1 ) const { - const TypeLong* r0 = t0->is_long(); - const TypeLong* r1 = t1->is_long(); - - return and_value(r0, r1); +const Type* AndLNode::mul_ring(const Type* t1, const Type* t2) const { + return RangeInference::infer_and(t1->is_long(), t2->is_long()); } const Type* AndLNode::Value(PhaseGVN* phase) const { diff --git a/src/hotspot/share/opto/rangeinference.cpp b/src/hotspot/share/opto/rangeinference.cpp index 40b9da4bde5..cb26e68ef58 100644 --- a/src/hotspot/share/opto/rangeinference.cpp +++ b/src/hotspot/share/opto/rangeinference.cpp @@ -25,7 +25,6 @@ #include "opto/rangeinference.hpp" #include "opto/type.hpp" #include "utilities/intn_t.hpp" -#include "utilities/tuple.hpp" // If the cardinality of a TypeInt is below this threshold, use min widen, see // TypeIntPrototype::normalize_widen @@ -688,6 +687,8 @@ template class TypeIntPrototype, uintn_t<1>>; template class TypeIntPrototype, uintn_t<2>>; template class TypeIntPrototype, uintn_t<3>>; template class TypeIntPrototype, uintn_t<4>>; +template class TypeIntPrototype, uintn_t<5>>; +template class TypeIntPrototype, uintn_t<6>>; // Compute the meet of 2 types. When dual is true, the subset relation in CT is // reversed. This means that the result of 2 CTs would be the intersection of @@ -709,10 +710,7 @@ const Type* TypeIntHelper::int_type_xmeet(const CT* i1, const Type* t2) { if (!i1->_is_dual) { // meet (a.k.a union) - return CT::make_or_top(TypeIntPrototype{{MIN2(i1->_lo, i2->_lo), MAX2(i1->_hi, i2->_hi)}, - {MIN2(i1->_ulo, i2->_ulo), MAX2(i1->_uhi, i2->_uhi)}, - {i1->_bits._zeros & i2->_bits._zeros, i1->_bits._ones & i2->_bits._ones}}, - MAX2(i1->_widen, i2->_widen), false); + return int_type_union(i1, i2); } else { // join (a.k.a intersection) return CT::make_or_top(TypeIntPrototype{{MAX2(i1->_lo, i2->_lo), MIN2(i1->_hi, i2->_hi)}, diff --git a/src/hotspot/share/opto/rangeinference.hpp b/src/hotspot/share/opto/rangeinference.hpp index 73b8b43bd6e..ebfd98ca4a6 100644 --- a/src/hotspot/share/opto/rangeinference.hpp +++ b/src/hotspot/share/opto/rangeinference.hpp @@ -25,6 +25,7 @@ #ifndef SHARE_OPTO_RANGEINFERENCE_HPP #define SHARE_OPTO_RANGEINFERENCE_HPP +#include "cppstdlib/limits.hpp" #include "cppstdlib/type_traits.hpp" #include "utilities/globalDefinitions.hpp" @@ -92,19 +93,6 @@ public: RangeInt _urange; KnownBits _bits; -private: - friend class TypeInt; - friend class TypeLong; - - template - friend void test_canonicalize_constraints_exhaustive(); - - template - friend void test_canonicalize_constraints_simple(); - - template - friend void test_canonicalize_constraints_random(); - // A canonicalized version of a TypeIntPrototype, if the prototype represents // an empty type, _present is false, otherwise, _data is canonical class CanonicalizedTypeIntPrototype { @@ -158,21 +146,33 @@ public: template static const Type* int_type_xmeet(const CT* i1, const Type* t2); - template - static bool int_type_is_equal(const CT* t1, const CT* t2) { + template + static CTP int_type_union(CTP t1, CTP t2) { + using CT = std::conditional_t, std::remove_pointer_t, CTP>; + using S = std::remove_const_t; + using U = std::remove_const_t; + return CT::make(TypeIntPrototype{{MIN2(t1->_lo, t2->_lo), MAX2(t1->_hi, t2->_hi)}, + {MIN2(t1->_ulo, t2->_ulo), MAX2(t1->_uhi, t2->_uhi)}, + {t1->_bits._zeros & t2->_bits._zeros, t1->_bits._ones & t2->_bits._ones}}, + MAX2(t1->_widen, t2->_widen)); + } + + template + static bool int_type_is_equal(const CTP t1, const CTP t2) { return t1->_lo == t2->_lo && t1->_hi == t2->_hi && t1->_ulo == t2->_ulo && t1->_uhi == t2->_uhi && t1->_bits._zeros == t2->_bits._zeros && t1->_bits._ones == t2->_bits._ones; } - template - static bool int_type_is_subset(const CT* super, const CT* sub) { + template + static bool int_type_is_subset(const CTP super, const CTP sub) { + using U = decltype(super->_ulo); return super->_lo <= sub->_lo && super->_hi >= sub->_hi && super->_ulo <= sub->_ulo && super->_uhi >= sub->_uhi && // All bits that are known in super must also be known to be the same // value in sub, &~ (and not) is the same as a set subtraction on bit // sets - (super->_bits._zeros &~ sub->_bits._zeros) == 0 && (super->_bits._ones &~ sub->_bits._ones) == 0; + (super->_bits._zeros &~ sub->_bits._zeros) == U(0) && (super->_bits._ones &~ sub->_bits._ones) == U(0); } template @@ -195,4 +195,199 @@ public: #endif // PRODUCT }; +// A TypeIntMirror is structurally similar to a TypeInt or a TypeLong but it decouples the range +// inference from the Type infrastructure of the compiler. It also allows more flexibility with the +// bit width of the integer type. As a result, it is more efficient to use for intermediate steps +// of inference, as well as more flexible to perform testing on different integer types. +template +class TypeIntMirror { +public: + S _lo; + S _hi; + U _ulo; + U _uhi; + KnownBits _bits; + int _widen = 0; // dummy field to mimic the same field in TypeInt, useful in testing + + static TypeIntMirror make(const TypeIntPrototype& t, int widen) { + auto canonicalized_t = t.canonicalize_constraints(); + assert(!canonicalized_t.empty(), "must not be empty"); + return TypeIntMirror{canonicalized_t._data._srange._lo, canonicalized_t._data._srange._hi, + canonicalized_t._data._urange._lo, canonicalized_t._data._urange._hi, + canonicalized_t._data._bits}; + } + + // These allow TypeIntMirror to mimick the behaviors of TypeInt* and TypeLong*, so they can be + // passed into RangeInference methods. These are only used in testing, so they are implemented in + // the test file. + const TypeIntMirror* operator->() const; + TypeIntMirror meet(const TypeIntMirror& o) const; + bool contains(U u) const; + bool contains(const TypeIntMirror& o) const; + bool operator==(const TypeIntMirror& o) const; + + template + TypeIntMirror cast() const; +}; + +// This class contains methods for inferring the Type of the result of several arithmetic +// operations from those of the corresponding inputs. For example, given a, b such that the Type of +// a is [0, 1] and the Type of b is [-1, 3], then the Type of the sum a + b is [-1, 4]. +// The methods in this class receive one or more template parameters which are often TypeInt* or +// TypeLong*, or they can be TypeIntMirror which behave similar to TypeInt* and TypeLong* during +// testing. This allows us to verify the correctness of the implementation without coupling with +// the hotspot compiler allocation infrastructure. +class RangeInference { +private: + // If CTP is a pointer, get the underlying type. For the test helper classes, using the struct + // directly allows straightfoward equality comparison. + template + using CT = std::remove_const_t, std::remove_pointer_t, CTP>>; + + // The type of CT::_lo, should be jint for TypeInt* and jlong for TypeLong* + template + using S = std::remove_const_t::_lo)>; + + // The type of CT::_ulo, should be juint for TypeInt* and julong for TypeLong* + template + using U = std::remove_const_t::_ulo)>; + + // A TypeInt consists of 1 or 2 simple intervals, each of which will lie either in the interval + // [0, max_signed] or [min_signed, -1]. It is more optimal to analyze each simple interval + // separately when doing inference. For example, consider a, b whose Types are both [-2, 2]. By + // analyzing the interval [-2, -1] and [0, 2] separately, we can easily see that the result of + // a & b must also be in the interval [-2, 2]. This is much harder if we want to work with the + // whole value range at the same time. + // This class offers a convenient way to traverse all the simple interval of a TypeInt. + template + class SimpleIntervalIterable { + private: + TypeIntMirror, U> _first_interval; + TypeIntMirror, U> _second_interval; + int _interval_num; + + public: + SimpleIntervalIterable(CTP t) { + if (U(t->_lo) <= U(t->_hi)) { + _interval_num = 1; + _first_interval = TypeIntMirror, U>{t->_lo, t->_hi, t->_ulo, t->_uhi, t->_bits}; + } else { + _interval_num = 2; + _first_interval = TypeIntMirror, U>::make(TypeIntPrototype, U>{{t->_lo, S(t->_uhi)}, {U(t->_lo), t->_uhi}, t->_bits}, 0); + _second_interval = TypeIntMirror, U>::make(TypeIntPrototype, U>{{S(t->_ulo), t->_hi}, {t->_ulo, U(t->_hi)}, t->_bits}, 0); + } + } + + class Iterator { + private: + const SimpleIntervalIterable& _iterable; + int _current_interval; + + Iterator(const SimpleIntervalIterable& iterable) : _iterable(iterable), _current_interval(0) {} + + friend class SimpleIntervalIterable; + public: + const TypeIntMirror, U>& operator*() const { + assert(_current_interval < _iterable._interval_num, "out of bounds, %d - %d", _current_interval, _iterable._interval_num); + if (_current_interval == 0) { + return _iterable._first_interval; + } else { + return _iterable._second_interval; + } + } + + Iterator& operator++() { + assert(_current_interval < _iterable._interval_num, "out of bounds, %d - %d", _current_interval, _iterable._interval_num); + _current_interval++; + return *this; + } + + bool operator!=(const Iterator& o) const { + assert(&_iterable == &o._iterable, "not on the same iterable"); + return _current_interval != o._current_interval; + } + }; + + Iterator begin() const { + return Iterator(*this); + } + + Iterator end() const { + Iterator res(*this); + res._current_interval = _interval_num; + return res; + } + }; + + // Infer a result given the input types of a binary operation + template + static CTP infer_binary(CTP t1, CTP t2, Inference infer) { + CTP res; + bool is_init = false; + + SimpleIntervalIterable t1_simple_intervals(t1); + SimpleIntervalIterable t2_simple_intervals(t2); + + for (auto& st1 : t1_simple_intervals) { + for (auto& st2 : t2_simple_intervals) { + CTP current = infer(st1, st2); + + if (is_init) { + res = res->meet(current)->template cast>(); + } else { + is_init = true; + res = current; + } + } + } + + assert(is_init, "must be initialized"); + return res; + } + +public: + template + static CTP infer_and(CTP t1, CTP t2) { + return infer_binary(t1, t2, [&](const TypeIntMirror, U>& st1, const TypeIntMirror, U>& st2) { + S lo = std::numeric_limits>::min(); + S hi = std::numeric_limits>::max(); + U ulo = std::numeric_limits>::min(); + // The unsigned value of the result of 'and' is always not greater than both of its inputs + // since there is no position at which the bit is 1 in the result and 0 in either input + U uhi = MIN2(st1._uhi, st2._uhi); + U zeros = st1._bits._zeros | st2._bits._zeros; + U ones = st1._bits._ones & st2._bits._ones; + return CT::make(TypeIntPrototype, U>{{lo, hi}, {ulo, uhi}, {zeros, ones}}, MAX2(t1->_widen, t2->_widen)); + }); + } + + template + static CTP infer_or(CTP t1, CTP t2) { + return infer_binary(t1, t2, [&](const TypeIntMirror, U>& st1, const TypeIntMirror, U>& st2) { + S lo = std::numeric_limits>::min(); + S hi = std::numeric_limits>::max(); + // The unsigned value of the result of 'or' is always not less than both of its inputs since + // there is no position at which the bit is 0 in the result and 1 in either input + U ulo = MAX2(st1._ulo, st2._ulo); + U uhi = std::numeric_limits>::max(); + U zeros = st1._bits._zeros & st2._bits._zeros; + U ones = st1._bits._ones | st2._bits._ones; + return CT::make(TypeIntPrototype, U>{{lo, hi}, {ulo, uhi}, {zeros, ones}}, MAX2(t1->_widen, t2->_widen)); + }); + } + + template + static CTP infer_xor(CTP t1, CTP t2) { + return infer_binary(t1, t2, [&](const TypeIntMirror, U>& st1, const TypeIntMirror, U>& st2) { + S lo = std::numeric_limits>::min(); + S hi = std::numeric_limits>::max(); + U ulo = std::numeric_limits>::min(); + U uhi = std::numeric_limits>::max(); + U zeros = (st1._bits._zeros & st2._bits._zeros) | (st1._bits._ones & st2._bits._ones); + U ones = (st1._bits._zeros & st2._bits._ones) | (st1._bits._ones & st2._bits._zeros); + return CT::make(TypeIntPrototype, U>{{lo, hi}, {ulo, uhi}, {zeros, ones}}, MAX2(t1->_widen, t2->_widen)); + }); + } +}; + #endif // SHARE_OPTO_RANGEINFERENCE_HPP diff --git a/src/hotspot/share/opto/type.hpp b/src/hotspot/share/opto/type.hpp index 4666cfbcf2d..73e2ba0045a 100644 --- a/src/hotspot/share/opto/type.hpp +++ b/src/hotspot/share/opto/type.hpp @@ -798,6 +798,7 @@ public: // must always specify w static const TypeInt* make(jint lo, jint hi, int widen); static const Type* make_or_top(const TypeIntPrototype& t, int widen); + static const TypeInt* make(const TypeIntPrototype& t, int widen) { return make_or_top(t, widen)->is_int(); } // Check for single integer bool is_con() const { return _lo == _hi; } @@ -879,6 +880,7 @@ public: // must always specify w static const TypeLong* make(jlong lo, jlong hi, int widen); static const Type* make_or_top(const TypeIntPrototype& t, int widen); + static const TypeLong* make(const TypeIntPrototype& t, int widen) { return make_or_top(t, widen)->is_long(); } // Check for single integer bool is_con() const { return _lo == _hi; } diff --git a/src/hotspot/share/opto/utilities/xor.hpp b/src/hotspot/share/opto/utilities/xor.hpp deleted file mode 100644 index 20edaf0d017..00000000000 --- a/src/hotspot/share/opto/utilities/xor.hpp +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef SHARE_OPTO_UTILITIES_XOR_HPP -#define SHARE_OPTO_UTILITIES_XOR_HPP - -#include "utilities/powerOfTwo.hpp" -// Code separated into its own header to allow access from GTEST - -// Given 2 non-negative values in the ranges [0, hi_0] and [0, hi_1], respectively. The bitwise -// xor of these values should also be non-negative. This method calculates an upper bound. - -// S and U type parameters correspond to the signed and unsigned -// variants of an integer to operate on. -template -static S xor_upper_bound_for_ranges(const S hi_0, const S hi_1) { - static_assert(S(-1) < S(0), "S must be signed"); - static_assert(U(-1) > U(0), "U must be unsigned"); - - assert(hi_0 >= 0, "must be non-negative"); - assert(hi_1 >= 0, "must be non-negative"); - - // x ^ y cannot have any bit set that is higher than both the highest bits set in x and y - // x cannot have any bit set that is higher than the highest bit set in hi_0 - // y cannot have any bit set that is higher than the highest bit set in hi_1 - - // We want to find a value that has all 1 bits everywhere up to and including - // the highest bits set in hi_0 as well as hi_1. For this, we can take the next - // power of 2 strictly greater than both hi values and subtract 1 from it. - - // Example 1: - // hi_0 = 5 (0b0101) hi_1=1 (0b0001) - // (5|1)+1 = 0b0110 - // round_up_pow2 = 0b1000 - // -1 = 0b0111 = max - - // Example 2 - this demonstrates need for the +1: - // hi_0 = 4 (0b0100) hi_1=4 (0b0100) - // (4|4)+1 = 0b0101 - // round_up_pow2 = 0b1000 - // -1 = 0b0111 = max - // Without the +1, round_up_pow2 would be 0b0100, resulting in 0b0011 as max - - // Note: cast to unsigned happens before +1 to avoid signed overflow, and - // round_up is safe because high bit is unset (0 <= lo <= hi) - - return round_up_power_of_2(U(hi_0 | hi_1) + 1) - 1; -} - -#endif // SHARE_OPTO_UTILITIES_XOR_HPP diff --git a/src/hotspot/share/utilities/intn_t.hpp b/src/hotspot/share/utilities/intn_t.hpp index 6f43f5c2556..594e62a1694 100644 --- a/src/hotspot/share/utilities/intn_t.hpp +++ b/src/hotspot/share/utilities/intn_t.hpp @@ -79,6 +79,7 @@ public: static_assert(min < max, ""); constexpr bool operator==(intn_t o) const { return (_v & _mask) == (o._v & _mask); } + constexpr bool operator!=(intn_t o) const { return !(*this == o); } constexpr bool operator<(intn_t o) const { return int(*this) < int(o); } constexpr bool operator>(intn_t o) const { return int(*this) > int(o); } constexpr bool operator<=(intn_t o) const { return int(*this) <= int(o); } diff --git a/test/hotspot/gtest/opto/test_rangeinference.cpp b/test/hotspot/gtest/opto/test_rangeinference.cpp index 1a62941a486..61a9ff7fb70 100644 --- a/test/hotspot/gtest/opto/test_rangeinference.cpp +++ b/test/hotspot/gtest/opto/test_rangeinference.cpp @@ -25,15 +25,16 @@ #include "opto/rangeinference.hpp" #include "opto/type.hpp" #include "runtime/os.hpp" -#include "utilities/intn_t.hpp" #include "unittest.hpp" +#include "utilities/intn_t.hpp" +#include "utilities/rbTree.hpp" +#include +#include +#include template -static U uniform_random(); - -template <> -juint uniform_random() { - return os::random(); +static U uniform_random() { + return U(juint(os::random())); } template <> @@ -201,7 +202,7 @@ static void test_canonicalize_constraints_random() { } } -TEST_VM(opto, canonicalize_constraints) { +TEST(opto, canonicalize_constraints) { test_canonicalize_constraints_trivial(); test_canonicalize_constraints_exhaustive, uintn_t<1>>(); test_canonicalize_constraints_exhaustive, uintn_t<2>>(); @@ -212,3 +213,413 @@ TEST_VM(opto, canonicalize_constraints) { test_canonicalize_constraints_random(); test_canonicalize_constraints_random(); } + +// Implementations of TypeIntMirror methods for testing purposes +template +const TypeIntMirror* TypeIntMirror::operator->() const { + return this; +} + +template +TypeIntMirror TypeIntMirror::meet(const TypeIntMirror& o) const { + return TypeIntHelper::int_type_union(*this, o); +} + +template +bool TypeIntMirror::contains(U u) const { + S s = S(u); + return s >= _lo && s <= _hi && u >= _ulo && u <= _uhi && _bits.is_satisfied_by(u); +} + +template +bool TypeIntMirror::contains(const TypeIntMirror& o) const { + return TypeIntHelper::int_type_is_subset(*this, o); +} + +template +bool TypeIntMirror::operator==(const TypeIntMirror& o) const { + return TypeIntHelper::int_type_is_equal(*this, o); +} + +template +template +TypeIntMirror TypeIntMirror::cast() const { + static_assert(std::is_same_v); + return *this; +} + +// The number of TypeIntMirror instances for integral types with a few bits. These values are +// calculated once and written down for usage in constexpr contexts. +template +static constexpr size_t all_instances_size() { + using U = decltype(CTP::_ulo); + constexpr juint max_unsigned = juint(std::numeric_limits::max()); + if constexpr (max_unsigned == 1U) { + // 1 bit + return 3; + } else if constexpr (max_unsigned == 3U) { + // 2 bits + return 15; + } else if constexpr (max_unsigned == 7U) { + // 3 bits + return 134; + } else { + // 4 bits + static_assert(max_unsigned == 15U); + // For more than 4 bits, the number of instances is too large and it is not realistic to + // compute all of them. + return 1732; + } +} + +template +static std::array()> compute_all_instances() { + using S = decltype(CTP::_lo); + using U = decltype(CTP::_ulo); + + class CTPComparator { + public: + static RBTreeOrdering cmp(const CTP& x, const RBNode* node) { + // Quick helper for the tediousness below + auto f = [](auto x, auto y) { + assert(x != y, "we only handle lt and gt cases"); + return x < y ? RBTreeOrdering::LT : RBTreeOrdering::GT; + }; + + const CTP& y = node->key(); + if (x._lo != y._lo) { + return f(x._lo, y._lo); + } else if (x._hi != y._hi) { + return f(x._hi, y._hi); + } else if (x._ulo != y._ulo) { + return f(x._ulo, y._ulo); + } else if (x._uhi != y._uhi) { + return f(x._uhi, y._uhi); + } else if (x._bits._zeros != y._bits._zeros) { + return f(x._bits._zeros, y._bits._zeros); + } else if (x._bits._ones != y._bits._ones) { + return f(x._bits._ones, y._bits._ones); + } else { + return RBTreeOrdering::EQ; + } + } + }; + + RBTreeCHeap collector; + for (jint lo = jint(std::numeric_limits::min()); lo <= jint(std::numeric_limits::max()); lo++) { + for (jint hi = lo; hi <= jint(std::numeric_limits::max()); hi++) { + for (juint ulo = 0; ulo <= juint(std::numeric_limits::max()); ulo++) { + for (juint uhi = ulo; uhi <= juint(std::numeric_limits::max()); uhi++) { + for (juint zeros = 0; zeros <= juint(std::numeric_limits::max()); zeros++) { + for (juint ones = 0; ones <= juint(std::numeric_limits::max()); ones++) { + TypeIntPrototype t{{S(lo), S(hi)}, {U(ulo), U(uhi)}, {U(zeros), U(ones)}}; + auto canonicalized_t = t.canonicalize_constraints(); + if (canonicalized_t.empty()) { + continue; + } + + TypeIntPrototype ct = canonicalized_t._data; + collector.upsert(CTP{ct._srange._lo, ct._srange._hi, ct._urange._lo, ct._urange._hi, ct._bits}, 0); + } + } + } + } + } + } + + assert(collector.size() == all_instances_size(), "unexpected size of all_instance, expected %d, actual %d", jint(all_instances_size()), jint(collector.size())); + std::array()> res; + size_t idx = 0; + collector.visit_in_order([&](RBNode* node) { + res[idx] = node->key(); + idx++; + return true; + }); + return res; +} + +template +static const std::array()>& all_instances() { + static std::array()> res = compute_all_instances(); + static_assert(std::is_trivially_destructible_v); + return res; +} + +// Check the correctness, that is, if v1 is an element of input1, v2 is an element of input2, then +// op(v1, v2) must be an element of infer(input1, input2). This version does the check exhaustively +// on all elements of input1 and input2. +template +static void test_binary_instance_correctness_exhaustive(Operation op, Inference infer, const InputType& input1, const InputType& input2) { + using S = std::remove_const_t_lo)>; + using U = std::remove_const_t_ulo)>; + InputType result = infer(input1, input2); + + for (juint v1 = juint(std::numeric_limits::min()); v1 <= juint(std::numeric_limits::max()); v1++) { + if (!input1.contains(U(v1))) { + continue; + } + + for (juint v2 = juint(std::numeric_limits::min()); v2 <= juint(std::numeric_limits::max()); v2++) { + if (!input2.contains(U(v2))) { + continue; + } + + U r = op(U(v1), U(v2)); + ASSERT_TRUE(result.contains(r)); + } + } +} + +// Check the correctness, that is, if v1 is an element of input1, v2 is an element of input2, then +// op(v1, v2) must be an element of infer(input1, input2). This version does the check randomly on +// a number of elements in input1 and input2. +template +static void test_binary_instance_correctness_samples(Operation op, Inference infer, const InputType& input1, const InputType& input2) { + using U = std::remove_const_t_ulo)>; + auto result = infer(input1, input2); + + constexpr size_t sample_count = 6; + U input1_samples[sample_count] {U(input1._lo), U(input1._hi), input1._ulo, input1._uhi, input1._ulo, input1._ulo}; + U input2_samples[sample_count] {U(input2._lo), U(input2._hi), input2._ulo, input2._uhi, input2._ulo, input2._ulo}; + + auto random_sample = [](U* samples, const InputType& input) { + constexpr size_t max_tries = 100; + constexpr size_t start_random_idx = 4; + for (size_t tries = 0, idx = start_random_idx; tries < max_tries && idx < sample_count; tries++) { + U n = uniform_random(); + if (input.contains(n)) { + samples[idx] = n; + idx++; + } + } + }; + random_sample(input1_samples, input1); + random_sample(input2_samples, input2); + + for (size_t i = 0; i < sample_count; i++) { + for (size_t j = 0; j < sample_count; j++) { + U r = op(input1_samples[i], input2_samples[j]); + ASSERT_TRUE(result.contains(r)); + } + } +} + +// Check the monotonicity, that is, if input1 is a subset of super1, input2 is a subset of super2, +// then infer(input1, input2) must be a subset of infer(super1, super2). This version does the +// check exhaustively on all supersets of input1 and input2. +template +static void test_binary_instance_monotonicity_exhaustive(Inference infer, const InputType& input1, const InputType& input2) { + InputType result = infer(input1, input2); + + for (const InputType& super1 : all_instances()) { + if (!super1.contains(input1) || super1 == input1) { + continue; + } + + for (const InputType& super2 : all_instances()) { + if (!super2.contains(input2) || super2 == input2) { + continue; + } + + ASSERT_TRUE(infer(input1, super2).contains(result)); + ASSERT_TRUE(infer(super1, input2).contains(result)); + ASSERT_TRUE(infer(super1, super2).contains(result)); + } + } +} + +// Check the monotonicity, that is, if input1 is a subset of super1, input2 is a subset of super2, +// then infer(input1, input2) must be a subset of infer(super1, super2). This version does the +// check randomly on a number of supersets of input1 and input2. +template +static void test_binary_instance_monotonicity_samples(Inference infer, const InputType& input1, const InputType& input2) { + using S = std::remove_const_t_lo)>; + using U = std::remove_const_t_ulo)>; + auto result = infer(input1, input2); + + // The set that is a superset of all other sets + InputType universe = InputType{std::numeric_limits::min(), std::numeric_limits::max(), U(0), U(-1), {U(0), U(0)}}; + ASSERT_TRUE(infer(universe, input2).contains(result)); + ASSERT_TRUE(infer(input1, universe).contains(result)); + ASSERT_TRUE(infer(universe, universe).contains(result)); + + auto random_superset = [](const InputType& input) { + S lo = MIN2(input->_lo, S(uniform_random())); + S hi = MAX2(input->_hi, S(uniform_random())); + U ulo = MIN2(input->_ulo, uniform_random()); + U uhi = MAX2(input->_uhi, uniform_random()); + U zeros = input->_bits._zeros & uniform_random(); + U ones = input->_bits._ones & uniform_random(); + InputType super = InputType::make(TypeIntPrototype{{lo, hi}, {ulo, uhi}, {zeros, ones}}, 0); + assert(super.contains(input), "impossible"); + return super; + }; + + InputType super1 = random_superset(input1); + InputType super2 = random_superset(input2); + ASSERT_TRUE(infer(super1, input2).contains(result)); + ASSERT_TRUE(infer(input1, super2).contains(result)); + ASSERT_TRUE(infer(super1, super2).contains(result)); +} + +// Verify the correctness and monotonicity of an inference function by exhautively analyzing all +// instances of InputType +template +static void test_binary_exhaustive(Operation op, Inference infer) { + for (const InputType& input1 : all_instances()) { + for (const InputType& input2 : all_instances()) { + test_binary_instance_correctness_exhaustive(op, infer, input1, input2); + if (all_instances().size() < 100) { + // This effectively covers the cases up to uintn_t<2> + test_binary_instance_monotonicity_exhaustive(infer, input1, input2); + } else { + // This effectively covers the cases of uintn_t<3> + test_binary_instance_monotonicity_samples(infer, input1, input2); + } + } + } +} + +// Verify the correctness and monotonicity of an inference function by randomly sampling instances +// of InputType +template +static void test_binary_random(Operation op, Inference infer) { + using S = std::remove_const_t; + using U = std::remove_const_t; + + constexpr size_t sample_count = 100; + InputType samples[sample_count]; + + // Fill with {0} + for (size_t i = 0; i < sample_count; i++) { + samples[i] = InputType::make(TypeIntPrototype{{S(0), S(0)}, {U(0), U(0)}, {U(0), U(0)}}, 0); + } + + // {1} + samples[1] = InputType::make(TypeIntPrototype{{S(1), S(1)}, {U(1), U(1)}, {U(0), U(0)}}, 0); + // {-1} + samples[2] = InputType::make(TypeIntPrototype{{S(-1), S(-1)}, {U(-1), U(-1)}, {U(0), U(0)}}, 0); + // {0, 1} + samples[3] = InputType::make(TypeIntPrototype{{S(0), S(1)}, {U(0), U(1)}, {U(0), U(0)}}, 0); + // {-1, 0, 1} + samples[4] = InputType::make(TypeIntPrototype{{S(-1), S(1)}, {U(0), U(-1)}, {U(0), U(0)}}, 0); + // {-1, 1} + samples[5] = InputType::make(TypeIntPrototype{{S(-1), S(1)}, {U(1), U(-1)}, {U(0), U(0)}}, 0); + // {0, 1, 2} + samples[6] = InputType::make(TypeIntPrototype{{S(0), S(2)}, {U(0), U(2)}, {U(0), U(0)}}, 0); + // {0, 2} + samples[7] = InputType::make(TypeIntPrototype{{S(0), S(2)}, {U(0), U(2)}, {U(1), U(0)}}, 0); + // [min_signed, max_signed] + samples[8] = InputType::make(TypeIntPrototype{{std::numeric_limits::min(), std::numeric_limits::max()}, {U(0), U(-1)}, {U(0), U(0)}}, 0); + // [0, max_signed] + samples[9] = InputType::make(TypeIntPrototype{{S(0), std::numeric_limits::max()}, {U(0), U(-1)}, {U(0), U(0)}}, 0); + // [min_signed, 0) + samples[10] = InputType::make(TypeIntPrototype{{std::numeric_limits::min(), S(-1)}, {U(0), U(-1)}, {U(0), U(0)}}, 0); + + constexpr size_t max_tries = 1000; + constexpr size_t start_random_idx = 11; + for (size_t tries = 0, idx = start_random_idx; tries < max_tries && idx < sample_count; tries++) { + // Try to have lo < hi + S signed_bound1 = S(uniform_random()); + S signed_bound2 = S(uniform_random()); + S lo = MIN2(signed_bound1, signed_bound2); + S hi = MAX2(signed_bound1, signed_bound2); + + // Try to have ulo < uhi + U unsigned_bound1 = uniform_random(); + U unsigned_bound2 = uniform_random(); + U ulo = MIN2(unsigned_bound1, unsigned_bound2); + U uhi = MAX2(unsigned_bound1, unsigned_bound2); + + // Try to have (zeros & ones) == 0 + U zeros = uniform_random(); + U ones = uniform_random(); + U common = zeros & ones; + zeros = zeros ^ common; + ones = ones ^ common; + + TypeIntPrototype t{{lo, hi}, {ulo, uhi}, {zeros, ones}}; + auto canonicalized_t = t.canonicalize_constraints(); + if (canonicalized_t.empty()) { + continue; + } + + samples[idx] = TypeIntMirror{canonicalized_t._data._srange._lo, canonicalized_t._data._srange._hi, + canonicalized_t._data._urange._lo, canonicalized_t._data._urange._hi, + canonicalized_t._data._bits}; + idx++; + } + + for (size_t i = 0; i < sample_count; i++) { + for (size_t j = 0; j < sample_count; j++) { + test_binary_instance_correctness_samples(op, infer, samples[i], samples[j]); + test_binary_instance_monotonicity_samples(infer, samples[i], samples[j]); + } + } +} + +template